fixed usage macros for custom vertex attributes

custom vertex attributes seem to never have been used before so this went unnoticed.

fixed usage macros for custom vertex attributes

it seems like custom vertex attributes have never been used before so this went unnoticed

custom vertex attribute fixes

fixes involve resizing the array before attempting to write in it.
fixing to signs that are used to calculate the shift value.
added a way to recognize valid custom attribute formats. although the only used one will be ARRAY_CUSTOM_RGBA_FLOAT

adding functions to MeshDataTool to alter custom vertex attributes

i have added the functions to MeshDataTool and the vertex attribute arrays in the Vertex struct after fixing rednering_server.cpp.

implemented functions to MeshDataTool to alter custom vertex attributes

i have implemented the functions that i added to mesh_data_tool.h and added the bindings for them
i have also modified the commit_to_surface and create_from_surface.
parts of the renderer is made to work with other formats while parts are made to work with ARRAY_CUSTOM_RGBA_FLOAT only due to the fact that vec4 will be loaded to the vertex shader.
note : custom data is accessible via CUSTOM0, CUSTOM1, CUSTOM2 and CUSTOM3 in the vertex shader. the type is vec4.
Color is used as an array of 4 floating point numbers.

fixed the documentation file with --doctool.

added explanations in the documentation.
This commit is contained in:
darth negative hunter 2021-08-29 12:58:09 +04:30 committed by hina nibblet
parent 4d08a737fb
commit 6871ace4ad
7 changed files with 881 additions and 13 deletions

View file

@ -73,6 +73,13 @@
Requires [Mesh] with primitive type [constant Mesh.PRIMITIVE_TRIANGLES].
</description>
</method>
<method name="get_custom_type" qualifiers="const">
<return type="int" />
<argument index="0" name="custom_idx" type="int" />
<description>
Returns the type of the custom attribute(selected by [code]custom_idx[/code]). returns [code]-1[/code] if type for the custom attribute is not set or [code]custom_idx[/code] is invalid. [code]custom_idx[/code] can range from 0 to 3.
</description>
</method>
<method name="get_edge_count" qualifiers="const">
<return type="int" />
<description>
@ -180,6 +187,42 @@
Returns the total number of vertices in [Mesh].
</description>
</method>
<method name="get_vertex_custom_float" qualifiers="const">
<return type="Color" />
<argument index="0" name="idx" type="int" />
<argument index="1" name="custom_idx" type="int" />
<description>
Returns the floating point representation of the custom attribute(specified by [code]custom_idx[/code]) of the given vertex (specified by [code]idx[/code]). [code]custom_idx[/code] can range from 0 to 3.
</description>
</method>
<method name="get_vertex_custom_hfloat" qualifiers="const">
<return type="PackedByteArray" />
<argument index="0" name="idx" type="int" />
<argument index="1" name="custom_idx" type="int" />
<description>
Returns the half-floating point representation of the custom attribute(specified by [code]custom_idx[/code]) of the given vertex (specified by [code]idx[/code]). [code]custom_idx[/code] can range from 0 to 3.
The returned data will be an array of 4 16-bit floating points that are represented by the bit layout below :
S : 1-bit sign | E : 5-bit exponent | M : 10-bit mantissa.
</description>
</method>
<method name="get_vertex_custom_snorm8_32i" qualifiers="const">
<return type="PackedInt32Array" />
<argument index="0" name="idx" type="int" />
<argument index="1" name="custom_idx" type="int" />
<description>
Returns the SNORM representation of the custom attribute(specified by [code]custom_idx[/code]) of the given vertex (specified by [code]idx[/code]). [code]custom_idx[/code] can range from 0 to 3.
The returned data will be an array of 4 32-bit signed integeres. a clamped shader input of -1.0 to 1.0 will be mapped to -127 to 127.
</description>
</method>
<method name="get_vertex_custom_unorm8" qualifiers="const">
<return type="PackedByteArray" />
<argument index="0" name="idx" type="int" />
<argument index="1" name="custom_idx" type="int" />
<description>
Returns the SNORM representation of the custom attribute specified by [code]custom_idx[/code] of the given vertex by [code]idx[/code]. [code]custom_idx[/code] can range from 0 to 3.
The returned data will be an array of 4 8-bit unsigned integeres. a clamped shader input of 0.0 to 1.0 will be mapped to 0 to 255.
</description>
</method>
<method name="get_vertex_edges" qualifiers="const">
<return type="PackedInt32Array" />
<argument index="0" name="idx" type="int" />
@ -236,6 +279,36 @@
Returns bone weights of the given vertex.
</description>
</method>
<method name="has_custom" qualifiers="const">
<return type="int" />
<argument index="0" name="custom_idx" type="int" />
<description>
Returns [code]true[/code] if the corresponding custom attribute(selected by [code]custom_idx[/code]) already has a specified format. returns false otherwise.
</description>
</method>
<method name="set_custom_type">
<return type="int" enum="Error" />
<argument index="0" name="custom_idx" type="int" />
<argument index="1" name="type" type="int" enum="Mesh.ArrayCustomFormat" />
<argument index="2" name="convert" type="bool" default="false" />
<argument index="3" name="has_custom" type="bool" default="true" />
<description>
Removes the corresponding custom attribute(selected by [code]custom_index) or set's it's format. [code]custom_idx[/code] can range from 0 to 3.
If [code]convert[/code] is set to [code]true[/code] and the corresponding custom attribute already has a specified format, the old data will be converted to the new type.
If [code]has_format[/code] is set to [code]false[/code] then the corresponding custom attribute will be removed.
When the custom attribute's type is set. it can be accessed via the vertex shader's [code]CUSTOM0[/code]-[code]CUSTOM3[/code] built in variables :
[codeblocks]
[gdscript]
mdt.create_from_surface(mesh, 0)
mdt.set_custom_type(0,Mesh.ARRAY_CUSTOM_RGBA_HALF) # set type of CUSTOM0 to 4x 16-bit floating points.
for i in range(mdt.get_vertex_count()):
Color value = mdt.get_vertex_custom_float(i, 0) # get the 32-bit floating point representation.
Color.r = Color.r*0.5 # modify the value that was equal to CUSTOM0.x
mdt.set_vertex_custom_float(j, 0, value) # set the value of CUSTOM0. the actual data remains as 4x 16-bit floating points.
[/gdscript]
[/codeblocks]
</description>
</method>
<method name="set_edge_meta">
<return type="void" />
<argument index="0" name="idx" type="int" />
@ -283,6 +356,53 @@
Sets the color of the given vertex.
</description>
</method>
<method name="set_vertex_custom_float">
<return type="int" enum="Error" />
<argument index="0" name="idx" type="int" />
<argument index="1" name="custom_idx" type="int" />
<argument index="2" name="customf" type="Color" />
<description>
Sets the 32-bit floating point representation of the custom attribute(specified by [code]custom_idx[/code]) of the given vertex (specified by [code]idx[/code]). [code]custom_idx[/code] can range from 0 to 3.
If the corresponding custom format is not already set, it will be set to [code]ARRAY_CUSTOM_RGBA_FLOAT[/code].
</description>
</method>
<method name="set_vertex_custom_hfloat">
<return type="int" enum="Error" />
<argument index="0" name="idx" type="int" />
<argument index="1" name="custom_idx" type="int" />
<argument index="2" name="customu" type="PackedByteArray" />
<description>
Sets the 16-bit floating point representation of the custom attribute(specified by [code]custom_idx[/code]) of the given vertex (specified by [code]idx[/code]). [code]custom_idx[/code] can range from 0 to 3.
The input array should be a array of up to 4 16-bit floating point values. if the count exceeds the capacity of the corresponding custom format, extra values will be ignored.
If the corresponding custom format is not already set, it will be set to [code]ARRAY_CUSTOM_RGBA_HFLOAT[/code].
The 16-bit floating point bit layout is as below :
S : 1-bit sign | E : 5-bit exponent | M : 10-bit mantissa.
</description>
</method>
<method name="set_vertex_custom_snorm8_32i">
<return type="int" enum="Error" />
<argument index="0" name="idx" type="int" />
<argument index="1" name="custom_idx" type="int" />
<argument index="2" name="customf" type="PackedInt32Array" />
<description>
Sets the SNORM floating point representation of the custom attribute(specified by [code]custom_idx[/code]) of the given vertex (specified by [code]idx[/code]). [code]custom_idx[/code] can range from 0 to 3.
The input array should be a array of up to 4 32-bit Integer values. if the count exceeds the capacity of the corresponding custom format, extra values will be ignored.
If the corresponding custom format is not already set, it will be set to [code]ARRAY_CUSTOM_RGBA8_SNORM[/code].
Clamped input values of -127 to 127 will be mapped to -1.0 to 1.0 in the shader input.
</description>
</method>
<method name="set_vertex_custom_unorm8">
<return type="int" enum="Error" />
<argument index="0" name="idx" type="int" />
<argument index="1" name="custom_idx" type="int" />
<argument index="2" name="customu" type="PackedByteArray" />
<description>
Sets the UNORM floating point representation of the custom attribute(specified by [code]custom_idx[/code]) of the given vertex (specified by [code]idx[/code]). [code]custom_idx[/code] can range from 0 to 3.
The input array should be a array of up to 4 8-bit Integer values. if the count exceeds the capacity of the corresponding custom format, extra values will be ignored.
If the corresponding custom format is not already set, it will be set to [code]ARRAY_CUSTOM_RGBA8_UNORM[/code].
Clamped input values of 0 to 255 will be mapped to -1.0 to 1.0 in the shader input.
</description>
</method>
<method name="set_vertex_meta">
<return type="void" />
<argument index="0" name="idx" type="int" />

