pandemonium_engine/modules/mesh_data_resource/mesh_data_resource.cpp

362 lines
11 KiB
C++

/*************************************************************************/
/* mesh_data_resource.cpp */
/*************************************************************************/
/* This file is part of: */
/* PANDEMONIUM ENGINE */
/* https://github.com/Relintai/pandemonium_engine */
/*************************************************************************/
/* Copyright (c) 2022-present Péter Magyar. */
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
#include "mesh_data_resource.h"
#include "core/variant/variant.h"
const String MeshDataResource::BINDING_STRING_COLLIDER_TYPE = "None,Trimesh Collision Shape,Single Convex Collision Shape,Multiple Convex Collision Shapes,Approximated Box,Approximated Capsule,Approximated Cylinder,Approximated Sphere";
Array MeshDataResource::get_array() {
return _arrays;
}
void MeshDataResource::set_array(const Array &p_arrays) {
_arrays = p_arrays;
recompute_aabb();
emit_changed();
}
Array MeshDataResource::get_array_const() const {
return _arrays;
}
AABB MeshDataResource::get_aabb() const {
return _aabb;
}
void MeshDataResource::set_aabb(const AABB &aabb) {
_aabb = aabb;
emit_changed();
}
void MeshDataResource::add_collision_shape(const Transform &transform, const Ref<Shape> &shape) {
MDRData d;
d.transform = transform;
d.shape = shape;
_collision_shapes.push_back(d);
emit_changed();
}
Ref<Shape> MeshDataResource::get_collision_shape(const int index) {
ERR_FAIL_INDEX_V(index, _collision_shapes.size(), Ref<Shape>());
return _collision_shapes[index].shape;
}
Transform MeshDataResource::get_collision_shape_offset(const int index) {
ERR_FAIL_INDEX_V(index, _collision_shapes.size(), Transform());
return _collision_shapes[index].transform;
}
int MeshDataResource::get_collision_shape_count() const {
return _collision_shapes.size();
}
Vector<Variant> MeshDataResource::get_collision_shapes() {
Vector<Variant> r;
for (int i = 0; i < _collision_shapes.size(); i++) {
r.push_back(_collision_shapes[i].transform);
r.push_back(_collision_shapes[i].shape.get_ref_ptr());
}
return r;
}
void MeshDataResource::set_collision_shapes(const Vector<Variant> &p_arrays) {
ERR_FAIL_COND(p_arrays.size() % 2 == 1);
_collision_shapes.clear();
for (int i = 0; i < p_arrays.size(); i += 2) {
MDRData d;
d.transform = p_arrays[i];
d.shape = Ref<Shape>(p_arrays[i + 1]);
_collision_shapes.push_back(d);
}
emit_changed();
}
PoolIntArray MeshDataResource::get_seams() {
return _seams;
}
void MeshDataResource::set_seams(const PoolIntArray &array) {
_seams = array;
emit_changed();
}
void MeshDataResource::append_arrays(const Array &p_arrays) {
if (p_arrays.size() != Mesh::ARRAY_MAX) {
return;
}
if (_arrays.size() != Mesh::ARRAY_MAX) {
_arrays = p_arrays;
return;
}
PoolVector3Array vertices = _arrays[Mesh::ARRAY_VERTEX];
if (vertices.size() == 0) {
_arrays = p_arrays;
return;
}
PoolVector3Array normals = _arrays[Mesh::ARRAY_NORMAL];
PoolRealArray tangents = _arrays[Mesh::ARRAY_TANGENT];
PoolColorArray colors = _arrays[Mesh::ARRAY_COLOR];
PoolVector2Array uv = _arrays[Mesh::ARRAY_TEX_UV];
PoolVector2Array uv2 = _arrays[Mesh::ARRAY_TEX_UV2];
PoolRealArray bones = _arrays[Mesh::ARRAY_BONES];
PoolRealArray weights = _arrays[Mesh::ARRAY_WEIGHTS];
PoolIntArray indices = _arrays[Mesh::ARRAY_INDEX];
PoolVector3Array merge_vertices = p_arrays[Mesh::ARRAY_VERTEX];
PoolVector3Array merge_normals = p_arrays[Mesh::ARRAY_NORMAL];
PoolRealArray merge_tangents = p_arrays[Mesh::ARRAY_TANGENT];
PoolColorArray merge_colors = p_arrays[Mesh::ARRAY_COLOR];
PoolVector2Array merge_uv = p_arrays[Mesh::ARRAY_TEX_UV];
PoolVector2Array merge_uv2 = p_arrays[Mesh::ARRAY_TEX_UV2];
PoolRealArray merge_bones = p_arrays[Mesh::ARRAY_BONES];
PoolRealArray merge_weights = p_arrays[Mesh::ARRAY_WEIGHTS];
PoolIntArray merge_indices = p_arrays[Mesh::ARRAY_INDEX];
//merge
int ovc = vertices.size();
vertices.append_array(merge_vertices);
if (_arrays[Mesh::ARRAY_NORMAL] != Variant()) {
if (merge_vertices.size() != merge_normals.size()) {
for (int i = 0; i < merge_vertices.size(); ++i) {
normals.append(Vector3());
}
} else {
normals.append_array(merge_normals);
}
}
if (_arrays[Mesh::ARRAY_TANGENT] != Variant()) {
if (merge_vertices.size() != merge_tangents.size() * 4) {
for (int i = 0; i < merge_vertices.size(); ++i) {
merge_tangents.append(0);
merge_tangents.append(0);
merge_tangents.append(0);
merge_tangents.append(0);
}
} else {
tangents.append_array(merge_tangents);
}
}
if (_arrays[Mesh::ARRAY_COLOR] != Variant()) {
if (merge_vertices.size() != merge_colors.size()) {
for (int i = 0; i < merge_vertices.size(); ++i) {
colors.append(Color());
}
} else {
colors.append_array(merge_colors);
}
}
if (_arrays[Mesh::ARRAY_TEX_UV] != Variant()) {
if (merge_vertices.size() != merge_uv.size()) {
for (int i = 0; i < merge_vertices.size(); ++i) {
uv.append(Vector2());
}
} else {
uv.append_array(merge_uv);
}
}
if (_arrays[Mesh::ARRAY_TEX_UV2] != Variant()) {
if (merge_vertices.size() != merge_uv2.size()) {
for (int i = 0; i < merge_vertices.size(); ++i) {
uv2.append(Vector2());
}
} else {
uv2.append_array(merge_uv2);
}
}
if (_arrays[Mesh::ARRAY_BONES] != Variant()) {
if (merge_vertices.size() != merge_bones.size() * 4) {
for (int i = 0; i < merge_vertices.size(); ++i) {
bones.append(0);
bones.append(0);
bones.append(0);
bones.append(0);
}
} else {
bones.append_array(merge_bones);
}
}
if (_arrays[Mesh::ARRAY_WEIGHTS] != Variant()) {
if (merge_vertices.size() != merge_weights.size() * 4) {
for (int i = 0; i < merge_vertices.size(); ++i) {
weights.append(0);
weights.append(0);
weights.append(0);
weights.append(0);
}
} else {
weights.append_array(merge_weights);
}
}
for (int i = 0; i < merge_indices.size(); ++i) {
merge_indices.set(i, merge_indices[i] + ovc);
}
indices.append_array(merge_indices);
//write back
_arrays[Mesh::ARRAY_VERTEX] = vertices;
if (_arrays[Mesh::ARRAY_NORMAL] != Variant()) {
_arrays[Mesh::ARRAY_NORMAL] = normals;
}
if (_arrays[Mesh::ARRAY_TANGENT] != Variant()) {
_arrays[Mesh::ARRAY_TANGENT] = tangents;
}
if (_arrays[Mesh::ARRAY_COLOR] != Variant()) {
_arrays[Mesh::ARRAY_COLOR] = colors;
}
if (_arrays[Mesh::ARRAY_TEX_UV] != Variant()) {
_arrays[Mesh::ARRAY_TEX_UV] = uv;
}
if (_arrays[Mesh::ARRAY_TEX_UV2] != Variant()) {
_arrays[Mesh::ARRAY_TEX_UV2] = uv2;
}
if (_arrays[Mesh::ARRAY_BONES] != Variant()) {
_arrays[Mesh::ARRAY_BONES] = bones;
}
if (_arrays[Mesh::ARRAY_WEIGHTS] != Variant()) {
_arrays[Mesh::ARRAY_WEIGHTS] = weights;
}
_arrays[Mesh::ARRAY_INDEX] = indices;
emit_changed();
}
void MeshDataResource::recompute_aabb() {
if (_arrays.size() == 0) {
return;
}
Variant arr = _arrays[Mesh::ARRAY_VERTEX];
PoolVector<Vector2> vertices_2d = arr;
if (vertices_2d.size() > 0) {
AABB aabb;
PoolVector<Vector2>::Read r = vertices_2d.read();
const Vector2 *vtx = r.ptr();
int len = vertices_2d.size();
aabb.position = Vector3(vtx[0].x, vtx[0].y, 0);
for (int i = 0; i < len; i++) {
aabb.expand_to(Vector3(vtx[i].x, vtx[i].y, 0));
}
_aabb = aabb;
return;
}
PoolVector<Vector3> vertices = arr;
int len = vertices.size();
if (len == 0) {
return;
}
PoolVector<Vector3>::Read r = vertices.read();
const Vector3 *vtx = r.ptr();
AABB aabb;
for (int i = 0; i < len; i++) {
if (i == 0)
aabb.position = vtx[i];
else
aabb.expand_to(vtx[i]);
}
_aabb = aabb;
}
MeshDataResource::MeshDataResource() {
}
MeshDataResource::~MeshDataResource() {
_arrays.clear();
_collision_shapes.clear();
}
void MeshDataResource::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_array"), &MeshDataResource::get_array);
ClassDB::bind_method(D_METHOD("set_array", "array"), &MeshDataResource::set_array);
ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "array"), "set_array", "get_array");
ClassDB::bind_method(D_METHOD("get_aabb"), &MeshDataResource::get_aabb);
ClassDB::bind_method(D_METHOD("set_aabb", "array"), &MeshDataResource::set_aabb);
ADD_PROPERTY(PropertyInfo(Variant::AABB, "aabb"), "set_aabb", "get_aabb");
ClassDB::bind_method(D_METHOD("get_collision_shapes"), &MeshDataResource::get_collision_shapes);
ClassDB::bind_method(D_METHOD("set_collision_shapes", "array"), &MeshDataResource::set_collision_shapes);
ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "collision_shapes"), "set_collision_shapes", "get_collision_shapes");
ClassDB::bind_method(D_METHOD("get_seams"), &MeshDataResource::get_seams);
ClassDB::bind_method(D_METHOD("set_seams", "array"), &MeshDataResource::set_seams);
ADD_PROPERTY(PropertyInfo(Variant::POOL_INT_ARRAY, "seams"), "set_seams", "get_seams");
ClassDB::bind_method(D_METHOD("add_collision_shape", "shape"), &MeshDataResource::add_collision_shape);
ClassDB::bind_method(D_METHOD("get_collision_shape", "index"), &MeshDataResource::get_collision_shape);
ClassDB::bind_method(D_METHOD("get_collision_shape_count"), &MeshDataResource::get_collision_shape_count);
ClassDB::bind_method(D_METHOD("append_arrays", "array"), &MeshDataResource::append_arrays);
ClassDB::bind_method(D_METHOD("recompute_aabb"), &MeshDataResource::recompute_aabb);
}