/* SPDX-License-Identifier: GPL-2.0-or-later * Copyright 2021 Blender Foundation. All rights reserved. */ /** \file * \ingroup draw */ #include "BLI_string.h" #include "draw_subdivision.h" #include "extract_mesh.hh" namespace blender::draw { /* ---------------------------------------------------------------------- */ /** \name Extract UV layers * \{ */ /* Initialize the vertex format to be used for UVs. Return true if any UV layer is * found, false otherwise. */ static bool mesh_extract_uv_format_init(GPUVertFormat *format, MeshBatchCache *cache, CustomData *cd_ldata, eMRExtractType extract_type, uint32_t &r_uv_layers) { GPU_vertformat_deinterleave(format); uint32_t uv_layers = cache->cd_used.uv; /* HACK to fix T68857 */ if (extract_type == MR_EXTRACT_BMESH && cache->cd_used.edit_uv == 1) { int layer = CustomData_get_active_layer(cd_ldata, CD_MLOOPUV); if (layer != -1) { uv_layers |= (1 << layer); } } r_uv_layers = uv_layers; for (int i = 0; i < MAX_MTFACE; i++) { if (uv_layers & (1 << i)) { char attr_name[32], attr_safe_name[GPU_MAX_SAFE_ATTR_NAME]; const char *layer_name = CustomData_get_layer_name(cd_ldata, CD_MLOOPUV, i); GPU_vertformat_safe_attr_name(layer_name, attr_safe_name, GPU_MAX_SAFE_ATTR_NAME); /* UV layer name. */ BLI_snprintf(attr_name, sizeof(attr_name), "a%s", attr_safe_name); GPU_vertformat_attr_add(format, attr_name, GPU_COMP_F32, 2, GPU_FETCH_FLOAT); /* Active render layer name. */ if (i == CustomData_get_render_layer(cd_ldata, CD_MLOOPUV)) { GPU_vertformat_alias_add(format, "a"); } /* Active display layer name. */ if (i == CustomData_get_active_layer(cd_ldata, CD_MLOOPUV)) { GPU_vertformat_alias_add(format, "au"); /* Alias to `pos` for edit uvs. */ GPU_vertformat_alias_add(format, "pos"); } /* Stencil mask uv layer name. */ if (i == CustomData_get_stencil_layer(cd_ldata, CD_MLOOPUV)) { GPU_vertformat_alias_add(format, "mu"); } } } if (format->attr_len == 0) { GPU_vertformat_attr_add(format, "dummy", GPU_COMP_F32, 1, GPU_FETCH_FLOAT); return false; } return true; } static void extract_uv_init(const MeshRenderData *mr, MeshBatchCache *cache, void *buf, void * /*tls_data*/) { GPUVertBuf *vbo = static_cast(buf); GPUVertFormat format = {0}; CustomData *cd_ldata = (mr->extract_type == MR_EXTRACT_BMESH) ? &mr->bm->ldata : &mr->me->ldata; int v_len = mr->loop_len; uint32_t uv_layers = cache->cd_used.uv; if (!mesh_extract_uv_format_init(&format, cache, cd_ldata, mr->extract_type, uv_layers)) { /* VBO will not be used, only allocate minimum of memory. */ v_len = 1; } GPU_vertbuf_init_with_format(vbo, &format); GPU_vertbuf_data_alloc(vbo, v_len); float(*uv_data)[2] = (float(*)[2])GPU_vertbuf_get_data(vbo); for (int i = 0; i < MAX_MTFACE; i++) { if (uv_layers & (1 << i)) { if (mr->extract_type == MR_EXTRACT_BMESH) { int cd_ofs = CustomData_get_n_offset(cd_ldata, CD_MLOOPUV, i); BMIter f_iter; BMFace *efa; BM_ITER_MESH (efa, &f_iter, mr->bm, BM_FACES_OF_MESH) { BMLoop *l_iter, *l_first; l_iter = l_first = BM_FACE_FIRST_LOOP(efa); do { MLoopUV *luv = (MLoopUV *)BM_ELEM_CD_GET_VOID_P(l_iter, cd_ofs); memcpy(uv_data, luv->uv, sizeof(*uv_data)); uv_data++; } while ((l_iter = l_iter->next) != l_first); } } else { const MLoopUV *layer_data = (const MLoopUV *)CustomData_get_layer_n( cd_ldata, CD_MLOOPUV, i); for (int ml_index = 0; ml_index < mr->loop_len; ml_index++, uv_data++, layer_data++) { memcpy(uv_data, layer_data->uv, sizeof(*uv_data)); } } } } } static void extract_uv_init_subdiv(const DRWSubdivCache *subdiv_cache, const MeshRenderData * /*mr*/, MeshBatchCache *cache, void *buffer, void * /*data*/) { Mesh *coarse_mesh = subdiv_cache->mesh; GPUVertBuf *vbo = static_cast(buffer); GPUVertFormat format = {0}; uint v_len = subdiv_cache->num_subdiv_loops; uint uv_layers; if (!mesh_extract_uv_format_init( &format, cache, &coarse_mesh->ldata, MR_EXTRACT_MESH, uv_layers)) { /* TODO(kevindietrich): handle this more gracefully. */ v_len = 1; } GPU_vertbuf_init_build_on_device(vbo, &format, v_len); if (uv_layers == 0) { return; } /* Index of the UV layer in the compact buffer. Used UV layers are stored in a single buffer. */ int pack_layer_index = 0; for (int i = 0; i < MAX_MTFACE; i++) { if (uv_layers & (1 << i)) { const int offset = int(subdiv_cache->num_subdiv_loops) * pack_layer_index++; draw_subdiv_extract_uvs(subdiv_cache, vbo, i, offset); } } } constexpr MeshExtract create_extractor_uv() { MeshExtract extractor = {nullptr}; extractor.init = extract_uv_init; extractor.init_subdiv = extract_uv_init_subdiv; extractor.data_type = MR_DATA_NONE; extractor.data_size = 0; extractor.use_threading = false; extractor.mesh_buffer_offset = offsetof(MeshBufferList, vbo.uv); return extractor; } /** \} */ } // namespace blender::draw const MeshExtract extract_uv = blender::draw::create_extractor_uv();