View file

@ -75,6 +75,10 @@ public:
};
enum {
ARRAY_CUSTOM_COUNT = RenderingServer::ARRAY_CUSTOM_COUNT
};
enum ArrayCustomFormat {
ARRAY_CUSTOM_RGBA8_UNORM,
ARRAY_CUSTOM_RGBA8_SNORM,
@ -105,6 +109,7 @@ public:
ARRAY_FORMAT_BLEND_SHAPE_MASK = RS::ARRAY_FORMAT_BLEND_SHAPE_MASK,
ARRAY_FORMAT_CUSTOM_BASE = RS::ARRAY_FORMAT_CUSTOM_BASE,
ARRAY_FORMAT_CUSTOM_BITS = RS::ARRAY_FORMAT_CUSTOM_BITS,
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,

View file

@ -42,6 +42,8 @@ Error MeshDataTool::create_from_surface(const Ref<ArrayMesh> &p_mesh, int p_surf
ERR_FAIL_COND_V(p_mesh.is_null(), ERR_INVALID_PARAMETER);
ERR_FAIL_COND_V(p_mesh->surface_get_primitive_type(p_surface) != Mesh::PRIMITIVE_TRIANGLES, ERR_INVALID_PARAMETER);
uint32_t custom_fmt_byte_size[RS::ARRAY_CUSTOM_MAX] = { 4, 4, 4, 8, 4, 8, 12, 16 };
Array arrays = p_mesh->surface_get_arrays(p_surface);
ERR_FAIL_COND_V(arrays.is_empty(), ERR_INVALID_PARAMETER);
@ -112,6 +114,20 @@ Error MeshDataTool::create_from_surface(const Ref<ArrayMesh> &p_mesh, int p_surf
we = arrays[Mesh::ARRAY_WEIGHTS].operator Vector<float>().ptr();
}
const uint8_t *cu[Mesh::ARRAY_CUSTOM_COUNT] = {};
uint32_t custom_type_byte_sizes[Mesh::ARRAY_CUSTOM_COUNT] = {};
for (uint32_t i = 0; i < Mesh::ARRAY_CUSTOM_COUNT; ++i) {
uint32_t arrType = arrays[Mesh::ARRAY_CUSTOM0 + i].get_type();
if (arrType == Variant::PACKED_FLOAT32_ARRAY) {
cu[i] = (const uint8_t *)arrays[Mesh::ARRAY_CUSTOM0 + i].operator Vector<float>().ptr();
} else if (arrType == Variant::PACKED_BYTE_ARRAY) {
cu[i] = arrays[Mesh::ARRAY_CUSTOM0 + i].operator Vector<uint8_t>().ptr();
}
uint32_t type = (format >> (Mesh::ARRAY_FORMAT_CUSTOM_BASE + i * Mesh::ARRAY_FORMAT_CUSTOM_BITS)) & Mesh::ARRAY_FORMAT_CUSTOM_MASK;
custom_type_byte_sizes[i] = custom_fmt_byte_size[type];
}
vertices.resize(vcount);
for (int i = 0; i < vcount; i++) {
@ -147,6 +163,12 @@ Error MeshDataTool::create_from_surface(const Ref<ArrayMesh> &p_mesh, int p_surf
v.bones.push_back(bo[i * 4 + 3]);
}
for (uint32_t j = 0; j < Mesh::ARRAY_CUSTOM_COUNT; ++j) {
if (cu[j]) {
memcpy(&v.custom[j], &(cu[j][i * custom_type_byte_sizes[j]]), custom_type_byte_sizes[j]);
}
}
vertices.write[i] = v;
}
@ -195,6 +217,9 @@ Error MeshDataTool::commit_to_surface(const Ref<ArrayMesh> &p_mesh) {
Array arr;
arr.resize(Mesh::ARRAY_MAX);
uint32_t custom_fmt_size[RS::ARRAY_CUSTOM_MAX] = { 4, 4, 4, 8, 1, 2, 3, 4 };
uint32_t custom_fmt_byte_size[RS::ARRAY_CUSTOM_MAX] = { 4, 4, 4, 8, 4, 8, 12, 16 };
int vcount = vertices.size();
Vector<Vector3> v;
@ -206,8 +231,29 @@ Error MeshDataTool::commit_to_surface(const Ref<ArrayMesh> &p_mesh) {
Vector<int> b;
Vector<real_t> w;
Vector<int> in;
Vector<float> cuf[Mesh::ARRAY_CUSTOM_COUNT];
Vector<uint8_t> cuu[Mesh::ARRAY_CUSTOM_COUNT];
{
uint8_t *cu_ptr[Mesh::ARRAY_CUSTOM_COUNT] = {};
uint32_t custom_type_byte_sizes[Mesh::ARRAY_CUSTOM_COUNT] = {};
for (uint32_t i = 0; i < Mesh::ARRAY_CUSTOM_COUNT; ++i) {
uint32_t type = (format >> (Mesh::ARRAY_FORMAT_CUSTOM_BASE + i * Mesh::ARRAY_FORMAT_CUSTOM_BITS)) & Mesh::ARRAY_FORMAT_CUSTOM_MASK;
custom_type_byte_sizes[i] = custom_fmt_byte_size[type];
if (format & (Mesh::ARRAY_FORMAT_CUSTOM0 << i)) {
if (type > Mesh::ARRAY_CUSTOM_RGBA_HALF) {
// floating point type
cuf[i].resize(vcount * custom_fmt_size[type]);
cu_ptr[i] = (uint8_t *)cuf[i].ptrw();
} else {
// non floating point type
cuu[i].resize(vcount * custom_fmt_size[type]);
cu_ptr[i] = (uint8_t *)cuu[i].ptrw();
}
}
}
v.resize(vcount);
Vector3 *vr = v.ptrw();
@ -289,6 +335,12 @@ Error MeshDataTool::commit_to_surface(const Ref<ArrayMesh> &p_mesh) {
bo[i * 4 + 2] = vtx.bones[2];
bo[i * 4 + 3] = vtx.bones[3];
}
for (uint32_t j = 0; j < Mesh::ARRAY_CUSTOM_COUNT; ++j) {
if (cu_ptr[j]) {
memcpy(cu_ptr[j] + i * custom_type_byte_sizes[j], &vtx.custom[j], custom_type_byte_sizes[j]);
}
}
}
int fc = faces.size();
@ -324,10 +376,17 @@ Error MeshDataTool::commit_to_surface(const Ref<ArrayMesh> &p_mesh) {
if (w.size()) {
arr[Mesh::ARRAY_WEIGHTS] = w;
}
for (uint32_t i = 0; i < Mesh::ARRAY_CUSTOM_COUNT; ++i) {
if (cuf[i].size()) {
arr[Mesh::ARRAY_CUSTOM0 + i] = cuf[i];
} else if (cuu[i].size()) {
arr[Mesh::ARRAY_CUSTOM0 + i] = cuu[i];
}
}
Ref<ArrayMesh> ncmesh = p_mesh;
int sc = ncmesh->get_surface_count();
ncmesh->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES, arr);
ncmesh->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES, arr, Array(), Dictionary(), format);
ncmesh->surface_set_material(sc, material);
return OK;
@ -446,6 +505,178 @@ void MeshDataTool::set_vertex_meta(int p_idx, const Variant &p_meta) {
vertices.write[p_idx].meta = p_meta;
}
Color MeshDataTool::get_vertex_custom_float(int p_idx, int p_custom_idx) const {
ERR_FAIL_INDEX_V(p_idx, vertices.size(), Color());
ERR_FAIL_INDEX_V(p_custom_idx, Mesh::ARRAY_CUSTOM_COUNT, Color());
uint32_t from_type = (format >> (Mesh::ARRAY_FORMAT_CUSTOM_BASE + p_custom_idx * Mesh::ARRAY_FORMAT_CUSTOM_BITS)) & Mesh::ARRAY_FORMAT_CUSTOM_MASK;
uint32_t to_type = Mesh::ARRAY_CUSTOM_RGBA_FLOAT;
return _convert_custom_data(vertices[p_idx].custom[p_custom_idx], from_type, to_type);
}
PackedByteArray MeshDataTool::get_vertex_custom_hfloat(int p_idx, int p_custom_idx) const {
Vector<uint8_t> ret;
ret.resize(8);
ERR_FAIL_INDEX_V(p_idx, vertices.size(), (memset(ret.ptrw(), 0, 8), ret));
ERR_FAIL_INDEX_V(p_custom_idx, Mesh::ARRAY_CUSTOM_COUNT, (memset(ret.ptrw(), 0, 8), ret));
uint32_t from_type = (format >> (Mesh::ARRAY_FORMAT_CUSTOM_BASE + p_custom_idx * Mesh::ARRAY_FORMAT_CUSTOM_BITS)) & Mesh::ARRAY_FORMAT_CUSTOM_MASK;
uint32_t to_type = Mesh::ARRAY_CUSTOM_RGBA_HALF;
Color c = _convert_custom_data(vertices[p_idx].custom[p_custom_idx], from_type, to_type);
memcpy(ret.ptrw(), &c, 8);
return ret;
}
PackedByteArray MeshDataTool::get_vertex_custom_unorm8(int p_idx, int p_custom_idx) const {
Vector<uint8_t> ret;
ret.resize(4);
ERR_FAIL_INDEX_V(p_idx, vertices.size(), (memset(ret.ptrw(), 0, 4), ret));
ERR_FAIL_INDEX_V(p_custom_idx, Mesh::ARRAY_CUSTOM_COUNT, (memset(ret.ptrw(), 0, 4), ret));
uint32_t from_type = (format >> (Mesh::ARRAY_FORMAT_CUSTOM_BASE + p_custom_idx * Mesh::ARRAY_FORMAT_CUSTOM_BITS)) & Mesh::ARRAY_FORMAT_CUSTOM_MASK;
uint32_t to_type = Mesh::ARRAY_CUSTOM_RGBA8_UNORM;
Color c = _convert_custom_data(vertices[p_idx].custom[p_custom_idx], from_type, to_type);
memcpy(ret.ptrw(), &c, 4);
return ret;
}
PackedInt32Array MeshDataTool::get_vertex_custom_snorm8_32i(int p_idx, int p_custom_idx) const {
Vector<int32_t> ret;
ret.resize(4);
ERR_FAIL_INDEX_V(p_idx, vertices.size(), (memset(ret.ptrw(), 0, 4 * sizeof(int32_t)), ret));
ERR_FAIL_INDEX_V(p_custom_idx, Mesh::ARRAY_CUSTOM_COUNT, (memset(ret.ptrw(), 0, 4 * sizeof(int32_t)), ret));
uint32_t from_type = (format >> (Mesh::ARRAY_FORMAT_CUSTOM_BASE + p_custom_idx * Mesh::ARRAY_FORMAT_CUSTOM_BITS)) & Mesh::ARRAY_FORMAT_CUSTOM_MASK;
uint32_t to_type = Mesh::ARRAY_CUSTOM_RGBA8_SNORM;
Color c = _convert_custom_data(vertices[p_idx].custom[p_custom_idx], from_type, to_type);
for (int i = 0; i < 4; ++i) {
ret.write[i] = ((uint8_t *)&c)[i];
}
return ret;
}
Error MeshDataTool::set_vertex_custom_float(int p_idx, int p_custom_idx, const Color &p_customf) {
ERR_FAIL_INDEX_V(p_idx, vertices.size(), ERR_INVALID_PARAMETER);
ERR_FAIL_INDEX_V(p_custom_idx, Mesh::ARRAY_CUSTOM_COUNT, ERR_INVALID_PARAMETER);
Color in(p_customf);
if (format & (Mesh::ARRAY_FORMAT_CUSTOM0 << p_custom_idx)) {
uint32_t type = (format >> (Mesh::ARRAY_FORMAT_CUSTOM_BASE + p_custom_idx * Mesh::ARRAY_FORMAT_CUSTOM_BITS)) & Mesh::ARRAY_FORMAT_CUSTOM_MASK;
vertices.write[p_idx].custom[p_custom_idx] = _convert_custom_data(in, Mesh::ARRAY_CUSTOM_RGBA_FLOAT, type);
} else {
// default behaviour setting the format to rgba_float
format |= Mesh::ARRAY_FORMAT_CUSTOM0 << p_custom_idx;
format &= ~(Mesh::ARRAY_FORMAT_CUSTOM_BITS << (Mesh::ARRAY_FORMAT_CUSTOM_BASE + p_custom_idx * Mesh::ARRAY_FORMAT_CUSTOM_BITS));
format |= Mesh::ARRAY_CUSTOM_RGBA_FLOAT << (Mesh::ARRAY_FORMAT_CUSTOM_BASE + p_custom_idx * Mesh::ARRAY_FORMAT_CUSTOM_BITS);
vertices.write[p_idx].custom[p_custom_idx] = in;
}
return OK;
}
Error MeshDataTool::set_vertex_custom_hfloat(int p_idx, int p_custom_idx, const PackedByteArray &p_customu) {
ERR_FAIL_INDEX_V(p_idx, vertices.size(), ERR_INVALID_PARAMETER);
ERR_FAIL_INDEX_V(p_custom_idx, Mesh::ARRAY_CUSTOM_COUNT, ERR_INVALID_PARAMETER);
uint32_t count = MIN(p_customu.size(), 8);
Color in(Color(0, 0, 0, 0));
memcpy(&in, p_customu.ptr(), count);
if (format & (Mesh::ARRAY_FORMAT_CUSTOM0 << p_custom_idx)) {
uint32_t type = (format >> (Mesh::ARRAY_FORMAT_CUSTOM_BASE + p_custom_idx * Mesh::ARRAY_FORMAT_CUSTOM_BITS)) & Mesh::ARRAY_FORMAT_CUSTOM_MASK;
vertices.write[p_idx].custom[p_custom_idx] = _convert_custom_data(in, Mesh::ARRAY_CUSTOM_RGBA_HALF, type);
} else {
// default behaviour setting the format to rgba_hfloat
format |= Mesh::ARRAY_FORMAT_CUSTOM0 << p_custom_idx;
format &= ~(Mesh::ARRAY_FORMAT_CUSTOM_BITS << (Mesh::ARRAY_FORMAT_CUSTOM_BASE + p_custom_idx * Mesh::ARRAY_FORMAT_CUSTOM_BITS));
format |= Mesh::ARRAY_CUSTOM_RGBA_HALF << (Mesh::ARRAY_FORMAT_CUSTOM_BASE + p_custom_idx * Mesh::ARRAY_FORMAT_CUSTOM_BITS);
vertices.write[p_idx].custom[p_custom_idx] = in;
}
return OK;
}
Error MeshDataTool::set_vertex_custom_unorm8(int p_idx, int p_custom_idx, const PackedByteArray &p_customu) {
ERR_FAIL_INDEX_V(p_idx, vertices.size(), ERR_INVALID_PARAMETER);
ERR_FAIL_INDEX_V(p_custom_idx, Mesh::ARRAY_CUSTOM_COUNT, ERR_INVALID_PARAMETER);
uint32_t count = MIN(p_customu.size(), 4);
Color in(Color(0, 0, 0, 0));
memcpy(&in, p_customu.ptr(), count);
if (format & (Mesh::ARRAY_FORMAT_CUSTOM0 << p_custom_idx)) {
uint32_t type = (format >> (Mesh::ARRAY_FORMAT_CUSTOM_BASE + p_custom_idx * Mesh::ARRAY_FORMAT_CUSTOM_BITS)) & Mesh::ARRAY_FORMAT_CUSTOM_MASK;
vertices.write[p_idx].custom[p_custom_idx] = _convert_custom_data(in, Mesh::ARRAY_CUSTOM_RGBA8_UNORM, type);
} else {
// default behaviour setting the format to rgba_hfloat
format |= Mesh::ARRAY_FORMAT_CUSTOM0 << p_custom_idx;
format &= ~(Mesh::ARRAY_FORMAT_CUSTOM_BITS << (Mesh::ARRAY_FORMAT_CUSTOM_BASE + p_custom_idx * Mesh::ARRAY_FORMAT_CUSTOM_BITS));
format |= Mesh::ARRAY_CUSTOM_RGBA8_UNORM << (Mesh::ARRAY_FORMAT_CUSTOM_BASE + p_custom_idx * Mesh::ARRAY_FORMAT_CUSTOM_BITS);
vertices.write[p_idx].custom[p_custom_idx] = in;
}
return OK;
}
Error MeshDataTool::set_vertex_custom_snorm8_32i(int p_idx, int p_custom_idx, const PackedInt32Array &p_customu) {
ERR_FAIL_INDEX_V(p_idx, vertices.size(), ERR_INVALID_PARAMETER);
ERR_FAIL_INDEX_V(p_custom_idx, Mesh::ARRAY_CUSTOM_COUNT, ERR_INVALID_PARAMETER);
uint32_t count = MIN(p_customu.size(), 4);
Color in(Color(0, 0, 0, 0));
for (uint32_t i = 0; i < count; ++i) {
((uint8_t *)&in)[i] = CLAMP(p_customu[i], -127, 127);
}
if (format & (Mesh::ARRAY_FORMAT_CUSTOM0 << p_custom_idx)) {
uint32_t type = (format >> (Mesh::ARRAY_FORMAT_CUSTOM_BASE + p_custom_idx * Mesh::ARRAY_FORMAT_CUSTOM_BITS)) & Mesh::ARRAY_FORMAT_CUSTOM_MASK;
vertices.write[p_idx].custom[p_custom_idx] = _convert_custom_data(in, Mesh::ARRAY_CUSTOM_RGBA8_SNORM, type);
} else {
// default behaviour setting the format to rgba_hfloat
format |= Mesh::ARRAY_FORMAT_CUSTOM0 << p_custom_idx;
format &= ~(Mesh::ARRAY_FORMAT_CUSTOM_BITS << (Mesh::ARRAY_FORMAT_CUSTOM_BASE + p_custom_idx * Mesh::ARRAY_FORMAT_CUSTOM_BITS));
format |= Mesh::ARRAY_CUSTOM_RGBA8_SNORM << (Mesh::ARRAY_FORMAT_CUSTOM_BASE + p_custom_idx * Mesh::ARRAY_FORMAT_CUSTOM_BITS);
vertices.write[p_idx].custom[p_custom_idx] = in;
}
return OK;
}
int MeshDataTool::has_custom(int p_custom_idx) const {
ERR_FAIL_INDEX_V(p_custom_idx, Mesh::ARRAY_CUSTOM_COUNT, 0);
if (format & (Mesh::ARRAY_FORMAT_CUSTOM0 << p_custom_idx)) {
return 1;
} else {
return 0;
}
}
int MeshDataTool::get_custom_type(int p_custom_idx) const {
ERR_FAIL_INDEX_V(p_custom_idx, Mesh::ARRAY_CUSTOM_COUNT, -1);
ERR_FAIL_COND_V((format & (Mesh::ARRAY_FORMAT_CUSTOM0 << p_custom_idx)) == 0, -1);
uint32_t type = (format >> (Mesh::ARRAY_FORMAT_CUSTOM_BASE + p_custom_idx * Mesh::ARRAY_FORMAT_CUSTOM_BITS)) & Mesh::ARRAY_FORMAT_CUSTOM_MASK;
return (Mesh::ArrayCustomFormat)type;
}
Error MeshDataTool::set_custom_type(int p_custom_idx, Mesh::ArrayCustomFormat p_type, bool p_convert, bool has_custom) {
ERR_FAIL_INDEX_V(p_custom_idx, Mesh::ARRAY_CUSTOM_COUNT, ERR_INVALID_PARAMETER);
ERR_FAIL_COND_V(p_type >= Mesh::ARRAY_CUSTOM_MAX, ERR_INVALID_PARAMETER);
if (has_custom) {
if (format & (Mesh::ARRAY_FORMAT_CUSTOM0 << p_custom_idx)) {
uint32_t prev_type = (format >> (Mesh::ARRAY_FORMAT_CUSTOM_BASE + p_custom_idx * Mesh::ARRAY_FORMAT_CUSTOM_BITS)) & Mesh::ARRAY_FORMAT_CUSTOM_MASK;
if (prev_type != p_type) {
format &= ~(Mesh::ARRAY_FORMAT_CUSTOM_MASK << (Mesh::ARRAY_FORMAT_CUSTOM_BASE + p_custom_idx * Mesh::ARRAY_FORMAT_CUSTOM_BITS));
if (p_convert) {
_convert_custom_data_n(vertices.ptrw(), p_custom_idx, vertices.size(), prev_type, p_type);
}
}
}
format |= Mesh::ARRAY_FORMAT_CUSTOM0 << p_custom_idx;
format &= ~(Mesh::ARRAY_FORMAT_CUSTOM_BITS << (Mesh::ARRAY_FORMAT_CUSTOM_BASE + p_custom_idx * Mesh::ARRAY_FORMAT_CUSTOM_BITS));
format |= p_type << (Mesh::ARRAY_FORMAT_CUSTOM_BASE + p_custom_idx * Mesh::ARRAY_FORMAT_CUSTOM_BITS);
} else {
// remove custom type.
format &= ~(Mesh::ARRAY_FORMAT_CUSTOM0 << p_custom_idx);
format &= ~(Mesh::ARRAY_FORMAT_CUSTOM_BITS << (Mesh::ARRAY_FORMAT_CUSTOM_BASE + p_custom_idx * Mesh::ARRAY_FORMAT_CUSTOM_BITS));
}
return OK;
}
Vector<int> MeshDataTool::get_vertex_edges(int p_idx) const {
ERR_FAIL_INDEX_V(p_idx, vertices.size(), Vector<int>());
return vertices[p_idx].edges;
@ -554,6 +785,20 @@ void MeshDataTool::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_vertex_meta", "idx", "meta"), &MeshDataTool::set_vertex_meta);
ClassDB::bind_method(D_METHOD("get_vertex_meta", "idx"), &MeshDataTool::get_vertex_meta);
ClassDB::bind_method(D_METHOD("set_vertex_custom_float", "idx", "custom_idx", "customf"), &MeshDataTool::set_vertex_custom_float);
ClassDB::bind_method(D_METHOD("set_vertex_custom_hfloat", "idx", "custom_idx", "customu"), &MeshDataTool::set_vertex_custom_hfloat);
ClassDB::bind_method(D_METHOD("set_vertex_custom_unorm8", "idx", "custom_idx", "customu"), &MeshDataTool::set_vertex_custom_unorm8);
ClassDB::bind_method(D_METHOD("set_vertex_custom_snorm8_32i", "idx", "custom_idx", "customf"), &MeshDataTool::set_vertex_custom_snorm8_32i);
ClassDB::bind_method(D_METHOD("get_vertex_custom_float", "idx", "custom_idx"), &MeshDataTool::get_vertex_custom_float);
ClassDB::bind_method(D_METHOD("get_vertex_custom_hfloat", "idx", "custom_idx"), &MeshDataTool::get_vertex_custom_hfloat);
ClassDB::bind_method(D_METHOD("get_vertex_custom_unorm8", "idx", "custom_idx"), &MeshDataTool::get_vertex_custom_unorm8);
ClassDB::bind_method(D_METHOD("get_vertex_custom_snorm8_32i", "idx", "custom_idx"), &MeshDataTool::get_vertex_custom_snorm8_32i);
ClassDB::bind_method(D_METHOD("has_custom", "custom_idx"), &MeshDataTool::has_custom);
ClassDB::bind_method(D_METHOD("get_custom_type", "custom_idx"), &MeshDataTool::get_custom_type);
ClassDB::bind_method(D_METHOD("set_custom_type", "custom_idx", "type", "convert", "has_custom"), &MeshDataTool::set_custom_type, DEFVAL(false), DEFVAL(true));
ClassDB::bind_method(D_METHOD("get_vertex_edges", "idx"), &MeshDataTool::get_vertex_edges);
ClassDB::bind_method(D_METHOD("get_vertex_faces", "idx"), &MeshDataTool::get_vertex_faces);
@ -575,6 +820,476 @@ void MeshDataTool::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_material"), &MeshDataTool::get_material);
}
Error MeshDataTool::_convert_custom_data_n(MeshDataTool::Vertex *p_data, uint32_t p_custom_idx, uint32_t n, uint32_t p_from_type, uint32_t p_to_type) {
// signed normalized conversions are based on : https://www.khronos.org/registry/DataFormat/specs/1.3/dataformat.1.3.html
// [-127, 127] will be mapped to [-1.0, 1.0]
// unsigned normalized conversions are based on : https://www.khronos.org/registry/DataFormat/specs/1.3/dataformat.1.3.html
// [0, 255] will be mapped to [0.0, 1.0]
if (p_from_type == p_to_type) {
return OK;
}
switch (p_from_type) {
case Mesh::ARRAY_CUSTOM_RGBA8_UNORM: {
// 4x [0,255] 8-bit numbers.
switch (p_to_type) {
case Mesh::ARRAY_CUSTOM_RGBA8_SNORM: {
// 4x [-127,127] 8-bit numbers.
for (size_t i = 0; i < n; ++i) {
Color &dstc = p_data[i].custom[p_custom_idx];
const Color srcc = p_data[i].custom[p_custom_idx];
for (uint32_t j = 0; j < 4; ++j) {
((uint8_t *)&dstc)[j] = (float)((uint8_t *)&srcc)[j] * (127 / 255);
}
}
return OK;
} break;
case Mesh::ARRAY_CUSTOM_RG_HALF:
// 2x 16-bit floating point numbers
case Mesh::ARRAY_CUSTOM_RGBA_HALF: {
// 4x 16-bit floating point numbers.
const uint32_t ct = (p_to_type - Mesh::ARRAY_CUSTOM_RG_HALF + 1) * 2;
for (uint32_t i = 0; i < n; ++i) {
Color &dstc = p_data[i].custom[p_custom_idx];
const Color srcc = p_data[i].custom[p_custom_idx];
uint16_t *wptr = (uint16_t *)&dstc;
for (uint32_t j = 0; j < ct; ++j) {
float value = (float)((uint8_t *)&srcc)[j] / 255;
// converting to half floating point
wptr[j] = Math::make_half_float(value);
}
}
} break;
case Mesh::ARRAY_CUSTOM_R_FLOAT:
case Mesh::ARRAY_CUSTOM_RG_FLOAT:
case Mesh::ARRAY_CUSTOM_RGB_FLOAT:
case Mesh::ARRAY_CUSTOM_RGBA_FLOAT: {
// 4x 32-bit floating point numbers.
const uint32_t ct = p_to_type - Mesh::ARRAY_CUSTOM_R_FLOAT + 1;
for (uint32_t i = 0; i < n; ++i) {
Color &dstc = p_data[i].custom[p_custom_idx];
const Color srcc = p_data[i].custom[p_custom_idx];
for (uint32_t j = 0; j < ct; ++j) {
dstc.components[j] = (float)((uint8_t *)&srcc)[j] / 255;
}
}
} break;
default: {
ERR_FAIL_V(ERR_INVALID_PARAMETER);
} break;
}
} break;
case Mesh::ARRAY_CUSTOM_RGBA8_SNORM: {
// 4x [-127,127] 8-bit numbers.
switch (p_to_type) {
case Mesh::ARRAY_CUSTOM_RGBA8_UNORM: {
// 4x [0, 255] 8-bit numbers.
for (size_t i = 0; i < n; ++i) {
Color &dstc = p_data[i].custom[p_custom_idx];
const Color srcc = p_data[i].custom[p_custom_idx];
for (uint32_t j = 0; j < 4; ++j) {
int8_t value = (int8_t)((uint8_t *)&srcc)[j];
((uint8_t *)&dstc)[j] = (float)(CLAMP(value, 0, 127)) * (255 / 127);
}
}
return OK;
} break;
case Mesh::ARRAY_CUSTOM_RG_HALF:
// 2x 16-bit floating point numbers.
case Mesh::ARRAY_CUSTOM_RGBA_HALF: {
// 4x 16-bit floating point numbers.
const uint32_t ct = (p_to_type - Mesh::ARRAY_CUSTOM_RG_HALF + 1) * 2;
for (uint32_t i = 0; i < n; ++i) {
Color &dstc = p_data[i].custom[p_custom_idx];
const Color srcc = p_data[i].custom[p_custom_idx];
uint16_t *wptr = (uint16_t *)&dstc;
for (uint32_t j = 0; j < ct; ++j) {
float value = (float)((uint8_t *)&srcc)[j] / 127;
value = value >= -1.0f ? value : -1.0f;
// converting to half floating point
wptr[j] = Math::make_half_float(value);
}
}
} break;
case Mesh::ARRAY_CUSTOM_R_FLOAT:
case Mesh::ARRAY_CUSTOM_RG_FLOAT:
case Mesh::ARRAY_CUSTOM_RGB_FLOAT:
case Mesh::ARRAY_CUSTOM_RGBA_FLOAT: {
// 4x 32-bit floating point numbers.
const uint32_t ct = p_to_type - Mesh::ARRAY_CUSTOM_R_FLOAT + 1;
for (uint32_t i = 0; i < n; ++i) {
Color &dstc = p_data[i].custom[p_custom_idx];
const Color srcc = p_data[i].custom[p_custom_idx];
for (uint32_t j = 0; j < ct; ++j) {
float value = (float)((uint8_t *)&srcc)[j] / 127;
dstc.components[j] = value >= -1.0f ? value : -1.0f;
}
}
} break;
default: {
ERR_FAIL_V(ERR_INVALID_PARAMETER);
} break;
}
} break;
case Mesh::ARRAY_CUSTOM_RG_HALF:
// 2x 16-bit floating point numbers.
case Mesh::ARRAY_CUSTOM_RGBA_HALF: {
// 4x 16-bit floating point numbers.
const uint32_t cf = (p_from_type - Mesh::ARRAY_CUSTOM_RG_HALF + 1) * 2;
switch (p_to_type) {
case Mesh::ARRAY_CUSTOM_RGBA8_UNORM: {
for (uint32_t i = 0; i < n; ++i) {
Color &dstc = p_data[i].custom[p_custom_idx];
uint16_t rptr[8];
Color *srccptr = (Color *)rptr; // Pointer used to silence wrong -Wmaybe-initialized.
*srccptr = p_data[i].custom[p_custom_idx];
// 4x [0, 255] 8-bit numbers.
for (uint32_t j = 0; j < cf; ++j) {
float value = Math::half_to_float(rptr[j]);
// converting to 32-bit floating point.
value = CLAMP(value, 0.0f, 1.0f);
((uint8_t *)&dstc)[j] = value * 255;
}
}
} break;
case Mesh::ARRAY_CUSTOM_RGBA8_SNORM: {
// 4x [-127,127] 8-bit numbers.
for (uint32_t i = 0; i < n; ++i) {
Color &dstc = p_data[i].custom[p_custom_idx];
uint16_t rptr[8];
Color *srccptr = (Color *)rptr; // Pointer used to silence wrong -Wmaybe-initialized.
*srccptr = p_data[i].custom[p_custom_idx];
for (uint32_t j = 0; j < cf; ++j) {
float value = Math::half_to_float(rptr[j]);
// converting to 32-bit floating point.
value = CLAMP(value, -1.0f, 1.0f);
((uint8_t *)&dstc)[j] = value * 127;
}
}
} break;
case Mesh::ARRAY_CUSTOM_RG_HALF: {
// 2x 16-bit floating point numbers.
// do nothing
return OK;
} break;
case Mesh::ARRAY_CUSTOM_RGBA_HALF: {
for (uint32_t i = 0; i < n; ++i) {
Color &dstc = p_data[i].custom[p_custom_idx];
uint16_t *wptr = (uint16_t *)&dstc;
for (uint32_t j = 2; j < 4; ++j) {
wptr[j] = 0;
}
}
return OK;
} break;
case Mesh::ARRAY_CUSTOM_R_FLOAT:
case Mesh::ARRAY_CUSTOM_RG_FLOAT:
case Mesh::ARRAY_CUSTOM_RGB_FLOAT:
case Mesh::ARRAY_CUSTOM_RGBA_FLOAT: {
// 4x 32-bit floating point numbers.
const uint32_t ct = p_to_type - Mesh::ARRAY_CUSTOM_R_FLOAT + 1;
const uint32_t c = MIN(cf, ct);
for (uint32_t i = 0; i < n; ++i) {
Color &dstc = p_data[i].custom[p_custom_idx];
uint16_t rptr[8];
Color *srccptr = (Color *)rptr; // Pointer used to silence wrong -Wmaybe-initialized.
*srccptr = p_data[i].custom[p_custom_idx];
for (uint32_t j = 0; j < c; ++j) {
// converting to 32-bit floating point.
dstc.components[j] = Math::half_to_float(rptr[j]);
}
for (uint32_t j = c; j < ct; ++j) {
dstc.components[j] = 0.0f;
}
}
} break;
default: {
ERR_FAIL_V(ERR_INVALID_PARAMETER);
} break;
}
} break;
case Mesh::ARRAY_CUSTOM_R_FLOAT:
// 1x 32-bit floating point numbers.
case Mesh::ARRAY_CUSTOM_RG_FLOAT:
// 2x 32-bit floating point numbers.
case Mesh::ARRAY_CUSTOM_RGB_FLOAT:
// 3x 32-bit floating point numbers.
case Mesh::ARRAY_CUSTOM_RGBA_FLOAT: {
// 4x 32-bit floating point numbers.
const uint32_t cf = p_from_type - Mesh::ARRAY_CUSTOM_R_FLOAT + 1;
switch (p_to_type) {
case Mesh::ARRAY_CUSTOM_RGBA8_UNORM: {
// 4x [0, 255] 8-bit numbers.
for (uint32_t i = 0; i < n; ++i) {
Color &dstc = p_data[i].custom[p_custom_idx];
const Color srcc = p_data[i].custom[p_custom_idx];
for (uint32_t j = 0; j < cf; ++j) {
float value = CLAMP(srcc.components[j], 0.0f, 1.0f);
((uint8_t *)&dstc)[j] = value * 255;
}
for (uint32_t j = cf; j < 4; ++j) {
((uint8_t *)&dstc)[j] = 0;
}
}
} break;
case Mesh::ARRAY_CUSTOM_RGBA8_SNORM: {
// 4x [-127,127] 8-bit numbers.
for (uint32_t i = 0; i < n; ++i) {
Color &dstc = p_data[i].custom[p_custom_idx];
const Color srcc = p_data[i].custom[p_custom_idx];
for (uint32_t j = 0; j < cf; ++j) {
float value = CLAMP(srcc.components[j], -1.0f, 1.0f);
((uint8_t *)&dstc)[j] = value * 127;
}
for (uint32_t j = cf; j < 4; ++j) {
((uint8_t *)&dstc)[j] = 0;
}
}
} break;
case Mesh::ARRAY_CUSTOM_RG_HALF:
// 2x 16-bit floating point numbers.
case Mesh::ARRAY_CUSTOM_RGBA_HALF: {
// 4x 16-bit floating point numbers.
const uint32_t ct = (p_to_type - Mesh::ARRAY_CUSTOM_RGBA_HALF + 1) * 2;
const uint32_t c = MIN(cf, ct);
for (uint32_t i = 0; i < n; ++i) {
Color &dstc = p_data[i].custom[p_custom_idx];
const Color srcc = p_data[i].custom[p_custom_idx];
uint16_t *wptr = (uint16_t *)&dstc;
for (uint32_t j = 0; j < c; ++j) {
// converting to 16-bit floating point.
wptr[j] = Math::make_half_float(srcc.components[j]);
}
for (uint32_t j = c; j < ct; ++j) {
dstc.components[j] = 0.0f;
}
}
} break;
case Mesh::ARRAY_CUSTOM_R_FLOAT:
case Mesh::ARRAY_CUSTOM_RG_FLOAT:
case Mesh::ARRAY_CUSTOM_RGB_FLOAT:
case Mesh::ARRAY_CUSTOM_RGBA_FLOAT: {
const uint32_t ct = (p_to_type - Mesh::ARRAY_CUSTOM_R_FLOAT + 1);
for (uint32_t i = 0; i < n; ++i) {
Color &dstc = p_data[i].custom[p_custom_idx];
for (uint32_t j = cf; j < ct; ++j) {
dstc.components[j] = 0.0f;
}
}
return OK;
}
default: {
ERR_FAIL_V(ERR_INVALID_PARAMETER);
} break;
}
} break;
default: {
ERR_FAIL_V(ERR_INVALID_PARAMETER);
} break;
}
return OK;
}
Color MeshDataTool::_convert_custom_data(const Color &srcc, uint32_t p_from_type, uint32_t p_to_type) {
// signed normalized conversions are based on : https://www.khronos.org/registry/DataFormat/specs/1.3/dataformat.1.3.html
// [-127, 127] will be mapped to [-1.0, 1.0]
// unsigned normalized conversions are based on : https://www.khronos.org/registry/DataFormat/specs/1.3/dataformat.1.3.html
// [0, 255] will be mapped to [0.0, 1.0]
if (p_from_type == p_to_type) {
return srcc;
}
Color dstc(Color(0, 0, 0, 0));
switch (p_from_type) {
case Mesh::ARRAY_CUSTOM_RGBA8_UNORM: {
// 4x [0,255] 8-bit numbers.
switch (p_to_type) {
case Mesh::ARRAY_CUSTOM_RGBA8_SNORM: {
// 4x [-127,127] 8-bit numbers.
for (uint32_t j = 0; j < 4; ++j) {
((uint8_t *)&dstc)[j] = CLAMP(((uint8_t *)&srcc)[j], 0, 127);
}
} break;
case Mesh::ARRAY_CUSTOM_RG_HALF:
// 2x 16-bit floating point numbers
case Mesh::ARRAY_CUSTOM_RGBA_HALF: {
// 4x 16-bit floating point numbers.
const uint32_t ct = (p_to_type - Mesh::ARRAY_CUSTOM_RG_HALF + 1) * 2;
uint16_t *wptr = (uint16_t *)&dstc;
for (uint32_t j = 0; j < ct; ++j) {
float value = (float)((uint8_t *)&srcc)[j] / 255;
// converting to half floating point
wptr[j] = Math::make_half_float(value);
}
} break;
case Mesh::ARRAY_CUSTOM_R_FLOAT:
case Mesh::ARRAY_CUSTOM_RG_FLOAT:
case Mesh::ARRAY_CUSTOM_RGB_FLOAT:
case Mesh::ARRAY_CUSTOM_RGBA_FLOAT: {
// 4x 32-bit floating point numbers.
const uint32_t ct = p_to_type - Mesh::ARRAY_CUSTOM_R_FLOAT + 1;
for (uint32_t j = 0; j < ct; ++j) {
dstc.components[j] = (float)((uint8_t *)&srcc)[j] / 255;
}
} break;
default: {
ERR_FAIL_V(Color(Color(0, 0, 0, 0)));
} break;
}
} break;
case Mesh::ARRAY_CUSTOM_RGBA8_SNORM: {
// 4x [-127,127] 8-bit numbers.
switch (p_to_type) {
case Mesh::ARRAY_CUSTOM_RGBA8_UNORM: {
// 4x [0, 255] 8-bit numbers.
for (uint32_t j = 0; j < 4; ++j) {
int8_t value = (int8_t)((uint8_t *)&srcc)[j];
((uint8_t *)&dstc)[j] = (float)(CLAMP(value, 0, 127)) * (255 / 127);
}
} break;
case Mesh::ARRAY_CUSTOM_RG_HALF:
// 2x 16-bit floating point numbers.
case Mesh::ARRAY_CUSTOM_RGBA_HALF: {
// 4x 16-bit floating point numbers.
const uint32_t ct = (p_to_type - Mesh::ARRAY_CUSTOM_RG_HALF + 1) * 2;
uint16_t *wptr = (uint16_t *)&dstc;
for (uint32_t j = 0; j < ct; ++j) {
float value = (float)((uint8_t *)&srcc)[j] / 127;
value = value >= -1.0f ? value : -1.0f;
// converting to half floating point
wptr[j] = Math::make_half_float(value);
}
} break;
case Mesh::ARRAY_CUSTOM_R_FLOAT:
case Mesh::ARRAY_CUSTOM_RG_FLOAT:
case Mesh::ARRAY_CUSTOM_RGB_FLOAT:
case Mesh::ARRAY_CUSTOM_RGBA_FLOAT: {
// 4x 32-bit floating point numbers.
const uint32_t ct = p_to_type - Mesh::ARRAY_CUSTOM_R_FLOAT + 1;
for (uint32_t j = 0; j < ct; ++j) {
float value = (float)((uint8_t *)&srcc)[j] / 127;
dstc.components[j] = value >= -1.0f ? value : -1.0f;
}
} break;
default: {
ERR_FAIL_V(Color(Color(0, 0, 0, 0)));
} break;
}
} break;
case Mesh::ARRAY_CUSTOM_RG_HALF:
// 2x 16-bit floating point numbers.
case Mesh::ARRAY_CUSTOM_RGBA_HALF: {
// 4x 16-bit floating point numbers.
const uint32_t cf = (p_from_type - Mesh::ARRAY_CUSTOM_RG_HALF + 1) * 2;
switch (p_to_type) {
case Mesh::ARRAY_CUSTOM_RGBA8_UNORM: {
const uint16_t *rptr = (const uint16_t *)&srcc;
// 4x [0, 255] 8-bit numbers.
for (uint32_t j = 0; j < cf; ++j) {
float value = Math::half_to_float(rptr[j]);
// converting to 32-bit floating point.
value = CLAMP(value, 0.0f, 1.0f);
((uint8_t *)&dstc)[j] = value * 255;
}
} break;
case Mesh::ARRAY_CUSTOM_RGBA8_SNORM: {
// 4x [-127,127] 8-bit numbers.
const uint16_t *rptr = (const uint16_t *)&srcc;
for (uint32_t j = 0; j < cf; ++j) {
float value = Math::half_to_float(rptr[j]);
// converting to 32-bit floating point.
value = CLAMP(value, -1.0f, 1.0f);
((uint8_t *)&dstc)[j] = value * 127;
}
} break;
case Mesh::ARRAY_CUSTOM_RG_HALF:
// 2x 16-bit floating point numbers.
case Mesh::ARRAY_CUSTOM_RGBA_HALF: {
// do nothing
return srcc;
} break;
case Mesh::ARRAY_CUSTOM_R_FLOAT:
case Mesh::ARRAY_CUSTOM_RG_FLOAT:
case Mesh::ARRAY_CUSTOM_RGB_FLOAT:
case Mesh::ARRAY_CUSTOM_RGBA_FLOAT: {
// 4x 32-bit floating point numbers.
const uint32_t ct = p_to_type - Mesh::ARRAY_CUSTOM_R_FLOAT + 1;
const uint32_t c = MIN(cf, ct);
const uint16_t *rptr = (const uint16_t *)&srcc;
for (uint32_t j = 0; j < c; ++j) {
// converting to 32-bit floating point.
dstc.components[j] = Math::half_to_float(rptr[j]);
}
} break;
default: {
ERR_FAIL_V(Color(Color(0, 0, 0, 0)));
} break;
}
} break;
case Mesh::ARRAY_CUSTOM_R_FLOAT:
// 1x 32-bit floating point numbers.
case Mesh::ARRAY_CUSTOM_RG_FLOAT:
// 2x 32-bit floating point numbers.
case Mesh::ARRAY_CUSTOM_RGB_FLOAT:
// 3x 32-bit floating point numbers.
case Mesh::ARRAY_CUSTOM_RGBA_FLOAT: {
// 4x 32-bit floating point numbers.
const uint32_t cf = p_from_type - Mesh::ARRAY_CUSTOM_R_FLOAT + 1;
switch (p_to_type) {
case Mesh::ARRAY_CUSTOM_RGBA8_UNORM: {
// 4x [0, 255] 8-bit numbers.
for (uint32_t j = 0; j < cf; ++j) {
float value = CLAMP(srcc.components[j], 0.0f, 1.0f);
((uint8_t *)&dstc)[j] = value * 255;
}
} break;
case Mesh::ARRAY_CUSTOM_RGBA8_SNORM: {
// 4x [-127,127] 8-bit numbers.
for (uint32_t j = 0; j < cf; ++j) {
float value = CLAMP(srcc.components[j], -1.0f, 1.0f);
((uint8_t *)&dstc)[j] = value * 127;
}
} break;
case Mesh::ARRAY_CUSTOM_RG_HALF:
// 2x 16-bit floating point numbers.
case Mesh::ARRAY_CUSTOM_RGBA_HALF: {
// 4x 16-bit floating point numbers.
const uint32_t ct = (p_to_type - Mesh::ARRAY_CUSTOM_RGBA_HALF + 1) * 2;
const uint32_t c = MIN(cf, ct);
uint16_t *wptr = (uint16_t *)&dstc;
for (uint32_t j = 0; j < c; ++j) {
// converting to 16-bit floating point.
wptr[j] = Math::make_half_float(srcc.components[j]);
}
} break;
case Mesh::ARRAY_CUSTOM_R_FLOAT:
case Mesh::ARRAY_CUSTOM_RG_FLOAT:
case Mesh::ARRAY_CUSTOM_RGB_FLOAT:
case Mesh::ARRAY_CUSTOM_RGBA_FLOAT: {
return srcc;
}
default: {
ERR_FAIL_V(Color(Color(0, 0, 0, 0)));
} break;
}
} break;
default: {
ERR_FAIL_V(Color(Color(0, 0, 0, 0)));
} break;
}
return dstc;
}
MeshDataTool::MeshDataTool() {
clear();
}

View file

@ -37,6 +37,7 @@ class MeshDataTool : public RefCounted {
GDCLASS(MeshDataTool, RefCounted);
int format = 0;
struct Vertex {
Vector3 vertex;
Color color;
@ -49,6 +50,7 @@ class MeshDataTool : public RefCounted {
Vector<int> edges;
Vector<int> faces;
Variant meta;
Color custom[Mesh::ARRAY_CUSTOM_COUNT];
};
Vector<Vertex> vertices;
@ -71,6 +73,9 @@ class MeshDataTool : public RefCounted {
Ref<Material> material;
static Error _convert_custom_data_n(MeshDataTool::Vertex *p_data, uint32_t p_custom_idx, uint32_t n, uint32_t p_from_type, uint32_t p_to_type);
static Color _convert_custom_data(const Color &srcc, uint32_t p_from_type, uint32_t p_to_type);
protected:
static void _bind_methods();
@ -112,6 +117,20 @@ public:
Variant get_vertex_meta(int p_idx) const;
void set_vertex_meta(int p_idx, const Variant &p_meta);
Color get_vertex_custom_float(int p_idx, int p_custom_idx) const;
PackedByteArray get_vertex_custom_hfloat(int p_idx, int p_custom_idx) const;
PackedByteArray get_vertex_custom_unorm8(int p_idx, int p_custom_idx) const;
PackedInt32Array get_vertex_custom_snorm8_32i(int p_idx, int p_custom_idx) const;
Error set_vertex_custom_float(int p_idx, int p_custom_idx, const Color &p_customf);
Error set_vertex_custom_hfloat(int p_idx, int p_custom_idx, const PackedByteArray &p_customu);
Error set_vertex_custom_unorm8(int p_idx, int p_custom_idx, const PackedByteArray &p_customu);
Error set_vertex_custom_snorm8_32i(int p_idx, int p_custom_idx, const PackedInt32Array &p_customu);
int has_custom(int p_custom_idx) const;
int get_custom_type(int p_custom_idx) const;
Error set_custom_type(int p_custom_idx, Mesh::ArrayCustomFormat p_type, bool p_convert = false, bool has_custom = true);
Vector<int> get_vertex_edges(int p_idx) const;
Vector<int> get_vertex_faces(int p_idx) const;

View file

@ -601,10 +601,10 @@ void SceneShaderForwardClustered::init(RendererStorageRD *p_storage, const Strin
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["CUSTOM0"] = "#define CUSTOM0_USED\n";
actions.usage_defines["CUSTOM1"] = "#define CUSTOM1_USED\n";
actions.usage_defines["CUSTOM2"] = "#define CUSTOM2_USED\n";
actions.usage_defines["CUSTOM3"] = "#define CUSTOM3_USED\n";
actions.usage_defines["NORMAL_MAP"] = "#define NORMAL_MAP_USED\n";
actions.usage_defines["NORMAL_MAP_DEPTH"] = "@NORMAL_MAP";
actions.usage_defines["COLOR"] = "#define COLOR_USED\n";

View file

@ -593,10 +593,10 @@ void SceneShaderForwardMobile::init(RendererStorageRD *p_storage, const String p
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["CUSTOM0"] = "#define CUSTOM0_USED\n";
actions.usage_defines["CUSTOM1"] = "#define CUSTOM1_USED\n";
actions.usage_defines["CUSTOM2"] = "#define CUSTOM2_USED\n";
actions.usage_defines["CUSTOM3"] = "#define CUSTOM3_USED\n";
actions.usage_defines["NORMAL_MAP"] = "#define NORMAL_MAP_USED\n";
actions.usage_defines["NORMAL_MAP_DEPTH"] = "@NORMAL_MAP";
actions.usage_defines["COLOR"] = "#define COLOR_USED\n";

View file

@ -500,7 +500,7 @@ Error RenderingServer::_surface_set_data(Array p_arrays, uint32_t p_format, uint
case RS::ARRAY_CUSTOM1:
case RS::ARRAY_CUSTOM2:
case RS::ARRAY_CUSTOM3: {
uint32_t type = (p_format >> (ARRAY_FORMAT_CUSTOM_BASE + ARRAY_FORMAT_CUSTOM_BITS * (RS::ARRAY_CUSTOM0 - ai))) & ARRAY_FORMAT_CUSTOM_MASK;
uint32_t type = (p_format >> (ARRAY_FORMAT_CUSTOM_BASE + ARRAY_FORMAT_CUSTOM_BITS * (ai - RS::ARRAY_CUSTOM0))) & ARRAY_FORMAT_CUSTOM_MASK;
switch (type) {
case ARRAY_CUSTOM_RGBA8_UNORM:
case ARRAY_CUSTOM_RGBA8_SNORM:
@ -541,14 +541,14 @@ Error RenderingServer::_surface_set_data(Array p_arrays, uint32_t p_format, uint
ERR_FAIL_COND_V(p_arrays[ai].get_type() != Variant::PACKED_FLOAT32_ARRAY, ERR_INVALID_PARAMETER);
Vector<float> array = p_arrays[ai];
int32_t s = ARRAY_CUSTOM_R_FLOAT - ai + 1;
int32_t s = type - ARRAY_CUSTOM_R_FLOAT + 1;
ERR_FAIL_COND_V(array.size() != p_vertex_array_len * s, ERR_INVALID_PARAMETER);
const float *src = array.ptr();
for (int i = 0; i < p_vertex_array_len; i++) {
memcpy(&aw[p_offsets[ai] + i * p_attrib_stride], &src[i * s], 4 * s);
memcpy(&aw[p_offsets[ai] + i * p_attrib_stride], &src[i * s], sizeof(float) * s);
}
} break;
default: {
@ -938,6 +938,13 @@ Error RenderingServer::mesh_create_surface_data_from_arrays(SurfaceData *r_surfa
}
}
for (uint32_t i = 0; i < RS::ARRAY_CUSTOM_COUNT; ++i) {
// include custom array format type.
if (format & (1 << (ARRAY_CUSTOM0 + i))) {
format |= (RS::ARRAY_FORMAT_CUSTOM_MASK << (RS::ARRAY_FORMAT_CUSTOM_BASE + i * RS::ARRAY_FORMAT_CUSTOM_BITS)) & p_compress_format;
}
}
uint32_t offsets[RS::ARRAY_MAX];
uint32_t vertex_element_size;
@ -1191,7 +1198,7 @@ Array RenderingServer::_get_array_from_surface(uint32_t p_format, Vector<uint8_t
case RS::ARRAY_CUSTOM1:
case RS::ARRAY_CUSTOM2:
case RS::ARRAY_CUSTOM3: {
uint32_t type = (p_format >> (ARRAY_FORMAT_CUSTOM_BASE + ARRAY_FORMAT_CUSTOM_BITS * (RS::ARRAY_CUSTOM0 - i))) & ARRAY_FORMAT_CUSTOM_MASK;
uint32_t type = (p_format >> (ARRAY_FORMAT_CUSTOM_BASE + ARRAY_FORMAT_CUSTOM_BITS * (i - RS::ARRAY_CUSTOM0))) & ARRAY_FORMAT_CUSTOM_MASK;
switch (type) {
case ARRAY_CUSTOM_RGBA8_UNORM:
case ARRAY_CUSTOM_RGBA8_SNORM:
@ -1219,6 +1226,8 @@ Array RenderingServer::_get_array_from_surface(uint32_t p_format, Vector<uint8_t
uint32_t s = type - ARRAY_CUSTOM_R_FLOAT + 1;
Vector<float> arr;
arr.resize(s * p_vertex_len);
float *w = arr.ptrw();
for (int j = 0; j < p_vertex_len; j++) {