Browse Source

Merge pull request #44025 from reduz/refactor-mesh

Refactored Mesh internals and formats.
Rémi Verschelde 4 years ago
parent
commit
b36ff888a0

+ 1 - 0
core/io/resource_importer.h

@@ -102,6 +102,7 @@ public:
 	virtual String get_resource_type() const = 0;
 	virtual float get_priority() const { return 1.0; }
 	virtual int get_import_order() const { return 0; }
+	virtual int get_format_version() const { return 0; }
 
 	struct ImportOption {
 		PropertyInfo option;

+ 2 - 1
drivers/vulkan/rendering_device_vulkan.cpp

@@ -615,6 +615,7 @@ int RenderingDeviceVulkan::get_format_vertex_size(DataFormat p_format) {
 		case DATA_FORMAT_B8G8R8A8_SNORM:
 		case DATA_FORMAT_B8G8R8A8_UINT:
 		case DATA_FORMAT_B8G8R8A8_SINT:
+		case DATA_FORMAT_A2B10G10R10_UNORM_PACK32:
 			return 4;
 		case DATA_FORMAT_R16_UNORM:
 		case DATA_FORMAT_R16_SNORM:
@@ -3528,7 +3529,7 @@ RenderingDevice::VertexFormatID RenderingDeviceVulkan::vertex_format_create(cons
 		ERR_FAIL_COND_V(used_locations.has(p_vertex_formats[i].location), INVALID_ID);
 
 		ERR_FAIL_COND_V_MSG(get_format_vertex_size(p_vertex_formats[i].format) == 0, INVALID_ID,
-				"Data format for attachment (" + itos(i) + ") is not valid for a vertex array.");
+				"Data format for attachment (" + itos(i) + "), '" + named_formats[p_vertex_formats[i].format] + "', is not valid for a vertex array.");
 
 		vdcache.bindings[i].binding = i;
 		vdcache.bindings[i].stride = p_vertex_formats[i].stride;

+ 16 - 0
editor/editor_file_system.cpp

@@ -357,10 +357,12 @@ bool EditorFileSystem::_test_for_reimport(const String &p_path, bool p_only_impo
 
 	List<String> to_check;
 
+	String importer_name;
 	String source_file = "";
 	String source_md5 = "";
 	Vector<String> dest_files;
 	String dest_md5 = "";
+	int version = 0;
 
 	while (true) {
 		assign = Variant();
@@ -384,6 +386,10 @@ bool EditorFileSystem::_test_for_reimport(const String &p_path, bool p_only_impo
 				for (int i = 0; i < fa.size(); i++) {
 					to_check.push_back(fa[i]);
 				}
+			} else if (assign == "importer_version") {
+				version = value;
+			} else if (assign == "importer") {
+				importer_name = value;
 			} else if (!p_only_imported_files) {
 				if (assign == "source_file") {
 					source_file = value;
@@ -399,6 +405,12 @@ bool EditorFileSystem::_test_for_reimport(const String &p_path, bool p_only_impo
 
 	memdelete(f);
 
+	Ref<ResourceImporter> importer = ResourceFormatImporter::get_singleton()->get_importer_by_name(importer_name);
+
+	if (importer->get_format_version() > version) {
+		return true; // version changed, reimport
+	}
+
 	// Read the md5's from a separate file (so the import parameters aren't dependent on the file version
 	String base_path = ResourceFormatImporter::get_singleton()->get_import_base_path(p_path);
 	FileAccess *md5s = FileAccess::open(base_path + ".md5", FileAccess::READ, &err);
@@ -1576,6 +1588,10 @@ Error EditorFileSystem::_reimport_group(const String &p_group_file, const Vector
 		f->store_line("[remap]");
 		f->store_line("");
 		f->store_line("importer=\"" + importer->get_importer_name() + "\"");
+		int version = importer->get_format_version();
+		if (version > 0) {
+			f->store_line("importer_version=" + itos(importer->get_format_version()));
+		}
 		if (importer->get_resource_type() != "") {
 			f->store_line("type=\"" + importer->get_resource_type() + "\"");
 		}

+ 8 - 8
editor/import/editor_import_collada.cpp

@@ -844,19 +844,19 @@ Error ColladaImport::_create_mesh_surfaces(bool p_optimize, Ref<ArrayMesh> &p_me
 
 			for (int k = 0; k < vertex_array.size(); k++) {
 				if (normal_src) {
-					surftool->add_normal(vertex_array[k].normal);
+					surftool->set_normal(vertex_array[k].normal);
 					if (binormal_src && tangent_src) {
-						surftool->add_tangent(vertex_array[k].tangent);
+						surftool->set_tangent(vertex_array[k].tangent);
 					}
 				}
 				if (uv_src) {
-					surftool->add_uv(Vector2(vertex_array[k].uv.x, vertex_array[k].uv.y));
+					surftool->set_uv(Vector2(vertex_array[k].uv.x, vertex_array[k].uv.y));
 				}
 				if (uv2_src) {
-					surftool->add_uv2(Vector2(vertex_array[k].uv2.x, vertex_array[k].uv2.y));
+					surftool->set_uv2(Vector2(vertex_array[k].uv2.x, vertex_array[k].uv2.y));
 				}
 				if (color_src) {
-					surftool->add_color(vertex_array[k].color);
+					surftool->set_color(vertex_array[k].color);
 				}
 
 				if (has_weights) {
@@ -876,8 +876,8 @@ Error ColladaImport::_create_mesh_surfaces(bool p_optimize, Ref<ArrayMesh> &p_me
 						}
 					}
 
-					surftool->add_bones(bones);
-					surftool->add_weights(weights);
+					surftool->set_bones(bones);
+					surftool->set_weights(weights);
 				}
 
 				surftool->add_vertex(vertex_array[k].vertex);
@@ -923,7 +923,7 @@ Error ColladaImport::_create_mesh_surfaces(bool p_optimize, Ref<ArrayMesh> &p_me
 				mr.push_back(a);
 			}
 
-			p_mesh->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES, d, mr, Dictionary(), p_use_compression ? Mesh::ARRAY_COMPRESS_DEFAULT : 0);
+			p_mesh->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES, d, mr, Dictionary(), 0);
 
 			if (material.is_valid()) {
 				if (p_use_mesh_material) {

+ 1 - 2
editor/import/editor_scene_importer_gltf.cpp

@@ -970,8 +970,7 @@ Error EditorSceneImporterGLTF::_parse_meshes(GLTFState &state) {
 		return OK;
 	}
 
-	bool compress_vert_data = state.import_flags & IMPORT_USE_COMPRESSION;
-	uint32_t mesh_flags = compress_vert_data ? Mesh::ARRAY_COMPRESS_DEFAULT : 0;
+	uint32_t mesh_flags = 0;
 
 	Array meshes = state.json["meshes"];
 	for (GLTFMeshIndex i = 0; i < meshes.size(); i++) {

+ 7 - 3
editor/import/resource_importer_obj.cpp

@@ -210,7 +210,7 @@ static Error _parse_obj(const String &p_path, List<Ref<Mesh>> &r_meshes, bool p_
 	bool generate_tangents = p_generate_tangents;
 	Vector3 scale_mesh = p_scale_mesh;
 	Vector3 offset_mesh = p_offset_mesh;
-	int mesh_flags = p_optimize ? Mesh::ARRAY_COMPRESS_DEFAULT : 0;
+	int mesh_flags = 0;
 
 	Vector<Vector3> vertices;
 	Vector<Vector3> normals;
@@ -294,7 +294,7 @@ static Error _parse_obj(const String &p_path, List<Ref<Mesh>> &r_meshes, bool p_
 							norm += normals.size() + 1;
 						}
 						ERR_FAIL_INDEX_V(norm, normals.size(), ERR_FILE_CORRUPT);
-						surf_tool->add_normal(normals[norm]);
+						surf_tool->set_normal(normals[norm]);
 					}
 
 					if (face[idx].size() >= 2 && face[idx][1] != String()) {
@@ -303,7 +303,7 @@ static Error _parse_obj(const String &p_path, List<Ref<Mesh>> &r_meshes, bool p_
 							uv += uvs.size() + 1;
 						}
 						ERR_FAIL_INDEX_V(uv, uvs.size(), ERR_FILE_CORRUPT);
-						surf_tool->add_uv(uvs[uv]);
+						surf_tool->set_uv(uvs[uv]);
 					}
 
 					int vtx = face[idx][0].to_int() - 1;
@@ -473,6 +473,10 @@ String ResourceImporterOBJ::get_resource_type() const {
 	return "Mesh";
 }
 
+int ResourceImporterOBJ::get_format_version() const {
+	return 1;
+}
+
 int ResourceImporterOBJ::get_preset_count() const {
 	return 0;
 }

+ 1 - 0
editor/import/resource_importer_obj.h

@@ -54,6 +54,7 @@ public:
 	virtual void get_recognized_extensions(List<String> *p_extensions) const override;
 	virtual String get_save_extension() const override;
 	virtual String get_resource_type() const override;
+	virtual int get_format_version() const override;
 
 	virtual int get_preset_count() const override;
 	virtual String get_preset_name(int p_idx) const override;

+ 4 - 0
editor/import/resource_importer_scene.cpp

@@ -172,6 +172,10 @@ String ResourceImporterScene::get_resource_type() const {
 	return "PackedScene";
 }
 
+int ResourceImporterScene::get_format_version() const {
+	return 1;
+}
+
 bool ResourceImporterScene::get_option_visibility(const String &p_option, const Map<StringName, Variant> &p_options) const {
 	if (p_option.begins_with("animation/")) {
 		if (p_option != "animation/import" && !bool(p_options["animation/import"])) {

+ 1 - 0
editor/import/resource_importer_scene.h

@@ -133,6 +133,7 @@ public:
 	virtual void get_recognized_extensions(List<String> *p_extensions) const override;
 	virtual String get_save_extension() const override;
 	virtual String get_resource_type() const override;
+	virtual int get_format_version() const override;
 
 	virtual int get_preset_count() const override;
 	virtual String get_preset_name(int p_idx) const override;

+ 24 - 24
editor/node_3d_editor_gizmos.cpp

@@ -1625,13 +1625,13 @@ void Skeleton3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
 			int pointidx = 0;
 			for (int j = 0; j < 3; j++) {
 				bones.write[0] = parent;
-				surface_tool->add_bones(bones);
-				surface_tool->add_weights(weights);
-				surface_tool->add_color(rootcolor);
+				surface_tool->set_bones(bones);
+				surface_tool->set_weights(weights);
+				surface_tool->set_color(rootcolor);
 				surface_tool->add_vertex(v0 - grests[parent].basis[j].normalized() * dist * 0.05);
-				surface_tool->add_bones(bones);
-				surface_tool->add_weights(weights);
-				surface_tool->add_color(rootcolor);
+				surface_tool->set_bones(bones);
+				surface_tool->set_weights(weights);
+				surface_tool->set_color(rootcolor);
 				surface_tool->add_vertex(v0 + grests[parent].basis[j].normalized() * dist * 0.05);
 
 				if (j == closest) {
@@ -1654,24 +1654,24 @@ void Skeleton3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
 					point += axis * dist * 0.1;
 
 					bones.write[0] = parent;
-					surface_tool->add_bones(bones);
-					surface_tool->add_weights(weights);
-					surface_tool->add_color(bonecolor);
+					surface_tool->set_bones(bones);
+					surface_tool->set_weights(weights);
+					surface_tool->set_color(bonecolor);
 					surface_tool->add_vertex(v0);
-					surface_tool->add_bones(bones);
-					surface_tool->add_weights(weights);
-					surface_tool->add_color(bonecolor);
+					surface_tool->set_bones(bones);
+					surface_tool->set_weights(weights);
+					surface_tool->set_color(bonecolor);
 					surface_tool->add_vertex(point);
 
 					bones.write[0] = parent;
-					surface_tool->add_bones(bones);
-					surface_tool->add_weights(weights);
-					surface_tool->add_color(bonecolor);
+					surface_tool->set_bones(bones);
+					surface_tool->set_weights(weights);
+					surface_tool->set_color(bonecolor);
 					surface_tool->add_vertex(point);
 					bones.write[0] = i;
-					surface_tool->add_bones(bones);
-					surface_tool->add_weights(weights);
-					surface_tool->add_color(bonecolor);
+					surface_tool->set_bones(bones);
+					surface_tool->set_weights(weights);
+					surface_tool->set_color(bonecolor);
 					surface_tool->add_vertex(v1);
 					points[pointidx++] = point;
 				}
@@ -1680,13 +1680,13 @@ void Skeleton3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
 			SWAP(points[1], points[2]);
 			for (int j = 0; j < 4; j++) {
 				bones.write[0] = parent;
-				surface_tool->add_bones(bones);
-				surface_tool->add_weights(weights);
-				surface_tool->add_color(bonecolor);
+				surface_tool->set_bones(bones);
+				surface_tool->set_weights(weights);
+				surface_tool->set_color(bonecolor);
 				surface_tool->add_vertex(points[j]);
-				surface_tool->add_bones(bones);
-				surface_tool->add_weights(weights);
-				surface_tool->add_color(bonecolor);
+				surface_tool->set_bones(bones);
+				surface_tool->set_weights(weights);
+				surface_tool->set_color(bonecolor);
 				surface_tool->add_vertex(points[(j + 1) % 4]);
 			}
 

+ 1 - 1
editor/plugins/node_3d_editor_plugin.cpp

@@ -5345,7 +5345,7 @@ void Node3DEditor::_init_indicators() {
 						Vector2 ofs = Vector2(Math::cos((Math_PI * 2.0 * k) / m), Math::sin((Math_PI * 2.0 * k) / m));
 						Vector3 normal = ivec * ofs.x + ivec2 * ofs.y;
 
-						surftool->add_normal(basis.xform(normal));
+						surftool->set_normal(basis.xform(normal));
 						surftool->add_vertex(vertex);
 					}
 				}

+ 2 - 2
modules/arkit/arkit_interface.mm

@@ -712,8 +712,8 @@ void ARKitInterface::_add_or_update_anchor(GodotARAnchor *p_anchor) {
 						int16_t index = planeAnchor.geometry.triangleIndices[j];
 						simd_float3 vrtx = planeAnchor.geometry.vertices[index];
 						simd_float2 textcoord = planeAnchor.geometry.textureCoordinates[index];
-						surftool->add_uv(Vector2(textcoord[0], textcoord[1]));
-						surftool->add_color(Color(0.8, 0.8, 0.8));
+						surftool->set_uv(Vector2(textcoord[0], textcoord[1]));
+						surftool->set_color(Color(0.8, 0.8, 0.8));
 						surftool->add_vertex(Vector3(vrtx[0], vrtx[1], vrtx[2]));
 					}
 

+ 8 - 9
modules/assimp/editor_scene_importer_assimp.cpp

@@ -827,8 +827,7 @@ EditorSceneImporterAssimp::_generate_mesh_from_surface_indices(ImportState &stat
 	Ref<ArrayMesh> mesh;
 	mesh.instance();
 	bool has_uvs = false;
-	bool compress_vert_data = state.import_flags & IMPORT_USE_COMPRESSION;
-	uint32_t mesh_flags = compress_vert_data ? Mesh::ARRAY_COMPRESS_DEFAULT : 0;
+	uint32_t mesh_flags = 0;
 
 	Map<String, uint32_t> morph_mesh_string_lookup;
 
@@ -904,33 +903,33 @@ EditorSceneImporterAssimp::_generate_mesh_from_surface_indices(ImportState &stat
 			// Get the texture coordinates if they exist
 			if (ai_mesh->HasTextureCoords(0)) {
 				has_uvs = true;
-				st->add_uv(Vector2(ai_mesh->mTextureCoords[0][j].x, 1.0f - ai_mesh->mTextureCoords[0][j].y));
+				st->set_uv(Vector2(ai_mesh->mTextureCoords[0][j].x, 1.0f - ai_mesh->mTextureCoords[0][j].y));
 			}
 
 			if (ai_mesh->HasTextureCoords(1)) {
 				has_uvs = true;
-				st->add_uv2(Vector2(ai_mesh->mTextureCoords[1][j].x, 1.0f - ai_mesh->mTextureCoords[1][j].y));
+				st->set_uv2(Vector2(ai_mesh->mTextureCoords[1][j].x, 1.0f - ai_mesh->mTextureCoords[1][j].y));
 			}
 
 			// Assign vertex colors
 			if (ai_mesh->HasVertexColors(0)) {
 				Color color = Color(ai_mesh->mColors[0]->r, ai_mesh->mColors[0]->g, ai_mesh->mColors[0]->b,
 						ai_mesh->mColors[0]->a);
-				st->add_color(color);
+				st->set_color(color);
 			}
 
 			// Work out normal calculations? - this needs work it doesn't work properly on huestos
 			if (ai_mesh->mNormals != nullptr) {
 				const aiVector3D normals = ai_mesh->mNormals[j];
 				const Vector3 godot_normal = Vector3(normals.x, normals.y, normals.z);
-				st->add_normal(godot_normal);
+				st->set_normal(godot_normal);
 				if (ai_mesh->HasTangentsAndBitangents()) {
 					const aiVector3D tangents = ai_mesh->mTangents[j];
 					const Vector3 godot_tangent = Vector3(tangents.x, tangents.y, tangents.z);
 					const aiVector3D bitangent = ai_mesh->mBitangents[j];
 					const Vector3 godot_bitangent = Vector3(bitangent.x, bitangent.y, bitangent.z);
 					float d = godot_normal.cross(godot_tangent).dot(godot_bitangent) > 0.0f ? 1.0f : -1.0f;
-					st->add_tangent(Plane(tangents.x, tangents.y, tangents.z, d));
+					st->set_tangent(Plane(tangents.x, tangents.y, tangents.z, d));
 				}
 			}
 
@@ -948,8 +947,8 @@ EditorSceneImporterAssimp::_generate_mesh_from_surface_indices(ImportState &stat
 					weights.write[k] = bone_info[k].weight;
 				}
 
-				st->add_bones(bones);
-				st->add_weights(weights);
+				st->set_bones(bones);
+				st->set_weights(weights);
 			}
 
 			// Assign vertex

+ 0 - 1
scene/3d/soft_body_3d.cpp

@@ -480,7 +480,6 @@ void SoftBody3D::become_mesh_owner() {
 		Dictionary surface_lods = mesh->surface_get_lods(0);
 		uint32_t surface_format = mesh->surface_get_format(0);
 
-		surface_format &= ~(Mesh::ARRAY_COMPRESS_NORMAL);
 		surface_format |= Mesh::ARRAY_FLAG_USE_DYNAMIC_UPDATE;
 
 		Ref<ArrayMesh> soft_mesh;

+ 155 - 47
scene/resources/mesh.cpp

@@ -157,7 +157,7 @@ void Mesh::generate_debug_mesh_indices(Vector<Vector3> &r_points) {
 
 bool Mesh::surface_is_softbody_friendly(int p_idx) const {
 	const uint32_t surface_format = surface_get_format(p_idx);
-	return (surface_format & Mesh::ARRAY_FLAG_USE_DYNAMIC_UPDATE && (!(surface_format & Mesh::ARRAY_COMPRESS_NORMAL)));
+	return (surface_format & Mesh::ARRAY_FLAG_USE_DYNAMIC_UPDATE);
 }
 
 Vector<Face3> Mesh::get_faces() const {
@@ -483,37 +483,59 @@ void Mesh::_bind_methods() {
 	BIND_ENUM_CONSTANT(BLEND_SHAPE_MODE_NORMALIZED);
 	BIND_ENUM_CONSTANT(BLEND_SHAPE_MODE_RELATIVE);
 
+	BIND_ENUM_CONSTANT(ARRAY_VERTEX);
+	BIND_ENUM_CONSTANT(ARRAY_NORMAL);
+	BIND_ENUM_CONSTANT(ARRAY_TANGENT);
+	BIND_ENUM_CONSTANT(ARRAY_COLOR);
+	BIND_ENUM_CONSTANT(ARRAY_TEX_UV);
+	BIND_ENUM_CONSTANT(ARRAY_TEX_UV2);
+	BIND_ENUM_CONSTANT(ARRAY_CUSTOM0);
+	BIND_ENUM_CONSTANT(ARRAY_CUSTOM1);
+	BIND_ENUM_CONSTANT(ARRAY_CUSTOM2);
+	BIND_ENUM_CONSTANT(ARRAY_CUSTOM3);
+	BIND_ENUM_CONSTANT(ARRAY_BONES);
+	BIND_ENUM_CONSTANT(ARRAY_WEIGHTS);
+	BIND_ENUM_CONSTANT(ARRAY_INDEX);
+	BIND_ENUM_CONSTANT(ARRAY_MAX);
+
+	BIND_ENUM_CONSTANT(ARRAY_CUSTOM_RGBA8_UNORM);
+	BIND_ENUM_CONSTANT(ARRAY_CUSTOM_RGBA8_SNORM);
+	BIND_ENUM_CONSTANT(ARRAY_CUSTOM_RG_HALF);
+	BIND_ENUM_CONSTANT(ARRAY_CUSTOM_RGBA_HALF);
+	BIND_ENUM_CONSTANT(ARRAY_CUSTOM_R_FLOAT);
+	BIND_ENUM_CONSTANT(ARRAY_CUSTOM_RG_FLOAT);
+	BIND_ENUM_CONSTANT(ARRAY_CUSTOM_RGB_FLOAT);
+	BIND_ENUM_CONSTANT(ARRAY_CUSTOM_RGBA_FLOAT);
+	BIND_ENUM_CONSTANT(ARRAY_CUSTOM_MAX);
+
 	BIND_ENUM_CONSTANT(ARRAY_FORMAT_VERTEX);
 	BIND_ENUM_CONSTANT(ARRAY_FORMAT_NORMAL);
 	BIND_ENUM_CONSTANT(ARRAY_FORMAT_TANGENT);
 	BIND_ENUM_CONSTANT(ARRAY_FORMAT_COLOR);
 	BIND_ENUM_CONSTANT(ARRAY_FORMAT_TEX_UV);
 	BIND_ENUM_CONSTANT(ARRAY_FORMAT_TEX_UV2);
+	BIND_ENUM_CONSTANT(ARRAY_FORMAT_CUSTOM0);
+	BIND_ENUM_CONSTANT(ARRAY_FORMAT_CUSTOM1);
+	BIND_ENUM_CONSTANT(ARRAY_FORMAT_CUSTOM2);
+	BIND_ENUM_CONSTANT(ARRAY_FORMAT_CUSTOM3);
 	BIND_ENUM_CONSTANT(ARRAY_FORMAT_BONES);
 	BIND_ENUM_CONSTANT(ARRAY_FORMAT_WEIGHTS);
 	BIND_ENUM_CONSTANT(ARRAY_FORMAT_INDEX);
 
-	BIND_ENUM_CONSTANT(ARRAY_COMPRESS_NORMAL);
-	BIND_ENUM_CONSTANT(ARRAY_COMPRESS_TANGENT);
-	BIND_ENUM_CONSTANT(ARRAY_COMPRESS_COLOR);
-	BIND_ENUM_CONSTANT(ARRAY_COMPRESS_TEX_UV);
-	BIND_ENUM_CONSTANT(ARRAY_COMPRESS_TEX_UV2);
-	BIND_ENUM_CONSTANT(ARRAY_COMPRESS_INDEX);
+	BIND_ENUM_CONSTANT(ARRAY_FORMAT_BLEND_SHAPE_MASK);
 
-	BIND_ENUM_CONSTANT(ARRAY_FLAG_USE_2D_VERTICES);
+	BIND_ENUM_CONSTANT(ARRAY_FORMAT_CUSTOM_BASE);
+	BIND_ENUM_CONSTANT(ARRAY_FORMAT_CUSTOM0_SHIFT);
+	BIND_ENUM_CONSTANT(ARRAY_FORMAT_CUSTOM1_SHIFT);
+	BIND_ENUM_CONSTANT(ARRAY_FORMAT_CUSTOM2_SHIFT);
+	BIND_ENUM_CONSTANT(ARRAY_FORMAT_CUSTOM3_SHIFT);
 
-	BIND_ENUM_CONSTANT(ARRAY_COMPRESS_DEFAULT);
+	BIND_ENUM_CONSTANT(ARRAY_FORMAT_CUSTOM_MASK);
+	BIND_ENUM_CONSTANT(ARRAY_COMPRESS_FLAGS_BASE);
 
-	BIND_ENUM_CONSTANT(ARRAY_VERTEX);
-	BIND_ENUM_CONSTANT(ARRAY_NORMAL);
-	BIND_ENUM_CONSTANT(ARRAY_TANGENT);
-	BIND_ENUM_CONSTANT(ARRAY_COLOR);
-	BIND_ENUM_CONSTANT(ARRAY_TEX_UV);
-	BIND_ENUM_CONSTANT(ARRAY_TEX_UV2);
-	BIND_ENUM_CONSTANT(ARRAY_BONES);
-	BIND_ENUM_CONSTANT(ARRAY_WEIGHTS);
-	BIND_ENUM_CONSTANT(ARRAY_INDEX);
-	BIND_ENUM_CONSTANT(ARRAY_MAX);
+	BIND_ENUM_CONSTANT(ARRAY_FLAG_USE_2D_VERTICES);
+	BIND_ENUM_CONSTANT(ARRAY_FLAG_USE_DYNAMIC_UPDATE);
+	BIND_ENUM_CONSTANT(ARRAY_FLAG_USE_8_BONE_WEIGHTS);
 }
 
 void Mesh::clear_cache() const {
@@ -559,12 +581,50 @@ Vector<Ref<Shape3D>> Mesh::convex_decompose() const {
 
 Mesh::Mesh() {
 }
-
+#if 0
 static Vector<uint8_t> _fix_array_compatibility(const Vector<uint8_t> &p_src, uint32_t p_format, uint32_t p_elements) {
-	bool vertex_16bit = p_format & ((1 << (Mesh::ARRAY_VERTEX + Mesh::ARRAY_COMPRESS_BASE)));
-	bool has_bones = (p_format & Mesh::ARRAY_FORMAT_BONES);
-	bool bone_8 = has_bones && !(p_format & (Mesh::ARRAY_COMPRESS_INDEX << 2));
-	bool weight_32 = has_bones && !(p_format & (Mesh::ARRAY_COMPRESS_TEX_UV2 << 2));
+	enum ArrayType {
+		OLD_ARRAY_VERTEX = 0,
+		OLD_ARRAY_NORMAL = 1,
+		OLD_ARRAY_TANGENT = 2,
+		OLD_ARRAY_COLOR = 3,
+		OLD_ARRAY_TEX_UV = 4,
+		OLD_ARRAY_TEX_UV2 = 5,
+		OLD_ARRAY_BONES = 6,
+		OLD_ARRAY_WEIGHTS = 7,
+		OLD_ARRAY_INDEX = 8,
+		OLD_ARRAY_MAX = 9
+	};
+
+	enum ArrayFormat {
+		/* OLD_ARRAY FORMAT FLAGS */
+		OLD_ARRAY_FORMAT_VERTEX = 1 << OLD_ARRAY_VERTEX, // mandatory
+		OLD_ARRAY_FORMAT_NORMAL = 1 << OLD_ARRAY_NORMAL,
+		OLD_ARRAY_FORMAT_TANGENT = 1 << OLD_ARRAY_TANGENT,
+		OLD_ARRAY_FORMAT_COLOR = 1 << OLD_ARRAY_COLOR,
+		OLD_ARRAY_FORMAT_TEX_UV = 1 << OLD_ARRAY_TEX_UV,
+		OLD_ARRAY_FORMAT_TEX_UV2 = 1 << OLD_ARRAY_TEX_UV2,
+		OLD_ARRAY_FORMAT_BONES = 1 << OLD_ARRAY_BONES,
+		OLD_ARRAY_FORMAT_WEIGHTS = 1 << OLD_ARRAY_WEIGHTS,
+		OLD_ARRAY_FORMAT_INDEX = 1 << OLD_ARRAY_INDEX,
+
+		OLD_ARRAY_COMPRESS_BASE = (OLD_ARRAY_INDEX + 1),
+		OLD_ARRAY_COMPRESS_NORMAL = 1 << (OLD_ARRAY_NORMAL + OLD_ARRAY_COMPRESS_BASE),
+		OLD_ARRAY_COMPRESS_TANGENT = 1 << (OLD_ARRAY_TANGENT + OLD_ARRAY_COMPRESS_BASE),
+		OLD_ARRAY_COMPRESS_COLOR = 1 << (OLD_ARRAY_COLOR + OLD_ARRAY_COMPRESS_BASE),
+		OLD_ARRAY_COMPRESS_TEX_UV = 1 << (OLD_ARRAY_TEX_UV + OLD_ARRAY_COMPRESS_BASE),
+		OLD_ARRAY_COMPRESS_TEX_UV2 = 1 << (OLD_ARRAY_TEX_UV2 + OLD_ARRAY_COMPRESS_BASE),
+		OLD_ARRAY_COMPRESS_INDEX = 1 << (OLD_ARRAY_INDEX + OLD_ARRAY_COMPRESS_BASE),
+		OLD_ARRAY_COMPRESS_DEFAULT = OLD_ARRAY_COMPRESS_NORMAL | OLD_ARRAY_COMPRESS_TANGENT | OLD_ARRAY_COMPRESS_COLOR | OLD_ARRAY_COMPRESS_TEX_UV | OLD_ARRAY_COMPRESS_TEX_UV2,
+
+		OLD_ARRAY_FLAG_USE_2D_VERTICES = OLD_ARRAY_COMPRESS_INDEX << 1,
+		OLD_ARRAY_FLAG_USE_DYNAMIC_UPDATE = OLD_ARRAY_COMPRESS_INDEX << 3,
+	};
+
+	bool vertex_16bit = p_format & ((1 << (OLD_ARRAY_VERTEX + OLD_ARRAY_COMPRESS_BASE)));
+	bool has_bones = (p_format & OLD_ARRAY_FORMAT_BONES);
+	bool bone_8 = has_bones && !(p_format & (OLD_ARRAY_COMPRESS_INDEX << 2));
+	bool weight_32 = has_bones && !(p_format & (OLD_ARRAY_COMPRESS_TEX_UV2 << 2));
 
 	print_line("convert vertex16: " + itos(vertex_16bit) + " convert bone 8 " + itos(bone_8) + " convert weight 32 " + itos(weight_32));
 
@@ -572,7 +632,7 @@ static Vector<uint8_t> _fix_array_compatibility(const Vector<uint8_t> &p_src, ui
 		return p_src;
 	}
 
-	bool vertex_2d = (p_format & (Mesh::ARRAY_COMPRESS_INDEX << 1));
+	bool vertex_2d = (p_format & (OLD_ARRAY_COMPRESS_INDEX << 1));
 
 	uint32_t src_stride = p_src.size() / p_elements;
 	uint32_t dst_stride = src_stride + (vertex_16bit ? 4 : 0) + (bone_8 ? 4 : 0) - (weight_32 ? 8 : 0);
@@ -671,7 +731,7 @@ static Vector<uint8_t> _fix_array_compatibility(const Vector<uint8_t> &p_src, ui
 
 	return ret;
 }
-
+#endif
 bool ArrayMesh::_set(const StringName &p_name, const Variant &p_value) {
 	String sname = p_name;
 
@@ -727,6 +787,7 @@ bool ArrayMesh::_set(const StringName &p_name, const Variant &p_value) {
 			add_surface_from_arrays(PrimitiveType(int(d["primitive"])), d["arrays"], d["morph_arrays"]);
 
 		} else if (d.has("array_data")) {
+#if 0
 			//print_line("array data (old style");
 			//older format (3.x)
 			Vector<uint8_t> array_data = d["array_data"];
@@ -793,6 +854,7 @@ bool ArrayMesh::_set(const StringName &p_name, const Variant &p_value) {
 			}
 
 			add_surface(format, PrimitiveType(primitive), array_data, vertex_count, array_index_data, index_count, aabb, blend_shapes, bone_aabb);
+#endif
 		} else {
 			ERR_FAIL_V(false);
 		}
@@ -824,6 +886,12 @@ Array ArrayMesh::_get_surfaces() const {
 		data["primitive"] = surface.primitive;
 		data["vertex_data"] = surface.vertex_data;
 		data["vertex_count"] = surface.vertex_count;
+		if (surface.skin_data.size()) {
+			data["skin_data"] = surface.skin_data;
+		}
+		if (surface.attribute_data.size()) {
+			data["attribute_data"] = surface.attribute_data;
+		}
 		data["aabb"] = surface.aabb;
 		if (surface.index_count) {
 			data["index_data"] = surface.index_data;
@@ -848,9 +916,9 @@ Array ArrayMesh::_get_surfaces() const {
 			data["bone_aabbs"] = bone_aabbs;
 		}
 
-		Array blend_shapes;
-		for (int j = 0; j < surface.blend_shapes.size(); j++) {
-			blend_shapes.push_back(surface.blend_shapes[j]);
+		if (surface.blend_shape_data.size()) {
+			data["blend_shapes"] = surface.blend_shape_data;
+			data["blend_shapes_count"] = surface.blend_shape_count;
 		}
 
 		if (surfaces[i].material.is_valid()) {
@@ -896,6 +964,12 @@ void ArrayMesh::_set_surfaces(const Array &p_surfaces) {
 		surface.primitive = RS::PrimitiveType(int(d["primitive"]));
 		surface.vertex_data = d["vertex_data"];
 		surface.vertex_count = d["vertex_count"];
+		if (d.has("attribute_data")) {
+			surface.attribute_data = d["attribute_data"];
+		}
+		if (d.has("skin_data")) {
+			surface.skin_data = d["skin_data"];
+		}
 		surface.aabb = d["aabb"];
 
 		if (d.has("index_data")) {
@@ -922,11 +996,9 @@ void ArrayMesh::_set_surfaces(const Array &p_surfaces) {
 			}
 		}
 
-		if (d.has("blend_shapes")) {
-			Array blend_shapes;
-			for (int j = 0; j < blend_shapes.size(); j++) {
-				surface.blend_shapes.push_back(blend_shapes[j]);
-			}
+		if (d.has("blend_shapes") && d.has("blend_shape_count")) {
+			surface.blend_shape_data = d["blend_shapes"];
+			surface.blend_shape_count = d["blend_shape_count"];
 		}
 
 		Ref<Material> material;
@@ -982,7 +1054,7 @@ void ArrayMesh::_set_surfaces(const Array &p_surfaces) {
 		s.aabb = surface_data[i].aabb;
 		if (i == 0) {
 			aabb = s.aabb;
-			blend_shapes.resize(surface_data[i].blend_shapes.size());
+			blend_shapes.resize(surface_data[i].blend_shape_count);
 		} else {
 			aabb.merge_with(s.aabb);
 		}
@@ -1070,7 +1142,7 @@ void ArrayMesh::_recompute_aabb() {
 #ifndef _MSC_VER
 #warning need to add binding to add_surface using future MeshSurfaceData object
 #endif
-void ArrayMesh::add_surface(uint32_t p_format, PrimitiveType p_primitive, const Vector<uint8_t> &p_array, int p_vertex_count, const Vector<uint8_t> &p_index_array, int p_index_count, const AABB &p_aabb, const Vector<Vector<uint8_t>> &p_blend_shapes, const Vector<AABB> &p_bone_aabb, const Vector<RS::SurfaceData::LOD> &p_lods) {
+void ArrayMesh::add_surface(uint32_t p_format, PrimitiveType p_primitive, const Vector<uint8_t> &p_array, const Vector<uint8_t> &p_attribute_array, const Vector<uint8_t> &p_skin_array, int p_vertex_count, const Vector<uint8_t> &p_index_array, int p_index_count, const AABB &p_aabb, const Vector<uint8_t> &p_blend_shape_data, uint32_t p_blend_shape_count, const Vector<AABB> &p_bone_aabbs, const Vector<RS::SurfaceData::LOD> &p_lods) {
 	_create_if_empty();
 
 	Surface s;
@@ -1090,10 +1162,13 @@ void ArrayMesh::add_surface(uint32_t p_format, PrimitiveType p_primitive, const
 	sd.aabb = p_aabb;
 	sd.vertex_count = p_vertex_count;
 	sd.vertex_data = p_array;
+	sd.attribute_data = p_attribute_array;
+	sd.skin_data = p_skin_array;
 	sd.index_count = p_index_count;
 	sd.index_data = p_index_array;
-	sd.blend_shapes = p_blend_shapes;
-	sd.bone_aabbs = p_bone_aabb;
+	sd.blend_shape_data = p_blend_shape_data;
+	sd.blend_shape_count = p_blend_shape_count;
+	sd.bone_aabbs = p_bone_aabbs;
 	sd.lods = p_lods;
 
 	RenderingServer::get_singleton()->mesh_add_surface(mesh, sd);
@@ -1119,7 +1194,7 @@ void ArrayMesh::add_surface_from_arrays(PrimitiveType p_primitive, const Array &
 	print_line("index count: " + itos(surface.index_count));
 	print_line("primitive: " + itos(surface.primitive));
 */
-	add_surface(surface.format, PrimitiveType(surface.primitive), surface.vertex_data, surface.vertex_count, surface.index_data, surface.index_count, surface.aabb, surface.blend_shapes, surface.bone_aabbs, surface.lods);
+	add_surface(surface.format, PrimitiveType(surface.primitive), surface.vertex_data, surface.attribute_data, surface.skin_data, surface.vertex_count, surface.index_data, surface.index_count, surface.aabb, surface.blend_shape_data, surface.blend_shape_count, surface.bone_aabbs, surface.lods);
 }
 
 Array ArrayMesh::surface_get_arrays(int p_surface) const {
@@ -1452,29 +1527,29 @@ Error ArrayMesh::lightmap_unwrap_cached(int *&r_cache_data, unsigned int &r_cach
 			SurfaceTool::Vertex v = lightmap_surfaces[surface].vertices[uv_indices[gen_vertices[gen_indices[i + j]]].second];
 
 			if (lightmap_surfaces[surface].format & ARRAY_FORMAT_COLOR) {
-				surfaces_tools.write[surface]->add_color(v.color);
+				surfaces_tools.write[surface]->set_color(v.color);
 			}
 			if (lightmap_surfaces[surface].format & ARRAY_FORMAT_TEX_UV) {
-				surfaces_tools.write[surface]->add_uv(v.uv);
+				surfaces_tools.write[surface]->set_uv(v.uv);
 			}
 			if (lightmap_surfaces[surface].format & ARRAY_FORMAT_NORMAL) {
-				surfaces_tools.write[surface]->add_normal(v.normal);
+				surfaces_tools.write[surface]->set_normal(v.normal);
 			}
 			if (lightmap_surfaces[surface].format & ARRAY_FORMAT_TANGENT) {
 				Plane t;
 				t.normal = v.tangent;
 				t.d = v.binormal.dot(v.normal.cross(v.tangent)) < 0 ? -1 : 1;
-				surfaces_tools.write[surface]->add_tangent(t);
+				surfaces_tools.write[surface]->set_tangent(t);
 			}
 			if (lightmap_surfaces[surface].format & ARRAY_FORMAT_BONES) {
-				surfaces_tools.write[surface]->add_bones(v.bones);
+				surfaces_tools.write[surface]->set_bones(v.bones);
 			}
 			if (lightmap_surfaces[surface].format & ARRAY_FORMAT_WEIGHTS) {
-				surfaces_tools.write[surface]->add_weights(v.weights);
+				surfaces_tools.write[surface]->set_weights(v.weights);
 			}
 
 			Vector2 uv2(gen_uvs[gen_indices[i + j] * 2 + 0], gen_uvs[gen_indices[i + j] * 2 + 1]);
-			surfaces_tools.write[surface]->add_uv2(uv2);
+			surfaces_tools.write[surface]->set_uv2(uv2);
 
 			surfaces_tools.write[surface]->add_vertex(v.vertex);
 		}
@@ -1507,7 +1582,7 @@ void ArrayMesh::_bind_methods() {
 	ClassDB::bind_method(D_METHOD("set_blend_shape_mode", "mode"), &ArrayMesh::set_blend_shape_mode);
 	ClassDB::bind_method(D_METHOD("get_blend_shape_mode"), &ArrayMesh::get_blend_shape_mode);
 
-	ClassDB::bind_method(D_METHOD("add_surface_from_arrays", "primitive", "arrays", "blend_shapes", "lods", "compress_flags"), &ArrayMesh::add_surface_from_arrays, DEFVAL(Array()), DEFVAL(Dictionary()), DEFVAL(ARRAY_COMPRESS_DEFAULT));
+	ClassDB::bind_method(D_METHOD("add_surface_from_arrays", "primitive", "arrays", "blend_shapes", "lods", "compress_flags"), &ArrayMesh::add_surface_from_arrays, DEFVAL(Array()), DEFVAL(Dictionary()), DEFVAL(0));
 	ClassDB::bind_method(D_METHOD("clear_surfaces"), &ArrayMesh::clear_surfaces);
 	ClassDB::bind_method(D_METHOD("surface_update_region", "surf_idx", "offset", "data"), &ArrayMesh::surface_update_region);
 	ClassDB::bind_method(D_METHOD("surface_get_array_len", "surf_idx"), &ArrayMesh::surface_get_array_len);
@@ -1546,20 +1621,53 @@ void ArrayMesh::_bind_methods() {
 	BIND_ENUM_CONSTANT(ARRAY_COLOR);
 	BIND_ENUM_CONSTANT(ARRAY_TEX_UV);
 	BIND_ENUM_CONSTANT(ARRAY_TEX_UV2);
+	BIND_ENUM_CONSTANT(ARRAY_CUSTOM0);
+	BIND_ENUM_CONSTANT(ARRAY_CUSTOM1);
+	BIND_ENUM_CONSTANT(ARRAY_CUSTOM2);
+	BIND_ENUM_CONSTANT(ARRAY_CUSTOM3);
 	BIND_ENUM_CONSTANT(ARRAY_BONES);
 	BIND_ENUM_CONSTANT(ARRAY_WEIGHTS);
 	BIND_ENUM_CONSTANT(ARRAY_INDEX);
 	BIND_ENUM_CONSTANT(ARRAY_MAX);
 
+	BIND_ENUM_CONSTANT(ARRAY_CUSTOM_RGBA8_UNORM);
+	BIND_ENUM_CONSTANT(ARRAY_CUSTOM_RGBA8_SNORM);
+	BIND_ENUM_CONSTANT(ARRAY_CUSTOM_RG_HALF);
+	BIND_ENUM_CONSTANT(ARRAY_CUSTOM_RGBA_HALF);
+	BIND_ENUM_CONSTANT(ARRAY_CUSTOM_R_FLOAT);
+	BIND_ENUM_CONSTANT(ARRAY_CUSTOM_RG_FLOAT);
+	BIND_ENUM_CONSTANT(ARRAY_CUSTOM_RGB_FLOAT);
+	BIND_ENUM_CONSTANT(ARRAY_CUSTOM_RGBA_FLOAT);
+	BIND_ENUM_CONSTANT(ARRAY_CUSTOM_MAX);
+
 	BIND_ENUM_CONSTANT(ARRAY_FORMAT_VERTEX);
 	BIND_ENUM_CONSTANT(ARRAY_FORMAT_NORMAL);
 	BIND_ENUM_CONSTANT(ARRAY_FORMAT_TANGENT);
 	BIND_ENUM_CONSTANT(ARRAY_FORMAT_COLOR);
 	BIND_ENUM_CONSTANT(ARRAY_FORMAT_TEX_UV);
 	BIND_ENUM_CONSTANT(ARRAY_FORMAT_TEX_UV2);
+	BIND_ENUM_CONSTANT(ARRAY_FORMAT_CUSTOM0);
+	BIND_ENUM_CONSTANT(ARRAY_FORMAT_CUSTOM1);
+	BIND_ENUM_CONSTANT(ARRAY_FORMAT_CUSTOM2);
+	BIND_ENUM_CONSTANT(ARRAY_FORMAT_CUSTOM3);
 	BIND_ENUM_CONSTANT(ARRAY_FORMAT_BONES);
 	BIND_ENUM_CONSTANT(ARRAY_FORMAT_WEIGHTS);
 	BIND_ENUM_CONSTANT(ARRAY_FORMAT_INDEX);
+
+	BIND_ENUM_CONSTANT(ARRAY_FORMAT_BLEND_SHAPE_MASK);
+
+	BIND_ENUM_CONSTANT(ARRAY_FORMAT_CUSTOM_BASE);
+	BIND_ENUM_CONSTANT(ARRAY_FORMAT_CUSTOM0_SHIFT);
+	BIND_ENUM_CONSTANT(ARRAY_FORMAT_CUSTOM1_SHIFT);
+	BIND_ENUM_CONSTANT(ARRAY_FORMAT_CUSTOM2_SHIFT);
+	BIND_ENUM_CONSTANT(ARRAY_FORMAT_CUSTOM3_SHIFT);
+
+	BIND_ENUM_CONSTANT(ARRAY_FORMAT_CUSTOM_MASK);
+	BIND_ENUM_CONSTANT(ARRAY_COMPRESS_FLAGS_BASE);
+
+	BIND_ENUM_CONSTANT(ARRAY_FLAG_USE_2D_VERTICES);
+	BIND_ENUM_CONSTANT(ARRAY_FLAG_USE_DYNAMIC_UPDATE);
+	BIND_ENUM_CONSTANT(ARRAY_FLAG_USE_8_BONE_WEIGHTS);
 }
 
 void ArrayMesh::reload_from_file() {

+ 47 - 25
scene/resources/mesh.h

@@ -61,6 +61,10 @@ public:
 		ARRAY_COLOR = RenderingServer::ARRAY_COLOR,
 		ARRAY_TEX_UV = RenderingServer::ARRAY_TEX_UV,
 		ARRAY_TEX_UV2 = RenderingServer::ARRAY_TEX_UV2,
+		ARRAY_CUSTOM0 = RenderingServer::ARRAY_CUSTOM0,
+		ARRAY_CUSTOM1 = RenderingServer::ARRAY_CUSTOM1,
+		ARRAY_CUSTOM2 = RenderingServer::ARRAY_CUSTOM2,
+		ARRAY_CUSTOM3 = RenderingServer::ARRAY_CUSTOM3,
 		ARRAY_BONES = RenderingServer::ARRAY_BONES,
 		ARRAY_WEIGHTS = RenderingServer::ARRAY_WEIGHTS,
 		ARRAY_INDEX = RenderingServer::ARRAY_INDEX,
@@ -68,30 +72,47 @@ public:
 
 	};
 
+	enum ArrayCustomFormat {
+		ARRAY_CUSTOM_RGBA8_UNORM,
+		ARRAY_CUSTOM_RGBA8_SNORM,
+		ARRAY_CUSTOM_RG_HALF,
+		ARRAY_CUSTOM_RGBA_HALF,
+		ARRAY_CUSTOM_R_FLOAT,
+		ARRAY_CUSTOM_RG_FLOAT,
+		ARRAY_CUSTOM_RGB_FLOAT,
+		ARRAY_CUSTOM_RGBA_FLOAT,
+		ARRAY_CUSTOM_MAX
+	};
+
 	enum ArrayFormat {
-		/* ARRAY FORMAT FLAGS */
-		ARRAY_FORMAT_VERTEX = 1 << ARRAY_VERTEX, // mandatory
-		ARRAY_FORMAT_NORMAL = 1 << ARRAY_NORMAL,
-		ARRAY_FORMAT_TANGENT = 1 << ARRAY_TANGENT,
-		ARRAY_FORMAT_COLOR = 1 << ARRAY_COLOR,
-		ARRAY_FORMAT_TEX_UV = 1 << ARRAY_TEX_UV,
-		ARRAY_FORMAT_TEX_UV2 = 1 << ARRAY_TEX_UV2,
-		ARRAY_FORMAT_BONES = 1 << ARRAY_BONES,
-		ARRAY_FORMAT_WEIGHTS = 1 << ARRAY_WEIGHTS,
-		ARRAY_FORMAT_INDEX = 1 << ARRAY_INDEX,
-
-		ARRAY_COMPRESS_BASE = (ARRAY_INDEX + 1),
-		ARRAY_COMPRESS_NORMAL = 1 << (ARRAY_NORMAL + ARRAY_COMPRESS_BASE),
-		ARRAY_COMPRESS_TANGENT = 1 << (ARRAY_TANGENT + ARRAY_COMPRESS_BASE),
-		ARRAY_COMPRESS_COLOR = 1 << (ARRAY_COLOR + ARRAY_COMPRESS_BASE),
-		ARRAY_COMPRESS_TEX_UV = 1 << (ARRAY_TEX_UV + ARRAY_COMPRESS_BASE),
-		ARRAY_COMPRESS_TEX_UV2 = 1 << (ARRAY_TEX_UV2 + ARRAY_COMPRESS_BASE),
-		ARRAY_COMPRESS_INDEX = 1 << (ARRAY_INDEX + ARRAY_COMPRESS_BASE),
-
-		ARRAY_FLAG_USE_2D_VERTICES = ARRAY_COMPRESS_INDEX << 1,
-		ARRAY_FLAG_USE_DYNAMIC_UPDATE = ARRAY_COMPRESS_INDEX << 3,
-
-		ARRAY_COMPRESS_DEFAULT = ARRAY_COMPRESS_NORMAL | ARRAY_COMPRESS_TANGENT | ARRAY_COMPRESS_COLOR | ARRAY_COMPRESS_TEX_UV | ARRAY_COMPRESS_TEX_UV2
+		ARRAY_FORMAT_VERTEX = RS::ARRAY_FORMAT_VERTEX,
+		ARRAY_FORMAT_NORMAL = RS::ARRAY_FORMAT_NORMAL,
+		ARRAY_FORMAT_TANGENT = RS::ARRAY_FORMAT_TANGENT,
+		ARRAY_FORMAT_COLOR = RS::ARRAY_FORMAT_COLOR,
+		ARRAY_FORMAT_TEX_UV = RS::ARRAY_FORMAT_TEX_UV,
+		ARRAY_FORMAT_TEX_UV2 = RS::ARRAY_FORMAT_TEX_UV2,
+		ARRAY_FORMAT_CUSTOM0 = RS::ARRAY_FORMAT_CUSTOM0,
+		ARRAY_FORMAT_CUSTOM1 = RS::ARRAY_FORMAT_CUSTOM1,
+		ARRAY_FORMAT_CUSTOM2 = RS::ARRAY_FORMAT_CUSTOM2,
+		ARRAY_FORMAT_CUSTOM3 = RS::ARRAY_FORMAT_CUSTOM3,
+		ARRAY_FORMAT_BONES = RS::ARRAY_FORMAT_BONES,
+		ARRAY_FORMAT_WEIGHTS = RS::ARRAY_FORMAT_WEIGHTS,
+		ARRAY_FORMAT_INDEX = RS::ARRAY_FORMAT_INDEX,
+
+		ARRAY_FORMAT_BLEND_SHAPE_MASK = RS::ARRAY_FORMAT_BLEND_SHAPE_MASK,
+
+		ARRAY_FORMAT_CUSTOM_BASE = RS::ARRAY_FORMAT_CUSTOM_BASE,
+		ARRAY_FORMAT_CUSTOM0_SHIFT = RS::ARRAY_FORMAT_CUSTOM0_SHIFT,
+		ARRAY_FORMAT_CUSTOM1_SHIFT = RS::ARRAY_FORMAT_CUSTOM1_SHIFT,
+		ARRAY_FORMAT_CUSTOM2_SHIFT = RS::ARRAY_FORMAT_CUSTOM2_SHIFT,
+		ARRAY_FORMAT_CUSTOM3_SHIFT = RS::ARRAY_FORMAT_CUSTOM3_SHIFT,
+
+		ARRAY_FORMAT_CUSTOM_MASK = RS::ARRAY_FORMAT_CUSTOM_MASK,
+		ARRAY_COMPRESS_FLAGS_BASE = RS::ARRAY_COMPRESS_FLAGS_BASE,
+
+		ARRAY_FLAG_USE_2D_VERTICES = RS::ARRAY_FLAG_USE_2D_VERTICES,
+		ARRAY_FLAG_USE_DYNAMIC_UPDATE = RS::ARRAY_FLAG_USE_DYNAMIC_UPDATE,
+		ARRAY_FLAG_USE_8_BONE_WEIGHTS = RS::ARRAY_FLAG_USE_8_BONE_WEIGHTS,
 
 	};
 
@@ -187,9 +208,9 @@ protected:
 	static void _bind_methods();
 
 public:
-	void add_surface_from_arrays(PrimitiveType p_primitive, const Array &p_arrays, const Array &p_blend_shapes = Array(), const Dictionary &p_lods = Dictionary(), uint32_t p_flags = ARRAY_COMPRESS_DEFAULT);
+	void add_surface_from_arrays(PrimitiveType p_primitive, const Array &p_arrays, const Array &p_blend_shapes = Array(), const Dictionary &p_lods = Dictionary(), uint32_t p_flags = 0);
 
-	void add_surface(uint32_t p_format, PrimitiveType p_primitive, const Vector<uint8_t> &p_array, int p_vertex_count, const Vector<uint8_t> &p_index_array, int p_index_count, const AABB &p_aabb, const Vector<Vector<uint8_t>> &p_blend_shapes = Vector<Vector<uint8_t>>(), const Vector<AABB> &p_bone_aabbs = Vector<AABB>(), const Vector<RS::SurfaceData::LOD> &p_lods = Vector<RS::SurfaceData::LOD>());
+	void add_surface(uint32_t p_format, PrimitiveType p_primitive, const Vector<uint8_t> &p_array, const Vector<uint8_t> &p_attribute_array, const Vector<uint8_t> &p_skin_array, int p_vertex_count, const Vector<uint8_t> &p_index_array, int p_index_count, const AABB &p_aabb, const Vector<uint8_t> &p_blend_shape_data = Vector<uint8_t>(), uint32_t p_blend_shape_count = 0, const Vector<AABB> &p_bone_aabbs = Vector<AABB>(), const Vector<RS::SurfaceData::LOD> &p_lods = Vector<RS::SurfaceData::LOD>());
 
 	Array surface_get_arrays(int p_surface) const override;
 	Array surface_get_blend_shape_arrays(int p_surface) const override;
@@ -244,6 +265,7 @@ public:
 
 VARIANT_ENUM_CAST(Mesh::ArrayType);
 VARIANT_ENUM_CAST(Mesh::ArrayFormat);
+VARIANT_ENUM_CAST(Mesh::ArrayCustomFormat);
 VARIANT_ENUM_CAST(Mesh::PrimitiveType);
 VARIANT_ENUM_CAST(Mesh::BlendShapeMode);
 

+ 1 - 1
scene/resources/primitive_meshes.cpp

@@ -148,7 +148,7 @@ Array PrimitiveMesh::surface_get_blend_shape_arrays(int p_surface) const {
 uint32_t PrimitiveMesh::surface_get_format(int p_idx) const {
 	ERR_FAIL_INDEX_V(p_idx, 1, 0);
 
-	return RS::ARRAY_FORMAT_VERTEX | RS::ARRAY_FORMAT_NORMAL | RS::ARRAY_FORMAT_TANGENT | RS::ARRAY_FORMAT_TEX_UV | RS::ARRAY_FORMAT_INDEX | RS::ARRAY_COMPRESS_DEFAULT;
+	return RS::ARRAY_FORMAT_VERTEX | RS::ARRAY_FORMAT_NORMAL | RS::ARRAY_FORMAT_TANGENT | RS::ARRAY_FORMAT_TEX_UV | RS::ARRAY_FORMAT_INDEX;
 }
 
 Mesh::PrimitiveType PrimitiveMesh::surface_get_primitive_type(int p_idx) const {

+ 308 - 125
scene/resources/surface_tool.cpp

@@ -74,6 +74,12 @@ bool SurfaceTool::Vertex::operator==(const Vertex &p_vertex) const {
 		}
 	}
 
+	for (int i = 0; i < RS::ARRAY_CUSTOM_MAX; i++) {
+		if (custom[i] != p_vertex.custom[i]) {
+			return false;
+		}
+	}
+
 	return true;
 }
 
@@ -87,6 +93,7 @@ uint32_t SurfaceTool::VertexHasher::hash(const Vertex &p_vtx) {
 	h = hash_djb2_buffer((const uint8_t *)&p_vtx.color, sizeof(real_t) * 4, h);
 	h = hash_djb2_buffer((const uint8_t *)p_vtx.bones.ptr(), p_vtx.bones.size() * sizeof(int), h);
 	h = hash_djb2_buffer((const uint8_t *)p_vtx.weights.ptr(), p_vtx.weights.size() * sizeof(float), h);
+	h = hash_djb2_buffer((const uint8_t *)&p_vtx.custom[0], sizeof(Color) * RS::ARRAY_CUSTOM_COUNT, h);
 	return h;
 }
 
@@ -111,8 +118,11 @@ void SurfaceTool::add_vertex(const Vector3 &p_vertex) {
 	vtx.bones = last_bones;
 	vtx.tangent = last_tangent.normal;
 	vtx.binormal = last_normal.cross(last_tangent.normal).normalized() * last_tangent.d;
+	for (int i = 0; i < RS::ARRAY_CUSTOM_COUNT; i++) {
+		vtx.custom[i] = last_custom[i];
+	}
 
-	const int expected_vertices = 4;
+	const int expected_vertices = skin_weights == SKIN_8_WEIGHTS ? 8 : 4;
 
 	if ((format & Mesh::ARRAY_FORMAT_WEIGHTS || format & Mesh::ARRAY_FORMAT_BONES) && (vtx.weights.size() != expected_vertices || vtx.bones.size() != expected_vertices)) {
 		//ensure vertices are the expected amount
@@ -163,7 +173,7 @@ void SurfaceTool::add_vertex(const Vector3 &p_vertex) {
 	format |= Mesh::ARRAY_FORMAT_VERTEX;
 }
 
-void SurfaceTool::add_color(Color p_color) {
+void SurfaceTool::set_color(Color p_color) {
 	ERR_FAIL_COND(!begun);
 
 	ERR_FAIL_COND(!first && !(format & Mesh::ARRAY_FORMAT_COLOR));
@@ -172,7 +182,7 @@ void SurfaceTool::add_color(Color p_color) {
 	last_color = p_color;
 }
 
-void SurfaceTool::add_normal(const Vector3 &p_normal) {
+void SurfaceTool::set_normal(const Vector3 &p_normal) {
 	ERR_FAIL_COND(!begun);
 
 	ERR_FAIL_COND(!first && !(format & Mesh::ARRAY_FORMAT_NORMAL));
@@ -181,7 +191,7 @@ void SurfaceTool::add_normal(const Vector3 &p_normal) {
 	last_normal = p_normal;
 }
 
-void SurfaceTool::add_tangent(const Plane &p_tangent) {
+void SurfaceTool::set_tangent(const Plane &p_tangent) {
 	ERR_FAIL_COND(!begun);
 	ERR_FAIL_COND(!first && !(format & Mesh::ARRAY_FORMAT_TANGENT));
 
@@ -189,7 +199,7 @@ void SurfaceTool::add_tangent(const Plane &p_tangent) {
 	last_tangent = p_tangent;
 }
 
-void SurfaceTool::add_uv(const Vector2 &p_uv) {
+void SurfaceTool::set_uv(const Vector2 &p_uv) {
 	ERR_FAIL_COND(!begun);
 	ERR_FAIL_COND(!first && !(format & Mesh::ARRAY_FORMAT_TEX_UV));
 
@@ -197,7 +207,7 @@ void SurfaceTool::add_uv(const Vector2 &p_uv) {
 	last_uv = p_uv;
 }
 
-void SurfaceTool::add_uv2(const Vector2 &p_uv2) {
+void SurfaceTool::set_uv2(const Vector2 &p_uv2) {
 	ERR_FAIL_COND(!begun);
 	ERR_FAIL_COND(!first && !(format & Mesh::ARRAY_FORMAT_TEX_UV2));
 
@@ -205,19 +215,40 @@ void SurfaceTool::add_uv2(const Vector2 &p_uv2) {
 	last_uv2 = p_uv2;
 }
 
-void SurfaceTool::add_bones(const Vector<int> &p_bones) {
+void SurfaceTool::set_custom(int p_index, const Color &p_custom) {
+	ERR_FAIL_INDEX(p_index, RS::ARRAY_CUSTOM_COUNT);
+	ERR_FAIL_COND(!begun);
+	ERR_FAIL_COND(last_custom_format[p_index] == CUSTOM_MAX);
+	static const uint32_t mask[RS::ARRAY_CUSTOM_COUNT] = { Mesh::ARRAY_FORMAT_CUSTOM0, Mesh::ARRAY_FORMAT_CUSTOM1, Mesh::ARRAY_FORMAT_CUSTOM2, Mesh::ARRAY_FORMAT_CUSTOM3 };
+	static const uint32_t shift[RS::ARRAY_CUSTOM_COUNT] = { Mesh::ARRAY_FORMAT_CUSTOM0_SHIFT, Mesh::ARRAY_FORMAT_CUSTOM1_SHIFT, Mesh::ARRAY_FORMAT_CUSTOM2_SHIFT, Mesh::ARRAY_FORMAT_CUSTOM3_SHIFT };
+	ERR_FAIL_COND(!first && !(format & mask[p_index]));
+
+	if (first) {
+		format |= mask[p_index];
+		format |= last_custom_format[p_index] << shift[p_index];
+	}
+	last_custom[p_index] = p_custom;
+}
+
+void SurfaceTool::set_bones(const Vector<int> &p_bones) {
 	ERR_FAIL_COND(!begun);
 	ERR_FAIL_COND(!first && !(format & Mesh::ARRAY_FORMAT_BONES));
 
 	format |= Mesh::ARRAY_FORMAT_BONES;
+	if (skin_weights == SKIN_8_WEIGHTS) {
+		format |= Mesh::ARRAY_FLAG_USE_8_BONE_WEIGHTS;
+	}
 	last_bones = p_bones;
 }
 
-void SurfaceTool::add_weights(const Vector<float> &p_weights) {
+void SurfaceTool::set_weights(const Vector<float> &p_weights) {
 	ERR_FAIL_COND(!begun);
 	ERR_FAIL_COND(!first && !(format & Mesh::ARRAY_FORMAT_WEIGHTS));
 
 	format |= Mesh::ARRAY_FORMAT_WEIGHTS;
+	if (skin_weights == SKIN_8_WEIGHTS) {
+		format |= Mesh::ARRAY_FLAG_USE_8_BONE_WEIGHTS;
+	}
 	last_weights = p_weights;
 }
 
@@ -238,15 +269,15 @@ void SurfaceTool::add_triangle_fan(const Vector<Vector3> &p_vertices, const Vect
 #define ADD_POINT(n)                    \
 	{                                   \
 		if (p_colors.size() > n)        \
-			add_color(p_colors[n]);     \
+			set_color(p_colors[n]);     \
 		if (p_uvs.size() > n)           \
-			add_uv(p_uvs[n]);           \
+			set_uv(p_uvs[n]);           \
 		if (p_uv2s.size() > n)          \
-			add_uv2(p_uv2s[n]);         \
+			set_uv2(p_uv2s[n]);         \
 		if (p_normals.size() > n)       \
-			add_normal(p_normals[n]);   \
+			set_normal(p_normals[n]);   \
 		if (p_tangents.size() > n)      \
-			add_tangent(p_tangents[n]); \
+			set_tangent(p_tangents[n]); \
 		add_vertex(p_vertices[n]);      \
 	}
 
@@ -358,18 +389,157 @@ Array SurfaceTool::commit_to_arrays() {
 
 				a[i] = array;
 			} break;
+			case Mesh::ARRAY_CUSTOM0:
+			case Mesh::ARRAY_CUSTOM1:
+			case Mesh::ARRAY_CUSTOM2:
+			case Mesh::ARRAY_CUSTOM3: {
+				int fmt = i - Mesh::ARRAY_CUSTOM0;
+				switch (last_custom_format[fmt]) {
+					case CUSTOM_RGBA8_UNORM: {
+						Vector<uint8_t> array;
+						array.resize(varr_len * 4);
+						uint8_t *w = array.ptrw();
+
+						int idx = 0;
+						for (List<Vertex>::Element *E = vertex_array.front(); E; E = E->next(), idx++) {
+							const Vertex &v = E->get();
+							const Color &c = v.custom[idx];
+							w[idx * 4 + 0] = CLAMP(int32_t(c.r * 255.0), 0, 255);
+							w[idx * 4 + 1] = CLAMP(int32_t(c.g * 255.0), 0, 255);
+							w[idx * 4 + 2] = CLAMP(int32_t(c.b * 255.0), 0, 255);
+							w[idx * 4 + 3] = CLAMP(int32_t(c.a * 255.0), 0, 255);
+						}
+
+						a[i] = array;
+					} break;
+					case CUSTOM_RGBA8_SNORM: {
+						Vector<uint8_t> array;
+						array.resize(varr_len * 4);
+						uint8_t *w = array.ptrw();
+
+						int idx = 0;
+						for (List<Vertex>::Element *E = vertex_array.front(); E; E = E->next(), idx++) {
+							const Vertex &v = E->get();
+							const Color &c = v.custom[idx];
+							w[idx * 4 + 0] = uint8_t(int8_t(CLAMP(int32_t(c.r * 127.0), -128, 127)));
+							w[idx * 4 + 1] = uint8_t(int8_t(CLAMP(int32_t(c.g * 127.0), -128, 127)));
+							w[idx * 4 + 2] = uint8_t(int8_t(CLAMP(int32_t(c.b * 127.0), -128, 127)));
+							w[idx * 4 + 3] = uint8_t(int8_t(CLAMP(int32_t(c.a * 127.0), -128, 127)));
+						}
+
+						a[i] = array;
+					} break;
+					case CUSTOM_RG_HALF: {
+						Vector<uint8_t> array;
+						array.resize(varr_len * 4);
+						uint16_t *w = (uint16_t *)array.ptrw();
+
+						int idx = 0;
+						for (List<Vertex>::Element *E = vertex_array.front(); E; E = E->next(), idx++) {
+							const Vertex &v = E->get();
+							const Color &c = v.custom[idx];
+							w[idx * 2 + 0] = Math::make_half_float(c.r);
+							w[idx * 2 + 1] = Math::make_half_float(c.g);
+						}
+
+						a[i] = array;
+					} break;
+					case CUSTOM_RGBA_HALF: {
+						Vector<uint8_t> array;
+						array.resize(varr_len * 8);
+						uint16_t *w = (uint16_t *)array.ptrw();
+
+						int idx = 0;
+						for (List<Vertex>::Element *E = vertex_array.front(); E; E = E->next(), idx++) {
+							const Vertex &v = E->get();
+							const Color &c = v.custom[idx];
+							w[idx * 4 + 0] = Math::make_half_float(c.r);
+							w[idx * 4 + 1] = Math::make_half_float(c.g);
+							w[idx * 4 + 2] = Math::make_half_float(c.b);
+							w[idx * 4 + 3] = Math::make_half_float(c.a);
+						}
+
+						a[i] = array;
+					} break;
+					case CUSTOM_R_FLOAT: {
+						Vector<float> array;
+						array.resize(varr_len);
+						float *w = (float *)array.ptrw();
+
+						int idx = 0;
+						for (List<Vertex>::Element *E = vertex_array.front(); E; E = E->next(), idx++) {
+							const Vertex &v = E->get();
+							const Color &c = v.custom[idx];
+							w[idx] = c.r;
+						}
+
+						a[i] = array;
+					} break;
+					case CUSTOM_RG_FLOAT: {
+						Vector<float> array;
+						array.resize(varr_len * 2);
+						float *w = (float *)array.ptrw();
+
+						int idx = 0;
+						for (List<Vertex>::Element *E = vertex_array.front(); E; E = E->next(), idx++) {
+							const Vertex &v = E->get();
+							const Color &c = v.custom[idx];
+							w[idx * 2 + 0] = c.r;
+							w[idx * 2 + 1] = c.g;
+						}
+
+						a[i] = array;
+					} break;
+					case CUSTOM_RGB_FLOAT: {
+						Vector<float> array;
+						array.resize(varr_len * 3);
+						float *w = (float *)array.ptrw();
+
+						int idx = 0;
+						for (List<Vertex>::Element *E = vertex_array.front(); E; E = E->next(), idx++) {
+							const Vertex &v = E->get();
+							const Color &c = v.custom[idx];
+							w[idx * 3 + 0] = c.r;
+							w[idx * 3 + 1] = c.g;
+							w[idx * 3 + 2] = c.b;
+						}
+
+						a[i] = array;
+					} break;
+					case CUSTOM_RGBA_FLOAT: {
+						Vector<float> array;
+						array.resize(varr_len * 4);
+						float *w = (float *)array.ptrw();
+
+						int idx = 0;
+						for (List<Vertex>::Element *E = vertex_array.front(); E; E = E->next(), idx++) {
+							const Vertex &v = E->get();
+							const Color &c = v.custom[idx];
+							w[idx * 4 + 0] = c.r;
+							w[idx * 4 + 1] = c.g;
+							w[idx * 4 + 2] = c.b;
+							w[idx * 4 + 3] = c.a;
+						}
+
+						a[i] = array;
+					} break;
+					default: {
+					} //unreachable but compiler warning anyway
+				}
+			} break;
 			case Mesh::ARRAY_BONES: {
+				int count = skin_weights == SKIN_8_WEIGHTS ? 8 : 4;
 				Vector<int> array;
-				array.resize(varr_len * 4);
+				array.resize(varr_len * count);
 				int *w = array.ptrw();
 
 				int idx = 0;
-				for (List<Vertex>::Element *E = vertex_array.front(); E; E = E->next(), idx += 4) {
+				for (List<Vertex>::Element *E = vertex_array.front(); E; E = E->next(), idx += count) {
 					const Vertex &v = E->get();
 
-					ERR_CONTINUE(v.bones.size() != 4);
+					ERR_CONTINUE(v.bones.size() != count);
 
-					for (int j = 0; j < 4; j++) {
+					for (int j = 0; j < count; j++) {
 						w[idx + j] = v.bones[j];
 					}
 				}
@@ -379,15 +549,17 @@ Array SurfaceTool::commit_to_arrays() {
 			} break;
 			case Mesh::ARRAY_WEIGHTS: {
 				Vector<float> array;
-				array.resize(varr_len * 4);
+				int count = skin_weights == SKIN_8_WEIGHTS ? 8 : 4;
+
+				array.resize(varr_len * count);
 				float *w = array.ptrw();
 
 				int idx = 0;
-				for (List<Vertex>::Element *E = vertex_array.front(); E; E = E->next(), idx += 4) {
+				for (List<Vertex>::Element *E = vertex_array.front(); E; E = E->next(), idx += count) {
 					const Vertex &v = E->get();
-					ERR_CONTINUE(v.weights.size() != 4);
+					ERR_CONTINUE(v.weights.size() != count);
 
-					for (int j = 0; j < 4; j++) {
+					for (int j = 0; j < count; j++) {
 						w[idx + j] = v.weights[j];
 					}
 				}
@@ -492,13 +664,13 @@ void SurfaceTool::deindex() {
 	index_array.clear();
 }
 
-void SurfaceTool::_create_list(const Ref<Mesh> &p_existing, int p_surface, List<Vertex> *r_vertex, List<int> *r_index, int &lformat) {
+void SurfaceTool::_create_list(const Ref<Mesh> &p_existing, int p_surface, List<Vertex> *r_vertex, List<int> *r_index, uint32_t &lformat) {
 	Array arr = p_existing->surface_get_arrays(p_surface);
 	ERR_FAIL_COND(arr.size() != RS::ARRAY_MAX);
 	_create_list_from_arrays(arr, r_vertex, r_index, lformat);
 }
 
-Vector<SurfaceTool::Vertex> SurfaceTool::create_vertex_array_from_triangle_arrays(const Array &p_arrays) {
+Vector<SurfaceTool::Vertex> SurfaceTool::create_vertex_array_from_triangle_arrays(const Array &p_arrays, uint32_t *r_format) {
 	Vector<SurfaceTool::Vertex> ret;
 
 	Vector<Vector3> varr = p_arrays[RS::ARRAY_VERTEX];
@@ -509,9 +681,13 @@ Vector<SurfaceTool::Vertex> SurfaceTool::create_vertex_array_from_triangle_array
 	Vector<Vector2> uv2arr = p_arrays[RS::ARRAY_TEX_UV2];
 	Vector<int> barr = p_arrays[RS::ARRAY_BONES];
 	Vector<float> warr = p_arrays[RS::ARRAY_WEIGHTS];
+	Vector<float> custom_float[RS::ARRAY_CUSTOM_COUNT];
 
 	int vc = varr.size();
 	if (vc == 0) {
+		if (r_format) {
+			*r_format = 0;
+		}
 		return ret;
 	}
 
@@ -534,12 +710,40 @@ Vector<SurfaceTool::Vertex> SurfaceTool::create_vertex_array_from_triangle_array
 	if (uv2arr.size()) {
 		lformat |= RS::ARRAY_FORMAT_TEX_UV2;
 	}
-	if (barr.size()) {
+	int wcount = 0;
+	if (barr.size() && warr.size()) {
 		lformat |= RS::ARRAY_FORMAT_BONES;
+		lformat |= RS::ARRAY_FORMAT_WEIGHTS;
+
+		wcount = barr.size() / varr.size();
+		if (wcount == 8) {
+			lformat |= RS::ARRAY_FLAG_USE_8_BONE_WEIGHTS;
+		}
 	}
+
 	if (warr.size()) {
 		lformat |= RS::ARRAY_FORMAT_WEIGHTS;
 	}
+	static const uint32_t custom_mask[RS::ARRAY_CUSTOM_COUNT] = { Mesh::ARRAY_FORMAT_CUSTOM0, Mesh::ARRAY_FORMAT_CUSTOM1, Mesh::ARRAY_FORMAT_CUSTOM2, Mesh::ARRAY_FORMAT_CUSTOM3 };
+	static const uint32_t custom_shift[RS::ARRAY_CUSTOM_COUNT] = { Mesh::ARRAY_FORMAT_CUSTOM0_SHIFT, Mesh::ARRAY_FORMAT_CUSTOM1_SHIFT, Mesh::ARRAY_FORMAT_CUSTOM2_SHIFT, Mesh::ARRAY_FORMAT_CUSTOM3_SHIFT };
+
+	for (int i = 0; i < RS::ARRAY_CUSTOM_COUNT; i++) {
+		ERR_CONTINUE_MSG(p_arrays[RS::ARRAY_CUSTOM0 + i].get_type() == Variant::PACKED_BYTE_ARRAY, "Extracting Byte/Half formats is not supported");
+		if (p_arrays[RS::ARRAY_CUSTOM0 + i].get_type() == Variant::PACKED_FLOAT32_ARRAY) {
+			lformat |= custom_mask[i];
+			custom_float[i] = p_arrays[RS::ARRAY_CUSTOM0 + i];
+			int fmt = custom_float[i].size() / varr.size();
+			if (fmt == 1) {
+				lformat |= CUSTOM_R_FLOAT << custom_shift[i];
+			} else if (fmt == 2) {
+				lformat |= CUSTOM_RG_FLOAT << custom_shift[i];
+			} else if (fmt == 3) {
+				lformat |= CUSTOM_RGB_FLOAT << custom_shift[i];
+			} else if (fmt == 4) {
+				lformat |= CUSTOM_RGBA_FLOAT << custom_shift[i];
+			}
+		}
+	}
 
 	for (int i = 0; i < vc; i++) {
 		Vertex v;
@@ -565,112 +769,46 @@ Vector<SurfaceTool::Vertex> SurfaceTool::create_vertex_array_from_triangle_array
 		}
 		if (lformat & RS::ARRAY_FORMAT_BONES) {
 			Vector<int> b;
-			b.resize(4);
-			b.write[0] = barr[i * 4 + 0];
-			b.write[1] = barr[i * 4 + 1];
-			b.write[2] = barr[i * 4 + 2];
-			b.write[3] = barr[i * 4 + 3];
+			b.resize(wcount);
+			for (int j = 0; j < wcount; j++) {
+				b.write[j] = barr[i * wcount + j];
+			}
 			v.bones = b;
 		}
 		if (lformat & RS::ARRAY_FORMAT_WEIGHTS) {
 			Vector<float> w;
-			w.resize(4);
-			w.write[0] = warr[i * 4 + 0];
-			w.write[1] = warr[i * 4 + 1];
-			w.write[2] = warr[i * 4 + 2];
-			w.write[3] = warr[i * 4 + 3];
+			w.resize(wcount);
+			for (int j = 0; j < wcount; j++) {
+				w.write[j] = warr[i * wcount + j];
+			}
 			v.weights = w;
 		}
 
+		for (int j = 0; j < RS::ARRAY_CUSTOM_COUNT; j++) {
+			if (lformat & custom_mask[j]) {
+				int cc = custom_float[j].size() / varr.size();
+				for (int k = 0; k < cc; k++) {
+					v.custom[j][k] = custom_float[j][i * cc + k];
+				}
+			}
+		}
+
 		ret.push_back(v);
 	}
 
-	return ret;
-}
-
-void SurfaceTool::_create_list_from_arrays(Array arr, List<Vertex> *r_vertex, List<int> *r_index, int &lformat) {
-	Vector<Vector3> varr = arr[RS::ARRAY_VERTEX];
-	Vector<Vector3> narr = arr[RS::ARRAY_NORMAL];
-	Vector<float> tarr = arr[RS::ARRAY_TANGENT];
-	Vector<Color> carr = arr[RS::ARRAY_COLOR];
-	Vector<Vector2> uvarr = arr[RS::ARRAY_TEX_UV];
-	Vector<Vector2> uv2arr = arr[RS::ARRAY_TEX_UV2];
-	Vector<int> barr = arr[RS::ARRAY_BONES];
-	Vector<float> warr = arr[RS::ARRAY_WEIGHTS];
-
-	int vc = varr.size();
-	if (vc == 0) {
-		return;
+	if (r_format) {
+		*r_format = lformat;
 	}
 
-	lformat = 0;
-	if (varr.size()) {
-		lformat |= RS::ARRAY_FORMAT_VERTEX;
-	}
-	if (narr.size()) {
-		lformat |= RS::ARRAY_FORMAT_NORMAL;
-	}
-	if (tarr.size()) {
-		lformat |= RS::ARRAY_FORMAT_TANGENT;
-	}
-	if (carr.size()) {
-		lformat |= RS::ARRAY_FORMAT_COLOR;
-	}
-	if (uvarr.size()) {
-		lformat |= RS::ARRAY_FORMAT_TEX_UV;
-	}
-	if (uv2arr.size()) {
-		lformat |= RS::ARRAY_FORMAT_TEX_UV2;
-	}
-	if (barr.size()) {
-		lformat |= RS::ARRAY_FORMAT_BONES;
-	}
-	if (warr.size()) {
-		lformat |= RS::ARRAY_FORMAT_WEIGHTS;
-	}
+	return ret;
+}
 
-	for (int i = 0; i < vc; i++) {
-		Vertex v;
-		if (lformat & RS::ARRAY_FORMAT_VERTEX) {
-			v.vertex = varr[i];
-		}
-		if (lformat & RS::ARRAY_FORMAT_NORMAL) {
-			v.normal = narr[i];
-		}
-		if (lformat & RS::ARRAY_FORMAT_TANGENT) {
-			Plane p(tarr[i * 4 + 0], tarr[i * 4 + 1], tarr[i * 4 + 2], tarr[i * 4 + 3]);
-			v.tangent = p.normal;
-			v.binormal = p.normal.cross(v.tangent).normalized() * p.d;
-		}
-		if (lformat & RS::ARRAY_FORMAT_COLOR) {
-			v.color = carr[i];
-		}
-		if (lformat & RS::ARRAY_FORMAT_TEX_UV) {
-			v.uv = uvarr[i];
-		}
-		if (lformat & RS::ARRAY_FORMAT_TEX_UV2) {
-			v.uv2 = uv2arr[i];
-		}
-		if (lformat & RS::ARRAY_FORMAT_BONES) {
-			Vector<int> b;
-			b.resize(4);
-			b.write[0] = barr[i * 4 + 0];
-			b.write[1] = barr[i * 4 + 1];
-			b.write[2] = barr[i * 4 + 2];
-			b.write[3] = barr[i * 4 + 3];
-			v.bones = b;
-		}
-		if (lformat & RS::ARRAY_FORMAT_WEIGHTS) {
-			Vector<float> w;
-			w.resize(4);
-			w.write[0] = warr[i * 4 + 0];
-			w.write[1] = warr[i * 4 + 1];
-			w.write[2] = warr[i * 4 + 2];
-			w.write[3] = warr[i * 4 + 3];
-			v.weights = w;
-		}
+void SurfaceTool::_create_list_from_arrays(Array arr, List<Vertex> *r_vertex, List<int> *r_index, uint32_t &lformat) {
+	Vector<Vertex> arrays = create_vertex_array_from_triangle_arrays(arr, &lformat);
+	ERR_FAIL_COND(arrays.size() == 0);
 
-		r_vertex->push_back(v);
+	for (int i = 0; i < arrays.size(); i++) {
+		r_vertex->push_back(arrays[i]);
 	}
 
 	//indices
@@ -725,7 +863,7 @@ void SurfaceTool::append_from(const Ref<Mesh> &p_existing, int p_surface, const
 		format = 0;
 	}
 
-	int nformat;
+	uint32_t nformat;
 	List<Vertex> nvertices;
 	List<int> nindices;
 	_create_list(p_existing, p_surface, &nvertices, &nindices, nformat);
@@ -975,19 +1113,48 @@ void SurfaceTool::clear() {
 	vertex_array.clear();
 	smooth_groups.clear();
 	material.unref();
+	for (int i = 0; i < RS::ARRAY_CUSTOM_COUNT; i++) {
+		last_custom_format[i] = CUSTOM_MAX;
+	}
+	skin_weights = SKIN_4_WEIGHTS;
+}
+
+void SurfaceTool::set_skin_weight_count(SkinWeightCount p_weights) {
+	ERR_FAIL_COND(begun);
+	skin_weights = p_weights;
+}
+SurfaceTool::SkinWeightCount SurfaceTool::get_skin_weight_count() const {
+	return skin_weights;
+}
+
+void SurfaceTool::set_custom_format(int p_index, CustomFormat p_format) {
+	ERR_FAIL_INDEX(p_index, RS::ARRAY_CUSTOM_COUNT);
+	ERR_FAIL_COND(begun);
+	last_custom_format[p_index] = p_format;
+}
+SurfaceTool::CustomFormat SurfaceTool::get_custom_format(int p_index) const {
+	ERR_FAIL_INDEX_V(p_index, RS::ARRAY_CUSTOM_COUNT, CUSTOM_MAX);
+	return last_custom_format[p_index];
 }
 
 void SurfaceTool::_bind_methods() {
+	ClassDB::bind_method(D_METHOD("set_skin_weight_count", "count"), &SurfaceTool::set_skin_weight_count);
+	ClassDB::bind_method(D_METHOD("get_skin_weight_count"), &SurfaceTool::get_skin_weight_count);
+
+	ClassDB::bind_method(D_METHOD("set_custom_format", "index", "format"), &SurfaceTool::set_custom_format);
+	ClassDB::bind_method(D_METHOD("get_custom_format", "index"), &SurfaceTool::get_custom_format);
+
 	ClassDB::bind_method(D_METHOD("begin", "primitive"), &SurfaceTool::begin);
 
 	ClassDB::bind_method(D_METHOD("add_vertex", "vertex"), &SurfaceTool::add_vertex);
-	ClassDB::bind_method(D_METHOD("add_color", "color"), &SurfaceTool::add_color);
-	ClassDB::bind_method(D_METHOD("add_normal", "normal"), &SurfaceTool::add_normal);
-	ClassDB::bind_method(D_METHOD("add_tangent", "tangent"), &SurfaceTool::add_tangent);
-	ClassDB::bind_method(D_METHOD("add_uv", "uv"), &SurfaceTool::add_uv);
-	ClassDB::bind_method(D_METHOD("add_uv2", "uv2"), &SurfaceTool::add_uv2);
-	ClassDB::bind_method(D_METHOD("add_bones", "bones"), &SurfaceTool::add_bones);
-	ClassDB::bind_method(D_METHOD("add_weights", "weights"), &SurfaceTool::add_weights);
+	ClassDB::bind_method(D_METHOD("set_color", "color"), &SurfaceTool::set_color);
+	ClassDB::bind_method(D_METHOD("set_normal", "normal"), &SurfaceTool::set_normal);
+	ClassDB::bind_method(D_METHOD("set_tangent", "tangent"), &SurfaceTool::set_tangent);
+	ClassDB::bind_method(D_METHOD("set_uv", "uv"), &SurfaceTool::set_uv);
+	ClassDB::bind_method(D_METHOD("set_uv2", "uv2"), &SurfaceTool::set_uv2);
+	ClassDB::bind_method(D_METHOD("set_bones", "bones"), &SurfaceTool::set_bones);
+	ClassDB::bind_method(D_METHOD("set_weights", "weights"), &SurfaceTool::set_weights);
+	ClassDB::bind_method(D_METHOD("set_custom", "index", "custom"), &SurfaceTool::set_custom);
 	ClassDB::bind_method(D_METHOD("add_smooth_group", "smooth"), &SurfaceTool::add_smooth_group);
 
 	ClassDB::bind_method(D_METHOD("add_triangle_fan", "vertices", "uvs", "colors", "uv2s", "normals", "tangents"), &SurfaceTool::add_triangle_fan, DEFVAL(Vector<Vector2>()), DEFVAL(Vector<Color>()), DEFVAL(Vector<Vector2>()), DEFVAL(Vector<Vector3>()), DEFVAL(Vector<Plane>()));
@@ -1006,13 +1173,29 @@ void SurfaceTool::_bind_methods() {
 	ClassDB::bind_method(D_METHOD("create_from", "existing", "surface"), &SurfaceTool::create_from);
 	ClassDB::bind_method(D_METHOD("create_from_blend_shape", "existing", "surface", "blend_shape"), &SurfaceTool::create_from_blend_shape);
 	ClassDB::bind_method(D_METHOD("append_from", "existing", "surface", "transform"), &SurfaceTool::append_from);
-	ClassDB::bind_method(D_METHOD("commit", "existing", "flags"), &SurfaceTool::commit, DEFVAL(Variant()), DEFVAL(Mesh::ARRAY_COMPRESS_DEFAULT));
+	ClassDB::bind_method(D_METHOD("commit", "existing", "flags"), &SurfaceTool::commit, DEFVAL(Variant()), DEFVAL(0));
 	ClassDB::bind_method(D_METHOD("commit_to_arrays"), &SurfaceTool::commit_to_arrays);
+
+	BIND_ENUM_CONSTANT(CUSTOM_RGBA8_UNORM);
+	BIND_ENUM_CONSTANT(CUSTOM_RGBA8_SNORM);
+	BIND_ENUM_CONSTANT(CUSTOM_RG_HALF);
+	BIND_ENUM_CONSTANT(CUSTOM_RGBA_HALF);
+	BIND_ENUM_CONSTANT(CUSTOM_R_FLOAT);
+	BIND_ENUM_CONSTANT(CUSTOM_RG_FLOAT);
+	BIND_ENUM_CONSTANT(CUSTOM_RGB_FLOAT);
+	BIND_ENUM_CONSTANT(CUSTOM_RGBA_FLOAT);
+	BIND_ENUM_CONSTANT(CUSTOM_MAX);
+	BIND_ENUM_CONSTANT(SKIN_4_WEIGHTS);
+	BIND_ENUM_CONSTANT(SKIN_8_WEIGHTS);
 }
 
 SurfaceTool::SurfaceTool() {
 	first = false;
 	begun = false;
+	for (int i = 0; i < RS::ARRAY_CUSTOM_COUNT; i++) {
+		last_custom_format[i] = CUSTOM_MAX;
+	}
 	primitive = Mesh::PRIMITIVE_LINES;
+	skin_weights = SKIN_4_WEIGHTS;
 	format = 0;
 }

+ 48 - 13
scene/resources/surface_tool.h

@@ -49,12 +49,30 @@ public:
 		Vector2 uv2;
 		Vector<int> bones;
 		Vector<float> weights;
+		Color custom[RS::ARRAY_CUSTOM_COUNT];
 
 		bool operator==(const Vertex &p_vertex) const;
 
 		Vertex() {}
 	};
 
+	enum CustomFormat {
+		CUSTOM_RGBA8_UNORM = RS::ARRAY_CUSTOM_RGBA8_UNORM,
+		CUSTOM_RGBA8_SNORM = RS::ARRAY_CUSTOM_RGBA8_SNORM,
+		CUSTOM_RG_HALF = RS::ARRAY_CUSTOM_RG_HALF,
+		CUSTOM_RGBA_HALF = RS::ARRAY_CUSTOM_RGBA_HALF,
+		CUSTOM_R_FLOAT = RS::ARRAY_CUSTOM_R_FLOAT,
+		CUSTOM_RG_FLOAT = RS::ARRAY_CUSTOM_RG_FLOAT,
+		CUSTOM_RGB_FLOAT = RS::ARRAY_CUSTOM_RGB_FLOAT,
+		CUSTOM_RGBA_FLOAT = RS::ARRAY_CUSTOM_RGBA_FLOAT,
+		CUSTOM_MAX = RS::ARRAY_CUSTOM_MAX
+	};
+
+	enum SkinWeightCount {
+		SKIN_4_WEIGHTS,
+		SKIN_8_WEIGHTS
+	};
+
 private:
 	struct VertexHasher {
 		static _FORCE_INLINE_ uint32_t hash(const Vertex &p_vtx);
@@ -71,7 +89,7 @@ private:
 	bool begun;
 	bool first;
 	Mesh::PrimitiveType primitive;
-	int format;
+	uint32_t format;
 	Ref<Material> material;
 	//arrays
 	List<Vertex> vertex_array;
@@ -87,8 +105,14 @@ private:
 	Vector<float> last_weights;
 	Plane last_tangent;
 
-	void _create_list_from_arrays(Array arr, List<Vertex> *r_vertex, List<int> *r_index, int &lformat);
-	void _create_list(const Ref<Mesh> &p_existing, int p_surface, List<Vertex> *r_vertex, List<int> *r_index, int &lformat);
+	SkinWeightCount skin_weights;
+
+	Color last_custom[RS::ARRAY_CUSTOM_COUNT];
+
+	CustomFormat last_custom_format[RS::ARRAY_CUSTOM_COUNT];
+
+	void _create_list_from_arrays(Array arr, List<Vertex> *r_vertex, List<int> *r_index, uint32_t &lformat);
+	void _create_list(const Ref<Mesh> &p_existing, int p_surface, List<Vertex> *r_vertex, List<int> *r_index, uint32_t &lformat);
 
 	//mikktspace callbacks
 	static int mikktGetNumFaces(const SMikkTSpaceContext *pContext);
@@ -103,18 +127,26 @@ protected:
 	static void _bind_methods();
 
 public:
+	void set_skin_weight_count(SkinWeightCount p_weights);
+	SkinWeightCount get_skin_weight_count() const;
+
+	void set_custom_format(int p_index, CustomFormat p_format);
+	CustomFormat get_custom_format(int p_index) const;
+
 	void begin(Mesh::PrimitiveType p_primitive);
 
+	void set_color(Color p_color);
+	void set_normal(const Vector3 &p_normal);
+	void set_tangent(const Plane &p_tangent);
+	void set_uv(const Vector2 &p_uv);
+	void set_uv2(const Vector2 &p_uv2);
+	void set_custom(int p_index, const Color &p_custom);
+	void set_bones(const Vector<int> &p_bones);
+	void set_weights(const Vector<float> &p_weights);
+
 	void add_vertex(const Vector3 &p_vertex);
-	void add_color(Color p_color);
-	void add_normal(const Vector3 &p_normal);
-	void add_tangent(const Plane &p_tangent);
-	void add_uv(const Vector2 &p_uv);
-	void add_uv2(const Vector2 &p_uv2);
-	void add_bones(const Vector<int> &p_bones);
-	void add_weights(const Vector<float> &p_weights);
-	void add_smooth_group(bool p_smooth);
 
+	void add_smooth_group(bool p_smooth);
 	void add_triangle_fan(const Vector<Vector3> &p_vertices, const Vector<Vector2> &p_uvs = Vector<Vector2>(), const Vector<Color> &p_colors = Vector<Color>(), const Vector<Vector2> &p_uv2s = Vector<Vector2>(), const Vector<Vector3> &p_normals = Vector<Vector3>(), const Vector<Plane> &p_tangents = Vector<Plane>());
 
 	void add_index(int p_index);
@@ -131,14 +163,17 @@ public:
 	List<Vertex> &get_vertex_array() { return vertex_array; }
 
 	void create_from_triangle_arrays(const Array &p_arrays);
-	static Vector<Vertex> create_vertex_array_from_triangle_arrays(const Array &p_arrays);
+	static Vector<Vertex> create_vertex_array_from_triangle_arrays(const Array &p_arrays, uint32_t *r_format = nullptr);
 	Array commit_to_arrays();
 	void create_from(const Ref<Mesh> &p_existing, int p_surface);
 	void create_from_blend_shape(const Ref<Mesh> &p_existing, int p_surface, const String &p_blend_shape_name);
 	void append_from(const Ref<Mesh> &p_existing, int p_surface, const Transform &p_xform);
-	Ref<ArrayMesh> commit(const Ref<ArrayMesh> &p_existing = Ref<ArrayMesh>(), uint32_t p_flags = Mesh::ARRAY_COMPRESS_DEFAULT);
+	Ref<ArrayMesh> commit(const Ref<ArrayMesh> &p_existing = Ref<ArrayMesh>(), uint32_t p_flags = 0);
 
 	SurfaceTool();
 };
 
+VARIANT_ENUM_CAST(SurfaceTool::CustomFormat)
+VARIANT_ENUM_CAST(SurfaceTool::SkinWeightCount)
+
 #endif

+ 67 - 36
servers/rendering/rasterizer_rd/rasterizer_canvas_rd.cpp

@@ -119,9 +119,9 @@ RasterizerCanvas::PolygonID RasterizerCanvasRD::request_polygon(const Vector<int
 	Vector<uint8_t> polygon_buffer;
 	polygon_buffer.resize(buffer_size * sizeof(float));
 	Vector<RD::VertexAttribute> descriptions;
-	descriptions.resize(4);
+	descriptions.resize(5);
 	Vector<RID> buffers;
-	buffers.resize(4);
+	buffers.resize(5);
 
 	{
 		const uint8_t *r = polygon_buffer.ptr();
@@ -218,7 +218,7 @@ RasterizerCanvas::PolygonID RasterizerCanvasRD::request_polygon(const Vector<int
 		//bones
 		if ((uint32_t)p_indices.size() == vertex_count * 4 && (uint32_t)p_weights.size() == vertex_count * 4) {
 			RD::VertexAttribute vd;
-			vd.format = RD::DATA_FORMAT_R32G32B32A32_UINT;
+			vd.format = RD::DATA_FORMAT_R16G16B16A16_UINT;
 			vd.offset = base_offset * sizeof(float);
 			vd.location = RS::ARRAY_BONES;
 			vd.stride = stride * sizeof(float);
@@ -226,16 +226,42 @@ RasterizerCanvas::PolygonID RasterizerCanvasRD::request_polygon(const Vector<int
 			descriptions.write[3] = vd;
 
 			const int *bone_ptr = p_bones.ptr();
-			const float *weight_ptr = p_weights.ptr();
 
 			for (uint32_t i = 0; i < vertex_count; i++) {
 				uint16_t *bone16w = (uint16_t *)&uptr[base_offset + i * stride];
-				uint16_t *weight16w = (uint16_t *)&uptr[base_offset + i * stride + 2];
 
 				bone16w[0] = bone_ptr[i * 4 + 0];
 				bone16w[1] = bone_ptr[i * 4 + 1];
 				bone16w[2] = bone_ptr[i * 4 + 2];
 				bone16w[3] = bone_ptr[i * 4 + 3];
+			}
+
+			base_offset += 2;
+		} else {
+			RD::VertexAttribute vd;
+			vd.format = RD::DATA_FORMAT_R32G32B32A32_UINT;
+			vd.offset = 0;
+			vd.location = RS::ARRAY_BONES;
+			vd.stride = 0;
+
+			descriptions.write[3] = vd;
+			buffers.write[3] = storage->mesh_get_default_rd_buffer(RasterizerStorageRD::DEFAULT_RD_BUFFER_BONES);
+		}
+
+		//weights
+		if ((uint32_t)p_weights.size() == vertex_count * 4) {
+			RD::VertexAttribute vd;
+			vd.format = RD::DATA_FORMAT_R16G16B16A16_UNORM;
+			vd.offset = base_offset * sizeof(float);
+			vd.location = RS::ARRAY_WEIGHTS;
+			vd.stride = stride * sizeof(float);
+
+			descriptions.write[4] = vd;
+
+			const float *weight_ptr = p_weights.ptr();
+
+			for (uint32_t i = 0; i < vertex_count; i++) {
+				uint16_t *weight16w = (uint16_t *)&uptr[base_offset + i * stride];
 
 				weight16w[0] = CLAMP(weight_ptr[i * 4 + 0] * 65535, 0, 65535);
 				weight16w[1] = CLAMP(weight_ptr[i * 4 + 1] * 65535, 0, 65535);
@@ -243,16 +269,16 @@ RasterizerCanvas::PolygonID RasterizerCanvasRD::request_polygon(const Vector<int
 				weight16w[3] = CLAMP(weight_ptr[i * 4 + 3] * 65535, 0, 65535);
 			}
 
-			base_offset += 4;
+			base_offset += 2;
 		} else {
 			RD::VertexAttribute vd;
-			vd.format = RD::DATA_FORMAT_R32G32B32A32_UINT;
+			vd.format = RD::DATA_FORMAT_R32G32B32A32_SFLOAT;
 			vd.offset = 0;
-			vd.location = RS::ARRAY_BONES;
+			vd.location = RS::ARRAY_WEIGHTS;
 			vd.stride = 0;
 
-			descriptions.write[3] = vd;
-			buffers.write[3] = storage->mesh_get_default_rd_buffer(RasterizerStorageRD::DEFAULT_RD_BUFFER_BONES);
+			descriptions.write[4] = vd;
+			buffers.write[4] = storage->mesh_get_default_rd_buffer(RasterizerStorageRD::DEFAULT_RD_BUFFER_BONES);
 		}
 
 		//check that everything is as it should be
@@ -1796,22 +1822,25 @@ void RasterizerCanvasRD::occluder_polygon_set_shape(RID p_occluder, const Vector
 	ERR_FAIL_COND(!oc);
 
 	Vector<Vector2> lines;
-	int lc = p_points.size() * 2;
 
-	lines.resize(lc - (p_closed ? 0 : 2));
-	{
-		Vector2 *w = lines.ptrw();
-		const Vector2 *r = p_points.ptr();
+	if (p_points.size()) {
+		int lc = p_points.size() * 2;
 
-		int max = lc / 2;
-		if (!p_closed) {
-			max--;
-		}
-		for (int i = 0; i < max; i++) {
-			Vector2 a = r[i];
-			Vector2 b = r[(i + 1) % (lc / 2)];
-			w[i * 2 + 0] = a;
-			w[i * 2 + 1] = b;
+		lines.resize(lc - (p_closed ? 0 : 2));
+		{
+			Vector2 *w = lines.ptrw();
+			const Vector2 *r = p_points.ptr();
+
+			int max = lc / 2;
+			if (!p_closed) {
+				max--;
+			}
+			for (int i = 0; i < max; i++) {
+				Vector2 a = r[i];
+				Vector2 b = r[(i + 1) % (lc / 2)];
+				w[i * 2 + 0] = a;
+				w[i * 2 + 1] = b;
+			}
 		}
 	}
 
@@ -1832,7 +1861,7 @@ void RasterizerCanvasRD::occluder_polygon_set_shape(RID p_occluder, const Vector
 	if (lines.size()) {
 		Vector<uint8_t> geometry;
 		Vector<uint8_t> indices;
-		lc = lines.size();
+		int lc = lines.size();
 
 		geometry.resize(lc * 6 * sizeof(float));
 		indices.resize(lc * 3 * sizeof(uint16_t));
@@ -1902,19 +1931,21 @@ void RasterizerCanvasRD::occluder_polygon_set_shape(RID p_occluder, const Vector
 
 	Vector<int> sdf_indices;
 
-	if (p_closed) {
-		sdf_indices = Geometry2D::triangulate_polygon(p_points);
-		oc->sdf_is_lines = false;
-	} else {
-		int max = p_points.size();
-		sdf_indices.resize(max * 2);
+	if (p_points.size()) {
+		if (p_closed) {
+			sdf_indices = Geometry2D::triangulate_polygon(p_points);
+			oc->sdf_is_lines = false;
+		} else {
+			int max = p_points.size();
+			sdf_indices.resize(max * 2);
 
-		int *iw = sdf_indices.ptrw();
-		for (int i = 0; i < max; i++) {
-			iw[i * 2 + 0] = i;
-			iw[i * 2 + 1] = (i + 1) % max;
+			int *iw = sdf_indices.ptrw();
+			for (int i = 0; i < max; i++) {
+				iw[i * 2 + 0] = i;
+				iw[i * 2 + 1] = (i + 1) % max;
+			}
+			oc->sdf_is_lines = true;
 		}
-		oc->sdf_is_lines = true;
 	}
 
 	if (oc->sdf_index_count != sdf_indices.size() && oc->sdf_point_count != p_points.size() && oc->sdf_vertex_array.is_valid()) {

+ 12 - 0
servers/rendering/rasterizer_rd/rasterizer_scene_high_end_rd.cpp

@@ -2795,6 +2795,12 @@ RasterizerSceneHighEndRD::RasterizerSceneHighEndRD(RasterizerStorageRD *p_storag
 		actions.renames["FOG"] = "custom_fog";
 		actions.renames["RADIANCE"] = "custom_radiance";
 		actions.renames["IRRADIANCE"] = "custom_irradiance";
+		actions.renames["BONE_INDICES"] = "bone_attrib";
+		actions.renames["BONE_WEIGHTS"] = "weight_attrib";
+		actions.renames["CUSTOM0"] = "custom0_attrib";
+		actions.renames["CUSTOM1"] = "custom1_attrib";
+		actions.renames["CUSTOM2"] = "custom2_attrib";
+		actions.renames["CUSTOM3"] = "custom3_attrib";
 
 		//for light
 		actions.renames["VIEW"] = "view";
@@ -2817,6 +2823,12 @@ RasterizerSceneHighEndRD::RasterizerSceneHighEndRD(RasterizerStorageRD *p_storag
 		actions.usage_defines["AO_LIGHT_AFFECT"] = "#define AO_USED\n";
 		actions.usage_defines["UV"] = "#define UV_USED\n";
 		actions.usage_defines["UV2"] = "#define UV2_USED\n";
+		actions.usage_defines["BONE_INDICES"] = "#define BONES_USED\n";
+		actions.usage_defines["BONE_WEIGHTS"] = "#define WEIGHTS_USED\n";
+		actions.usage_defines["CUSTOM0"] = "#define CUSTOM0\n";
+		actions.usage_defines["CUSTOM1"] = "#define CUSTOM1\n";
+		actions.usage_defines["CUSTOM2"] = "#define CUSTOM2\n";
+		actions.usage_defines["CUSTOM3"] = "#define CUSTOM3\n";
 		actions.usage_defines["NORMALMAP"] = "#define NORMALMAP_USED\n";
 		actions.usage_defines["NORMALMAP_DEPTH"] = "@NORMALMAP";
 		actions.usage_defines["COLOR"] = "#define COLOR_USED\n";

+ 5 - 4
servers/rendering/rasterizer_rd/rasterizer_scene_rd.cpp

@@ -5336,18 +5336,19 @@ void RasterizerSceneRD::_render_buffers_post_process_and_tonemap(RID p_render_bu
 			tonemap.exposure = env->exposure;
 		}
 
+		tonemap.use_color_correction = false;
+		tonemap.use_1d_color_correction = false;
+		tonemap.color_correction_texture = storage->texture_rd_get_default(RasterizerStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE);
+
 		if (can_use_effects && env) {
 			tonemap.use_bcs = env->adjustments_enabled;
 			tonemap.brightness = env->adjustments_brightness;
 			tonemap.contrast = env->adjustments_contrast;
 			tonemap.saturation = env->adjustments_saturation;
-			tonemap.use_1d_color_correction = env->use_1d_color_correction;
 			if (env->adjustments_enabled && env->color_correction.is_valid()) {
 				tonemap.use_color_correction = true;
+				tonemap.use_1d_color_correction = env->use_1d_color_correction;
 				tonemap.color_correction_texture = storage->texture_get_rd_texture(env->color_correction);
-			} else {
-				tonemap.use_color_correction = false;
-				tonemap.color_correction_texture = storage->texture_rd_get_default(RasterizerStorageRD::DEFAULT_RD_TEXTURE_WHITE);
 			}
 		}
 

+ 147 - 92
servers/rendering/rasterizer_rd/rasterizer_storage_rd.cpp

@@ -2398,13 +2398,15 @@ void RasterizerStorageRD::mesh_add_surface(RID p_mesh, const RS::SurfaceData &p_
 	ERR_FAIL_COND(!mesh);
 
 	//ensure blend shape consistency
-	ERR_FAIL_COND(mesh->blend_shape_count && p_surface.blend_shapes.size() != (int)mesh->blend_shape_count);
+	ERR_FAIL_COND(mesh->blend_shape_count && p_surface.blend_shape_count != mesh->blend_shape_count);
 	ERR_FAIL_COND(mesh->blend_shape_count && p_surface.bone_aabbs.size() != mesh->bone_aabbs.size());
 
 #ifdef DEBUG_ENABLED
 	//do a validation, to catch errors first
 	{
 		uint32_t stride = 0;
+		uint32_t attrib_stride = 0;
+		uint32_t skin_stride = 0;
 
 		for (int i = 0; i < RS::ARRAY_WEIGHTS; i++) {
 			if ((p_surface.format & (1 << i))) {
@@ -2418,59 +2420,54 @@ void RasterizerStorageRD::mesh_add_surface(RID p_mesh, const RS::SurfaceData &p_
 
 					} break;
 					case RS::ARRAY_NORMAL: {
-						if (p_surface.format & RS::ARRAY_COMPRESS_NORMAL) {
-							stride += sizeof(int8_t) * 4;
-						} else {
-							stride += sizeof(float) * 4;
-						}
+						stride += sizeof(int32_t);
 
 					} break;
 					case RS::ARRAY_TANGENT: {
-						if (p_surface.format & RS::ARRAY_COMPRESS_TANGENT) {
-							stride += sizeof(int8_t) * 4;
-						} else {
-							stride += sizeof(float) * 4;
-						}
+						stride += sizeof(int32_t);
 
 					} break;
 					case RS::ARRAY_COLOR: {
-						if (p_surface.format & RS::ARRAY_COMPRESS_COLOR) {
-							stride += sizeof(int8_t) * 4;
-						} else {
-							stride += sizeof(float) * 4;
-						}
-
+						attrib_stride += sizeof(int16_t) * 4;
 					} break;
 					case RS::ARRAY_TEX_UV: {
-						if (p_surface.format & RS::ARRAY_COMPRESS_TEX_UV) {
-							stride += sizeof(int16_t) * 2;
-						} else {
-							stride += sizeof(float) * 2;
-						}
+						attrib_stride += sizeof(float) * 2;
 
 					} break;
 					case RS::ARRAY_TEX_UV2: {
-						if (p_surface.format & RS::ARRAY_COMPRESS_TEX_UV2) {
-							stride += sizeof(int16_t) * 2;
-						} else {
-							stride += sizeof(float) * 2;
-						}
+						attrib_stride += sizeof(float) * 2;
 
 					} break;
-					case RS::ARRAY_BONES: {
-						//assumed weights too
-
-						//unique format, internally 16 bits, exposed as single array for 32
-
-						stride += sizeof(int32_t) * 4;
+					case RS::ARRAY_CUSTOM0:
+					case RS::ARRAY_CUSTOM1:
+					case RS::ARRAY_CUSTOM2:
+					case RS::ARRAY_CUSTOM3: {
+						int idx = i - RS::ARRAY_CUSTOM0;
+						uint32_t fmt_shift[RS::ARRAY_CUSTOM_COUNT] = { RS::ARRAY_FORMAT_CUSTOM0_SHIFT, RS::ARRAY_FORMAT_CUSTOM1_SHIFT, RS::ARRAY_FORMAT_CUSTOM2_SHIFT, RS::ARRAY_FORMAT_CUSTOM3_SHIFT };
+						uint32_t fmt = (p_surface.format >> fmt_shift[idx]) & RS::ARRAY_FORMAT_CUSTOM_MASK;
+						uint32_t fmtsize[RS::ARRAY_CUSTOM_MAX] = { 4, 4, 4, 8, 4, 8, 12, 16 };
+						attrib_stride += fmtsize[fmt];
 
 					} break;
+					case RS::ARRAY_WEIGHTS:
+					case RS::ARRAY_BONES: {
+						//uses a separate array
+						bool use_8 = p_surface.format & RS::ARRAY_FLAG_USE_8_BONE_WEIGHTS;
+						skin_stride += sizeof(int16_t) * (use_8 ? 8 : 4);
+					} break;
 				}
 			}
 		}
 
 		int expected_size = stride * p_surface.vertex_count;
-		ERR_FAIL_COND_MSG(expected_size != p_surface.vertex_data.size(), "Size of data provided (" + itos(p_surface.vertex_data.size()) + ") does not match expected (" + itos(expected_size) + ")");
+		ERR_FAIL_COND_MSG(expected_size != p_surface.vertex_data.size(), "Size of vertex data provided (" + itos(p_surface.vertex_data.size()) + ") does not match expected (" + itos(expected_size) + ")");
+		int expected_attrib_size = attrib_stride * p_surface.vertex_count;
+		ERR_FAIL_COND_MSG(expected_attrib_size != p_surface.attribute_data.size(), "Size of attribute data provided (" + itos(p_surface.attribute_data.size()) + ") does not match expected (" + itos(expected_attrib_size) + ")");
+
+		if ((p_surface.format & RS::ARRAY_FORMAT_WEIGHTS) && (p_surface.format & RS::ARRAY_FORMAT_BONES)) {
+			expected_size = skin_stride * p_surface.vertex_count;
+			ERR_FAIL_COND_MSG(expected_size != p_surface.skin_data.size(), "Size of skin data provided (" + itos(p_surface.skin_data.size()) + ") does not match expected (" + itos(expected_size) + ")");
+		}
 	}
 
 #endif
@@ -2481,6 +2478,12 @@ void RasterizerStorageRD::mesh_add_surface(RID p_mesh, const RS::SurfaceData &p_
 	s->primitive = p_surface.primitive;
 
 	s->vertex_buffer = RD::get_singleton()->vertex_buffer_create(p_surface.vertex_data.size(), p_surface.vertex_data);
+	if (p_surface.attribute_data.size()) {
+		s->attribute_buffer = RD::get_singleton()->vertex_buffer_create(p_surface.attribute_data.size(), p_surface.attribute_data);
+	}
+	if (p_surface.skin_data.size()) {
+		s->skin_buffer = RD::get_singleton()->vertex_buffer_create(p_surface.skin_data.size(), p_surface.skin_data);
+	}
 	s->vertex_count = p_surface.vertex_count;
 
 	if (p_surface.index_count) {
@@ -2504,7 +2507,7 @@ void RasterizerStorageRD::mesh_add_surface(RID p_mesh, const RS::SurfaceData &p_
 
 	s->aabb = p_surface.aabb;
 	s->bone_aabbs = p_surface.bone_aabbs; //only really useful for returning them.
-
+#if 0
 	for (int i = 0; i < p_surface.blend_shapes.size(); i++) {
 		if (p_surface.blend_shapes[i].size() != p_surface.vertex_data.size()) {
 			memdelete(s);
@@ -2513,8 +2516,8 @@ void RasterizerStorageRD::mesh_add_surface(RID p_mesh, const RS::SurfaceData &p_
 		RID vertex_buffer = RD::get_singleton()->vertex_buffer_create(p_surface.blend_shapes[i].size(), p_surface.blend_shapes[i]);
 		s->blend_shapes.push_back(vertex_buffer);
 	}
-
-	mesh->blend_shape_count = p_surface.blend_shapes.size();
+#endif
+	mesh->blend_shape_count = p_surface.blend_shape_count;
 
 	if (mesh->surface_count == 0) {
 		mesh->bone_aabbs = p_surface.bone_aabbs;
@@ -2596,6 +2599,12 @@ RS::SurfaceData RasterizerStorageRD::mesh_get_surface(RID p_mesh, int p_surface)
 	RS::SurfaceData sd;
 	sd.format = s.format;
 	sd.vertex_data = RD::get_singleton()->buffer_get_data(s.vertex_buffer);
+	if (s.attribute_buffer.is_valid()) {
+		sd.attribute_data = RD::get_singleton()->buffer_get_data(s.attribute_buffer);
+	}
+	if (s.skin_buffer.is_valid()) {
+		sd.skin_data = RD::get_singleton()->buffer_get_data(s.skin_buffer);
+	}
 	sd.vertex_count = s.vertex_count;
 	sd.index_count = s.index_count;
 	sd.primitive = s.primitive;
@@ -2613,9 +2622,8 @@ RS::SurfaceData RasterizerStorageRD::mesh_get_surface(RID p_mesh, int p_surface)
 
 	sd.bone_aabbs = s.bone_aabbs;
 
-	for (int i = 0; i < s.blend_shapes.size(); i++) {
-		Vector<uint8_t> bs = RD::get_singleton()->buffer_get_data(s.blend_shapes[i]);
-		sd.blend_shapes.push_back(bs);
+	if (s.blend_shape_buffer.is_valid()) {
+		sd.blend_shape_data = RD::get_singleton()->buffer_get_data(s.blend_shape_buffer);
 	}
 
 	return sd;
@@ -2750,6 +2758,12 @@ void RasterizerStorageRD::mesh_clear(RID p_mesh) {
 	for (uint32_t i = 0; i < mesh->surface_count; i++) {
 		Mesh::Surface &s = *mesh->surfaces[i];
 		RD::get_singleton()->free(s.vertex_buffer); //clears arrays as dependency automatically, including all versions
+		if (s.attribute_buffer.is_valid()) {
+			RD::get_singleton()->free(s.attribute_buffer);
+		}
+		if (s.skin_buffer.is_valid()) {
+			RD::get_singleton()->free(s.skin_buffer);
+		}
 		if (s.versions) {
 			memfree(s.versions); //reallocs, so free with memfree.
 		}
@@ -2765,12 +2779,8 @@ void RasterizerStorageRD::mesh_clear(RID p_mesh) {
 			memdelete_arr(s.lods);
 		}
 
-		for (int32_t j = 0; j < s.blend_shapes.size(); j++) {
-			RD::get_singleton()->free(s.blend_shapes[j]);
-		}
-
-		if (s.blend_shape_base_buffer.is_valid()) {
-			RD::get_singleton()->free(s.blend_shape_base_buffer);
+		if (s.blend_shape_buffer.is_valid()) {
+			RD::get_singleton()->free(s.blend_shape_buffer);
 		}
 
 		memdelete(mesh->surfaces[i]);
@@ -2796,8 +2806,10 @@ void RasterizerStorageRD::_mesh_surface_generate_version_for_input_mask(Mesh::Su
 	Vector<RID> buffers;
 
 	uint32_t stride = 0;
+	uint32_t attribute_stride = 0;
+	uint32_t skin_stride = 0;
 
-	for (int i = 0; i < RS::ARRAY_WEIGHTS; i++) {
+	for (int i = 0; i < RS::ARRAY_INDEX; i++) {
 		RD::VertexAttribute vd;
 		RID buffer;
 		vd.location = i;
@@ -2805,6 +2817,7 @@ void RasterizerStorageRD::_mesh_surface_generate_version_for_input_mask(Mesh::Su
 		if (!(s->format & (1 << i))) {
 			// Not supplied by surface, use default value
 			buffer = mesh_default_rd_buffers[i];
+			vd.stride = 0;
 			switch (i) {
 				case RS::ARRAY_VERTEX: {
 					vd.format = RD::DATA_FORMAT_R32G32B32_SFLOAT;
@@ -2827,20 +2840,31 @@ void RasterizerStorageRD::_mesh_surface_generate_version_for_input_mask(Mesh::Su
 				case RS::ARRAY_TEX_UV2: {
 					vd.format = RD::DATA_FORMAT_R32G32_SFLOAT;
 				} break;
+				case RS::ARRAY_CUSTOM0:
+				case RS::ARRAY_CUSTOM1:
+				case RS::ARRAY_CUSTOM2:
+				case RS::ARRAY_CUSTOM3: {
+					//assumed weights too
+					vd.format = RD::DATA_FORMAT_R32G32B32A32_SFLOAT;
+				} break;
 				case RS::ARRAY_BONES: {
 					//assumed weights too
 					vd.format = RD::DATA_FORMAT_R32G32B32A32_UINT;
 				} break;
+				case RS::ARRAY_WEIGHTS: {
+					//assumed weights too
+					vd.format = RD::DATA_FORMAT_R32G32B32A32_UINT;
+				} break;
 			}
 		} else {
 			//Supplied, use it
 
-			vd.offset = stride;
-			vd.stride = 1; //mark that it needs a stride set
-			buffer = s->vertex_buffer;
+			vd.stride = 1; //mark that it needs a stride set (default uses 0)
 
 			switch (i) {
 				case RS::ARRAY_VERTEX: {
+					vd.offset = stride;
+
 					if (s->format & RS::ARRAY_FLAG_USE_2D_VERTICES) {
 						vd.format = RD::DATA_FORMAT_R32G32_SFLOAT;
 						stride += sizeof(float) * 2;
@@ -2849,71 +2873,80 @@ void RasterizerStorageRD::_mesh_surface_generate_version_for_input_mask(Mesh::Su
 						stride += sizeof(float) * 3;
 					}
 
+					buffer = s->vertex_buffer;
+
 				} break;
 				case RS::ARRAY_NORMAL: {
-					if (s->format & RS::ARRAY_COMPRESS_NORMAL) {
-						vd.format = RD::DATA_FORMAT_R8G8B8A8_SNORM;
-						stride += sizeof(int8_t) * 4;
-					} else {
-						vd.format = RD::DATA_FORMAT_R32G32B32A32_SFLOAT;
-						stride += sizeof(float) * 4;
-					}
+					vd.offset = stride;
 
+					vd.format = RD::DATA_FORMAT_A2B10G10R10_UNORM_PACK32;
+
+					stride += sizeof(uint32_t);
+					buffer = s->vertex_buffer;
 				} break;
 				case RS::ARRAY_TANGENT: {
-					if (s->format & RS::ARRAY_COMPRESS_TANGENT) {
-						vd.format = RD::DATA_FORMAT_R8G8B8A8_SNORM;
-						stride += sizeof(int8_t) * 4;
-					} else {
-						vd.format = RD::DATA_FORMAT_R32G32B32A32_SFLOAT;
-						stride += sizeof(float) * 4;
-					}
+					vd.offset = stride;
 
+					vd.format = RD::DATA_FORMAT_A2B10G10R10_UNORM_PACK32;
+					stride += sizeof(uint32_t);
+					buffer = s->vertex_buffer;
 				} break;
 				case RS::ARRAY_COLOR: {
-					if (s->format & RS::ARRAY_COMPRESS_COLOR) {
-						vd.format = RD::DATA_FORMAT_R8G8B8A8_UNORM;
-						stride += sizeof(int8_t) * 4;
-					} else {
-						vd.format = RD::DATA_FORMAT_R32G32B32A32_SFLOAT;
-						stride += sizeof(float) * 4;
-					}
+					vd.offset = attribute_stride;
 
+					vd.format = RD::DATA_FORMAT_R16G16B16A16_SFLOAT;
+					attribute_stride += sizeof(int16_t) * 4;
+					buffer = s->attribute_buffer;
 				} break;
 				case RS::ARRAY_TEX_UV: {
-					if (s->format & RS::ARRAY_COMPRESS_TEX_UV) {
-						vd.format = RD::DATA_FORMAT_R16G16_SFLOAT;
-						stride += sizeof(int16_t) * 2;
-					} else {
-						vd.format = RD::DATA_FORMAT_R32G32_SFLOAT;
-						stride += sizeof(float) * 2;
-					}
+					vd.offset = attribute_stride;
+
+					vd.format = RD::DATA_FORMAT_R32G32_SFLOAT;
+					attribute_stride += sizeof(float) * 2;
+					buffer = s->attribute_buffer;
 
 				} break;
 				case RS::ARRAY_TEX_UV2: {
-					if (s->format & RS::ARRAY_COMPRESS_TEX_UV2) {
-						vd.format = RD::DATA_FORMAT_R16G16_SFLOAT;
-						stride += sizeof(int16_t) * 2;
-					} else {
-						vd.format = RD::DATA_FORMAT_R32G32_SFLOAT;
-						stride += sizeof(float) * 2;
-					}
+					vd.offset = attribute_stride;
 
+					vd.format = RD::DATA_FORMAT_R32G32_SFLOAT;
+					attribute_stride += sizeof(float) * 2;
+					buffer = s->attribute_buffer;
+				} break;
+				case RS::ARRAY_CUSTOM0:
+				case RS::ARRAY_CUSTOM1:
+				case RS::ARRAY_CUSTOM2:
+				case RS::ARRAY_CUSTOM3: {
+					vd.offset = attribute_stride;
+
+					int idx = i - RS::ARRAY_CUSTOM0;
+					uint32_t fmt_shift[RS::ARRAY_CUSTOM_COUNT] = { RS::ARRAY_FORMAT_CUSTOM0_SHIFT, RS::ARRAY_FORMAT_CUSTOM1_SHIFT, RS::ARRAY_FORMAT_CUSTOM2_SHIFT, RS::ARRAY_FORMAT_CUSTOM3_SHIFT };
+					uint32_t fmt = (s->format >> fmt_shift[idx]) & RS::ARRAY_FORMAT_CUSTOM_MASK;
+					uint32_t fmtsize[RS::ARRAY_CUSTOM_MAX] = { 4, 4, 4, 8, 4, 8, 12, 16 };
+					RD::DataFormat fmtrd[RS::ARRAY_CUSTOM_MAX] = { RD::DATA_FORMAT_R8G8B8A8_UNORM, RD::DATA_FORMAT_R8G8B8A8_SNORM, RD::DATA_FORMAT_R16G16_SFLOAT, RD::DATA_FORMAT_R16G16B16A16_SFLOAT, RD::DATA_FORMAT_R32_SFLOAT, RD::DATA_FORMAT_R32G32_SFLOAT, RD::DATA_FORMAT_R32G32B32_SFLOAT, RD::DATA_FORMAT_R32G32B32A32_SFLOAT };
+					vd.format = fmtrd[fmt];
+					attribute_stride += fmtsize[fmt];
+					buffer = s->attribute_buffer;
 				} break;
 				case RS::ARRAY_BONES: {
-					//assumed weights too
-
-					//unique format, internally 16 bits, exposed as single array for 32
+					vd.offset = skin_stride;
 
-					vd.format = RD::DATA_FORMAT_R32G32B32A32_UINT;
-					stride += sizeof(int32_t) * 4;
+					vd.format = RD::DATA_FORMAT_R16G16B16A16_UINT;
+					skin_stride += sizeof(int16_t) * 4;
+					buffer = s->skin_buffer;
+				} break;
+				case RS::ARRAY_WEIGHTS: {
+					vd.offset = skin_stride;
 
+					vd.format = RD::DATA_FORMAT_R16G16B16A16_UNORM;
+					skin_stride += sizeof(int16_t) * 4;
+					buffer = s->skin_buffer;
 				} break;
 			}
 		}
 
 		if (!(p_input_mask & (1 << i))) {
-			continue; // Shader does not need this, skip it
+			continue; // Shader does not need this, skip it (but computing stride was important anyway)
 		}
 
 		attributes.push_back(vd);
@@ -2922,8 +2955,17 @@ void RasterizerStorageRD::_mesh_surface_generate_version_for_input_mask(Mesh::Su
 
 	//update final stride
 	for (int i = 0; i < attributes.size(); i++) {
-		if (attributes[i].stride == 1) {
+		if (attributes[i].stride == 0) {
+			continue; //default location
+		}
+		int loc = attributes[i].location;
+
+		if (loc < RS::ARRAY_COLOR) {
 			attributes.write[i].stride = stride;
+		} else if (loc < RS::ARRAY_BONES) {
+			attributes.write[i].stride = attribute_stride;
+		} else {
+			attributes.write[i].stride = skin_stride;
 		}
 	}
 
@@ -8263,6 +8305,19 @@ RasterizerStorageRD::RasterizerStorageRD() {
 			mesh_default_rd_buffers[DEFAULT_RD_BUFFER_TEX_UV2] = RD::get_singleton()->vertex_buffer_create(buffer.size(), buffer);
 		}
 
+		for (int i = 0; i < RS::ARRAY_CUSTOM_COUNT; i++) {
+			buffer.resize(sizeof(float) * 4);
+			{
+				uint8_t *w = buffer.ptrw();
+				float *fptr = (float *)w;
+				fptr[0] = 0.0;
+				fptr[1] = 0.0;
+				fptr[2] = 0.0;
+				fptr[3] = 0.0;
+			}
+			mesh_default_rd_buffers[DEFAULT_RD_BUFFER_CUSTOM0 + i] = RD::get_singleton()->vertex_buffer_create(buffer.size(), buffer);
+		}
+
 		{ //bones
 			buffer.resize(sizeof(uint32_t) * 4);
 			{

+ 7 - 2
servers/rendering/rasterizer_rd/rasterizer_storage_rd.h

@@ -170,6 +170,10 @@ public:
 		DEFAULT_RD_BUFFER_COLOR,
 		DEFAULT_RD_BUFFER_TEX_UV,
 		DEFAULT_RD_BUFFER_TEX_UV2,
+		DEFAULT_RD_BUFFER_CUSTOM0,
+		DEFAULT_RD_BUFFER_CUSTOM1,
+		DEFAULT_RD_BUFFER_CUSTOM2,
+		DEFAULT_RD_BUFFER_CUSTOM3,
 		DEFAULT_RD_BUFFER_BONES,
 		DEFAULT_RD_BUFFER_WEIGHTS,
 		DEFAULT_RD_BUFFER_MAX,
@@ -378,6 +382,8 @@ private:
 			uint32_t format = 0;
 
 			RID vertex_buffer;
+			RID attribute_buffer;
+			RID skin_buffer;
 			uint32_t vertex_count = 0;
 
 			// A different pipeline needs to be allocated
@@ -414,8 +420,7 @@ private:
 
 			Vector<AABB> bone_aabbs;
 
-			Vector<RID> blend_shapes;
-			RID blend_shape_base_buffer; //source buffer goes here when using blend shapes, and main one is uncompressed
+			RID blend_shape_buffer;
 
 			RID material;
 

+ 5 - 2
servers/rendering/rasterizer_rd/shaders/canvas.glsl

@@ -9,7 +9,8 @@ layout(location = 0) in vec2 vertex_attrib;
 layout(location = 3) in vec4 color_attrib;
 layout(location = 4) in vec2 uv_attrib;
 
-layout(location = 6) in uvec4 bones_attrib;
+layout(location = 10) in uvec4 bone_attrib;
+layout(location = 11) in vec4 weight_attrib;
 
 #endif
 
@@ -61,6 +62,7 @@ void main() {
 		color = vec4(unpackHalf2x16(draw_data.colors[4]), unpackHalf2x16(draw_data.colors[5]));
 	}
 	uvec4 bones = uvec4(0, 0, 0, 0);
+	vec4 bone_weights = vec4(0.0);
 
 #elif defined(USE_ATTRIBUTES)
 
@@ -68,7 +70,8 @@ void main() {
 	vec4 color = color_attrib;
 	vec2 uv = uv_attrib;
 
-	uvec4 bones = bones_attrib;
+	uvec4 bones = bone_attrib;
+	vec4 bone_weights = weight_attrib;
 #else
 
 	vec2 vertex_base_arr[4] = vec2[](vec2(0.0, 0.0), vec2(0.0, 1.0), vec2(1.0, 1.0), vec2(1.0, 0.0));

+ 28 - 5
servers/rendering/rasterizer_rd/shaders/scene_high_end.glsl

@@ -24,7 +24,29 @@ layout(location = 4) in vec2 uv_attrib;
 layout(location = 5) in vec2 uv2_attrib;
 #endif
 
-layout(location = 6) in uvec4 bone_attrib; // always bound, even if unused
+#if defined(CUSTOM0_USED)
+layout(location = 6) in vec4 custom0_attrib;
+#endif
+
+#if defined(CUSTOM1_USED)
+layout(location = 7) in vec4 custom1_attrib;
+#endif
+
+#if defined(CUSTOM2_USED)
+layout(location = 8) in vec4 custom2_attrib;
+#endif
+
+#if defined(CUSTOM3_USED)
+layout(location = 9) in vec4 custom3_attrib;
+#endif
+
+#if defined(BONES_USED)
+layout(location = 10) in uvec4 bone_attrib;
+#endif
+
+#if defined(WEIGHTS_USED)
+layout(location = 11) in vec4 weight_attrib;
+#endif
 
 /* Varyings */
 
@@ -116,14 +138,15 @@ void main() {
 	}
 
 	vec3 vertex = vertex_attrib;
-	vec3 normal = normal_attrib;
+	vec3 normal = normal_attrib * 2.0 - 1.0;
 
 #if defined(TANGENT_USED) || defined(NORMALMAP_USED) || defined(LIGHT_ANISOTROPY_USED)
-	vec3 tangent = tangent_attrib.xyz;
-	float binormalf = tangent_attrib.a;
+	vec3 tangent = tangent_attrib.xyz * 2.0 - 1.0;
+	float binormalf = tangent_attrib.a * 2.0 - 1.0;
 	vec3 binormal = normalize(cross(normal, tangent) * binormalf);
 #endif
 
+#if 0
 	if (bool(instances.data[instance_index].flags & INSTANCE_FLAGS_SKELETON)) {
 		//multimesh, instances are for it
 
@@ -147,7 +170,7 @@ void main() {
 		binormal = (vec4(binormal, 0.0) * m).xyz;
 #endif
 	}
-
+#endif
 	uv_interp = uv_attrib;
 
 #if defined(UV2_USED) || defined(USE_LIGHTMAP)

+ 6 - 0
servers/rendering/shader_types.cpp

@@ -67,6 +67,12 @@ ShaderTypes::ShaderTypes() {
 	shader_modes[RS::SHADER_SPATIAL].functions["vertex"].built_ins["INSTANCE_ID"] = constt(ShaderLanguage::TYPE_INT);
 	shader_modes[RS::SHADER_SPATIAL].functions["vertex"].built_ins["INSTANCE_CUSTOM"] = constt(ShaderLanguage::TYPE_VEC4);
 	shader_modes[RS::SHADER_SPATIAL].functions["vertex"].built_ins["ROUGHNESS"] = ShaderLanguage::TYPE_FLOAT;
+	shader_modes[RS::SHADER_SPATIAL].functions["vertex"].built_ins["BONE_INDICES"] = ShaderLanguage::TYPE_UVEC4;
+	shader_modes[RS::SHADER_SPATIAL].functions["vertex"].built_ins["BONE_WEIGHTS"] = ShaderLanguage::TYPE_VEC4;
+	shader_modes[RS::SHADER_SPATIAL].functions["vertex"].built_ins["CUSTOM0"] = ShaderLanguage::TYPE_VEC4;
+	shader_modes[RS::SHADER_SPATIAL].functions["vertex"].built_ins["CUSTOM1"] = ShaderLanguage::TYPE_VEC4;
+	shader_modes[RS::SHADER_SPATIAL].functions["vertex"].built_ins["CUSTOM2"] = ShaderLanguage::TYPE_VEC4;
+	shader_modes[RS::SHADER_SPATIAL].functions["vertex"].built_ins["CUSTOM3"] = ShaderLanguage::TYPE_VEC4;
 	shader_modes[RS::SHADER_SPATIAL].functions["vertex"].can_discard = false;
 
 	//builtins

File diff suppressed because it is too large
+ 324 - 425
servers/rendering_server.cpp


+ 64 - 29
servers/rendering_server.h

@@ -52,7 +52,7 @@ class RenderingServer : public Object {
 
 	void _camera_set_orthogonal(RID p_camera, float p_size, float p_z_near, float p_z_far);
 	void _canvas_item_add_style_box(RID p_item, const Rect2 &p_rect, const Rect2 &p_source, RID p_texture, const Vector<float> &p_margins, const Color &p_modulate = Color(1, 1, 1));
-	Array _get_array_from_surface(uint32_t p_format, Vector<uint8_t> p_vertex_data, int p_vertex_len, Vector<uint8_t> p_index_data, int p_index_len) const;
+	Array _get_array_from_surface(uint32_t p_format, Vector<uint8_t> p_vertex_data, Vector<uint8_t> p_attrib_data, Vector<uint8_t> p_skin_data, int p_vertex_len, Vector<uint8_t> p_index_data, int p_index_len) const;
 
 protected:
 	RID _make_test_cube();
@@ -61,7 +61,7 @@ protected:
 	RID white_texture;
 	RID test_material;
 
-	Error _surface_set_data(Array p_arrays, uint32_t p_format, uint32_t *p_offsets, uint32_t p_stride, Vector<uint8_t> &r_vertex_array, int p_vertex_array_len, Vector<uint8_t> &r_index_array, int p_index_array_len, AABB &r_aabb, Vector<AABB> &r_bone_aabb);
+	Error _surface_set_data(Array p_arrays, uint32_t p_format, uint32_t *p_offsets, uint32_t p_vertex_stride, uint32_t p_attrib_stride, uint32_t p_skin_stride, Vector<uint8_t> &r_vertex_array, Vector<uint8_t> &r_attrib_array, Vector<uint8_t> &r_skin_array, int p_vertex_array_len, Vector<uint8_t> &r_index_array, int p_index_array_len, AABB &r_aabb, Vector<AABB> &r_bone_aabb);
 
 	static RenderingServer *(*create_func)();
 	static void _bind_methods();
@@ -199,16 +199,36 @@ public:
 	/* MESH API */
 
 	enum ArrayType {
-		ARRAY_VERTEX = 0,
-		ARRAY_NORMAL = 1,
-		ARRAY_TANGENT = 2,
-		ARRAY_COLOR = 3,
-		ARRAY_TEX_UV = 4,
-		ARRAY_TEX_UV2 = 5,
-		ARRAY_BONES = 6,
-		ARRAY_WEIGHTS = 7,
-		ARRAY_INDEX = 8,
-		ARRAY_MAX = 9
+		ARRAY_VERTEX = 0, // RG32F or RGB32F (depending on 2D bit)
+		ARRAY_NORMAL = 1, // A2B10G10R10
+		ARRAY_TANGENT = 2, // A2B10G10R10, A flips sign of binormal
+		ARRAY_COLOR = 3, // RGBA16F
+		ARRAY_TEX_UV = 4, // RG32F
+		ARRAY_TEX_UV2 = 5, // RG32F
+		ARRAY_CUSTOM0 = 6, // depends on ArrayCustomFormat
+		ARRAY_CUSTOM1 = 7,
+		ARRAY_CUSTOM2 = 8,
+		ARRAY_CUSTOM3 = 9,
+		ARRAY_BONES = 10, // RGBA16UI (x2 if 8 weights)
+		ARRAY_WEIGHTS = 11, // RGBA16UNORM (x2 if 8 weights)
+		ARRAY_INDEX = 12, // 16 or 32 bits depending on length > 0xFFFF
+		ARRAY_MAX = 13
+	};
+
+	enum {
+		ARRAY_CUSTOM_COUNT = ARRAY_BONES - ARRAY_CUSTOM0
+	};
+
+	enum ArrayCustomFormat {
+		ARRAY_CUSTOM_RGBA8_UNORM,
+		ARRAY_CUSTOM_RGBA8_SNORM,
+		ARRAY_CUSTOM_RG_HALF,
+		ARRAY_CUSTOM_RGBA_HALF,
+		ARRAY_CUSTOM_R_FLOAT,
+		ARRAY_CUSTOM_RG_FLOAT,
+		ARRAY_CUSTOM_RGB_FLOAT,
+		ARRAY_CUSTOM_RGBA_FLOAT,
+		ARRAY_CUSTOM_MAX
 	};
 
 	enum ArrayFormat {
@@ -219,21 +239,29 @@ public:
 		ARRAY_FORMAT_COLOR = 1 << ARRAY_COLOR,
 		ARRAY_FORMAT_TEX_UV = 1 << ARRAY_TEX_UV,
 		ARRAY_FORMAT_TEX_UV2 = 1 << ARRAY_TEX_UV2,
+		ARRAY_FORMAT_CUSTOM0 = 1 << ARRAY_CUSTOM0,
+		ARRAY_FORMAT_CUSTOM1 = 1 << ARRAY_CUSTOM1,
+		ARRAY_FORMAT_CUSTOM2 = 1 << ARRAY_CUSTOM2,
+		ARRAY_FORMAT_CUSTOM3 = 1 << ARRAY_CUSTOM3,
 		ARRAY_FORMAT_BONES = 1 << ARRAY_BONES,
 		ARRAY_FORMAT_WEIGHTS = 1 << ARRAY_WEIGHTS,
 		ARRAY_FORMAT_INDEX = 1 << ARRAY_INDEX,
 
-		ARRAY_COMPRESS_BASE = (ARRAY_INDEX + 1),
-		ARRAY_COMPRESS_NORMAL = 1 << (ARRAY_NORMAL + ARRAY_COMPRESS_BASE),
-		ARRAY_COMPRESS_TANGENT = 1 << (ARRAY_TANGENT + ARRAY_COMPRESS_BASE),
-		ARRAY_COMPRESS_COLOR = 1 << (ARRAY_COLOR + ARRAY_COMPRESS_BASE),
-		ARRAY_COMPRESS_TEX_UV = 1 << (ARRAY_TEX_UV + ARRAY_COMPRESS_BASE),
-		ARRAY_COMPRESS_TEX_UV2 = 1 << (ARRAY_TEX_UV2 + ARRAY_COMPRESS_BASE),
-		ARRAY_COMPRESS_INDEX = 1 << (ARRAY_INDEX + ARRAY_COMPRESS_BASE),
-		ARRAY_COMPRESS_DEFAULT = ARRAY_COMPRESS_NORMAL | ARRAY_COMPRESS_TANGENT | ARRAY_COMPRESS_COLOR | ARRAY_COMPRESS_TEX_UV | ARRAY_COMPRESS_TEX_UV2,
+		ARRAY_FORMAT_BLEND_SHAPE_MASK = ~(ARRAY_FORMAT_COLOR | ARRAY_FORMAT_TEX_UV | ARRAY_FORMAT_TEX_UV2 | ARRAY_FORMAT_BONES | ARRAY_FORMAT_WEIGHTS | ARRAY_FORMAT_CUSTOM0 | ARRAY_FORMAT_CUSTOM1 | ARRAY_FORMAT_CUSTOM2 | ARRAY_FORMAT_CUSTOM3 | ARRAY_FORMAT_INDEX),
 
-		ARRAY_FLAG_USE_2D_VERTICES = ARRAY_COMPRESS_INDEX << 1,
-		ARRAY_FLAG_USE_DYNAMIC_UPDATE = ARRAY_COMPRESS_INDEX << 3,
+		ARRAY_FORMAT_CUSTOM_BASE = (ARRAY_INDEX + 1),
+		ARRAY_FORMAT_CUSTOM_BITS = 3,
+		ARRAY_FORMAT_CUSTOM0_SHIFT = (ARRAY_FORMAT_CUSTOM_BASE + 0),
+		ARRAY_FORMAT_CUSTOM1_SHIFT = (ARRAY_FORMAT_CUSTOM_BASE + ARRAY_FORMAT_CUSTOM_BITS),
+		ARRAY_FORMAT_CUSTOM2_SHIFT = (ARRAY_FORMAT_CUSTOM_BASE + ARRAY_FORMAT_CUSTOM_BITS * 2),
+		ARRAY_FORMAT_CUSTOM3_SHIFT = (ARRAY_FORMAT_CUSTOM_BASE + ARRAY_FORMAT_CUSTOM_BITS * 3),
+
+		ARRAY_FORMAT_CUSTOM_MASK = 0x7,
+		ARRAY_COMPRESS_FLAGS_BASE = (ARRAY_INDEX + 1 + 12),
+
+		ARRAY_FLAG_USE_2D_VERTICES = 1 << (ARRAY_COMPRESS_FLAGS_BASE + 0),
+		ARRAY_FLAG_USE_DYNAMIC_UPDATE = 1 << (ARRAY_COMPRESS_FLAGS_BASE + 1),
+		ARRAY_FLAG_USE_8_BONE_WEIGHTS = 1 << (ARRAY_COMPRESS_FLAGS_BASE + 2),
 	};
 
 	enum PrimitiveType {
@@ -249,11 +277,15 @@ public:
 		PrimitiveType primitive = PRIMITIVE_MAX;
 
 		uint32_t format = 0;
-		Vector<uint8_t> vertex_data;
+		Vector<uint8_t> vertex_data; // vertex, normal, tangent (change with skinning, blendshape)
+		Vector<uint8_t> attribute_data; // color,uv, uv2, custom0-3
+		Vector<uint8_t> skin_data; // bone index, bone weight
 		uint32_t vertex_count = 0;
 		Vector<uint8_t> index_data;
 		uint32_t index_count = 0;
 
+		uint32_t blend_shape_count = 0;
+
 		AABB aabb;
 		struct LOD {
 			float edge_length;
@@ -262,7 +294,7 @@ public:
 		Vector<LOD> lods;
 		Vector<AABB> bone_aabbs;
 
-		Vector<Vector<uint8_t>> blend_shapes;
+		Vector<uint8_t> blend_shape_data;
 
 		RID material;
 	};
@@ -270,17 +302,20 @@ public:
 	virtual RID mesh_create_from_surfaces(const Vector<SurfaceData> &p_surfaces) = 0;
 	virtual RID mesh_create() = 0;
 
-	virtual uint32_t mesh_surface_get_format_offset(uint32_t p_format, int p_vertex_len, int p_index_len, int p_array_index) const;
-	virtual uint32_t mesh_surface_get_format_stride(uint32_t p_format, int p_vertex_len, int p_index_len) const;
+	virtual uint32_t mesh_surface_get_format_offset(uint32_t p_format, int p_vertex_len, int p_array_index) const;
+	virtual uint32_t mesh_surface_get_format_vertex_stride(uint32_t p_format, int p_vertex_len) const;
+	virtual uint32_t mesh_surface_get_format_attribute_stride(uint32_t p_format, int p_vertex_len) const;
+	virtual uint32_t mesh_surface_get_format_skin_stride(uint32_t p_format, int p_vertex_len) const;
+
 	/// Returns stride
-	virtual uint32_t mesh_surface_make_offsets_from_format(uint32_t p_format, int p_vertex_len, int p_index_len, uint32_t *r_offsets) const;
-	virtual Error mesh_create_surface_data_from_arrays(SurfaceData *r_surface_data, PrimitiveType p_primitive, const Array &p_arrays, const Array &p_blend_shapes = Array(), const Dictionary &p_lods = Dictionary(), uint32_t p_compress_format = ARRAY_COMPRESS_DEFAULT);
+	virtual void mesh_surface_make_offsets_from_format(uint32_t p_format, int p_vertex_len, int p_index_len, uint32_t *r_offsets, uint32_t &r_vertex_element_size, uint32_t &r_attrib_element_size, uint32_t &r_skin_element_size) const;
+	virtual Error mesh_create_surface_data_from_arrays(SurfaceData *r_surface_data, PrimitiveType p_primitive, const Array &p_arrays, const Array &p_blend_shapes = Array(), const Dictionary &p_lods = Dictionary(), uint32_t p_compress_format = 0);
 	Array mesh_create_arrays_from_surface_data(const SurfaceData &p_data) const;
 	Array mesh_surface_get_arrays(RID p_mesh, int p_surface) const;
 	Array mesh_surface_get_blend_shape_arrays(RID p_mesh, int p_surface) const;
 	Dictionary mesh_surface_get_lods(RID p_mesh, int p_surface) const;
 
-	virtual void mesh_add_surface_from_arrays(RID p_mesh, PrimitiveType p_primitive, const Array &p_arrays, const Array &p_blend_shapes = Array(), const Dictionary &p_lods = Dictionary(), uint32_t p_compress_format = ARRAY_COMPRESS_DEFAULT);
+	virtual void mesh_add_surface_from_arrays(RID p_mesh, PrimitiveType p_primitive, const Array &p_arrays, const Array &p_blend_shapes = Array(), const Dictionary &p_lods = Dictionary(), uint32_t p_compress_format = 0);
 	virtual void mesh_add_surface(RID p_mesh, const SurfaceData &p_surface) = 0;
 
 	virtual int mesh_get_blend_shape_count(RID p_mesh) const = 0;

Some files were not shown because too many files changed in this diff