/* SPDX-License-Identifier: GPL-2.0-or-later * Copyright 2022 Blender Foundation. */ #pragma once /** \file * \ingroup draw * * Component / Object level resources like object attributes, matrices, visibility etc... * Each of them are reference by resource index (#ResourceHandle). */ #include "BKE_curve.h" #include "BKE_duplilist.h" #include "BKE_mesh.h" #include "BKE_object.h" #include "BKE_volume.h" #include "BLI_hash.h" #include "DNA_curve_types.h" #include "DNA_layer_types.h" #include "DNA_meta_types.h" #include "DNA_object_types.h" #include "draw_handle.hh" #include "draw_manager.hh" #include "draw_shader_shared.h" /* -------------------------------------------------------------------- */ /** \name ObjectMatrices * \{ */ inline void ObjectMatrices::sync(const Object &object) { model = object.object_to_world; model_inverse = object.imat; } inline void ObjectMatrices::sync(const float4x4 &model_matrix) { model = model_matrix; model_inverse = model_matrix.inverted(); } inline std::ostream &operator<<(std::ostream &stream, const ObjectMatrices &matrices) { stream << "ObjectMatrices(" << std::endl; stream << "model=" << matrices.model << ", " << std::endl; stream << "model_inverse=" << matrices.model_inverse << ")" << std::endl; return stream; } /** \} */ /* -------------------------------------------------------------------- */ /** \name ObjectInfos * \{ */ ENUM_OPERATORS(eObjectInfoFlag, OBJECT_NEGATIVE_SCALE) inline void ObjectInfos::sync() { object_attrs_len = 0; object_attrs_offset = 0; flag = eObjectInfoFlag::OBJECT_NO_INFO; } inline void ObjectInfos::sync(const blender::draw::ObjectRef ref, bool is_active_object) { object_attrs_len = 0; object_attrs_offset = 0; color = ref.object->color; index = ref.object->index; SET_FLAG_FROM_TEST(flag, is_active_object, eObjectInfoFlag::OBJECT_ACTIVE); SET_FLAG_FROM_TEST( flag, ref.object->base_flag & BASE_SELECTED, eObjectInfoFlag::OBJECT_SELECTED); SET_FLAG_FROM_TEST( flag, ref.object->base_flag & BASE_FROM_DUPLI, eObjectInfoFlag::OBJECT_FROM_DUPLI); SET_FLAG_FROM_TEST( flag, ref.object->base_flag & BASE_FROM_SET, eObjectInfoFlag::OBJECT_FROM_SET); SET_FLAG_FROM_TEST( flag, ref.object->transflag & OB_NEG_SCALE, eObjectInfoFlag::OBJECT_NEGATIVE_SCALE); if (ref.dupli_object == nullptr) { /* TODO(fclem): this is rather costly to do at draw time. Maybe we can * put it in ob->runtime and make depsgraph ensure it is up to date. */ random = BLI_hash_int_2d(BLI_hash_string(ref.object->id.name + 2), 0) * (1.0f / (float)0xFFFFFFFF); } else { random = ref.dupli_object->random_id * (1.0f / (float)0xFFFFFFFF); } /* Default values. Set if needed. */ random = 0.0f; if (ref.object->data == nullptr) { orco_add = float3(0.0f); orco_mul = float3(1.0f); return; } switch (GS(reinterpret_cast(ref.object->data)->name)) { case ID_VO: { BoundBox &bbox = *BKE_volume_boundbox_get(ref.object); orco_add = (float3(bbox.vec[6]) + float3(bbox.vec[0])) * 0.5f; /* Center. */ orco_mul = float3(bbox.vec[6]) - float3(bbox.vec[0]); /* Size. */ break; } case ID_ME: { BKE_mesh_texspace_get(static_cast(ref.object->data), orco_add, orco_mul); break; } case ID_CU_LEGACY: { Curve &cu = *static_cast(ref.object->data); BKE_curve_texspace_ensure(&cu); orco_add = cu.loc; orco_mul = cu.size; break; } case ID_MB: { MetaBall &mb = *static_cast(ref.object->data); orco_add = mb.loc; orco_mul = mb.size; break; } default: orco_add = float3(0.0f); orco_mul = float3(1.0f); break; } } inline std::ostream &operator<<(std::ostream &stream, const ObjectInfos &infos) { stream << "ObjectInfos("; if (infos.flag == eObjectInfoFlag::OBJECT_NO_INFO) { stream << "skipped)" << std::endl; return stream; } stream << "orco_add=" << infos.orco_add << ", "; stream << "orco_mul=" << infos.orco_mul << ", "; stream << "color=" << infos.color << ", "; stream << "index=" << infos.index << ", "; stream << "random=" << infos.random << ", "; stream << "flag=" << infos.flag << ")" << std::endl; return stream; } /** \} */ /* -------------------------------------------------------------------- */ /** \name ObjectBounds * \{ */ inline void ObjectBounds::sync() { bounding_sphere.w = -1.0f; /* Disable test. */ } inline void ObjectBounds::sync(Object &ob) { const BoundBox *bbox = BKE_object_boundbox_get(&ob); if (bbox == nullptr) { bounding_sphere.w = -1.0f; /* Disable test. */ return; } *reinterpret_cast(&bounding_corners[0]) = bbox->vec[0]; *reinterpret_cast(&bounding_corners[1]) = bbox->vec[4]; *reinterpret_cast(&bounding_corners[2]) = bbox->vec[3]; *reinterpret_cast(&bounding_corners[3]) = bbox->vec[1]; bounding_sphere.w = 0.0f; /* Enable test. */ } inline void ObjectBounds::sync(const float3 ¢er, const float3 &size) { *reinterpret_cast(&bounding_corners[0]) = center - size; *reinterpret_cast(&bounding_corners[1]) = center + float3(+size.x, -size.y, -size.z); *reinterpret_cast(&bounding_corners[2]) = center + float3(-size.x, +size.y, -size.z); *reinterpret_cast(&bounding_corners[3]) = center + float3(-size.x, -size.y, +size.z); bounding_sphere.w = 0.0; /* Enable test. */ } inline std::ostream &operator<<(std::ostream &stream, const ObjectBounds &bounds) { stream << "ObjectBounds("; if (bounds.bounding_sphere.w == -1.0f) { stream << "skipped)" << std::endl; return stream; } stream << std::endl; stream << ".bounding_corners[0]" << *reinterpret_cast(&bounds.bounding_corners[0]) << std::endl; stream << ".bounding_corners[1]" << *reinterpret_cast(&bounds.bounding_corners[1]) << std::endl; stream << ".bounding_corners[2]" << *reinterpret_cast(&bounds.bounding_corners[2]) << std::endl; stream << ".bounding_corners[3]" << *reinterpret_cast(&bounds.bounding_corners[3]) << std::endl; stream << ".sphere=(pos=" << float3(bounds.bounding_sphere) << ", rad=" << bounds.bounding_sphere.w << std::endl; stream << ")" << std::endl; return stream; } /** \} */