Blender  V3.3
draw_cache_impl_pointcloud.c
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later
2  * Copyright 2017 Blender Foundation. All rights reserved. */
3 
10 #include <string.h>
11 
12 #include "MEM_guardedalloc.h"
13 
14 #include "BLI_math_base.h"
15 #include "BLI_math_vector.h"
16 #include "BLI_utildefines.h"
17 
18 #include "DNA_object_types.h"
19 #include "DNA_pointcloud_types.h"
20 
21 #include "BKE_customdata.h"
22 #include "BKE_pointcloud.h"
23 
24 #include "GPU_batch.h"
25 
26 #include "draw_cache_impl.h" /* own include */
27 
28 static void pointcloud_batch_cache_clear(PointCloud *pointcloud);
29 
30 /* ---------------------------------------------------------------------- */
31 /* PointCloud GPUBatch Cache */
32 
33 typedef struct PointCloudBatchCache {
34  GPUVertBuf *pos; /* Position and radius. */
35  GPUVertBuf *geom; /* Instanced geometry for each point in the cloud (small sphere). */
37 
41 
42  /* settings to determine if cache is invalid */
43  bool is_dirty;
44 
45  int mat_len;
47 
48 /* GPUBatch cache management. */
49 
50 static bool pointcloud_batch_cache_valid(PointCloud *pointcloud)
51 {
52  PointCloudBatchCache *cache = pointcloud->batch_cache;
53 
54  if (cache == NULL) {
55  return false;
56  }
57  if (cache->mat_len != DRW_pointcloud_material_count_get(pointcloud)) {
58  return false;
59  }
60  return cache->is_dirty == false;
61 }
62 
63 static void pointcloud_batch_cache_init(PointCloud *pointcloud)
64 {
65  PointCloudBatchCache *cache = pointcloud->batch_cache;
66 
67  if (!cache) {
68  cache = pointcloud->batch_cache = MEM_callocN(sizeof(*cache), __func__);
69  }
70  else {
71  memset(cache, 0, sizeof(*cache));
72  }
73 
74  cache->mat_len = DRW_pointcloud_material_count_get(pointcloud);
75  cache->surface_per_mat = MEM_callocN(sizeof(GPUBatch *) * cache->mat_len,
76  "pointcloud suface_per_mat");
77 
78  cache->is_dirty = false;
79 }
80 
82 {
83  if (!pointcloud_batch_cache_valid(pointcloud)) {
84  pointcloud_batch_cache_clear(pointcloud);
85  pointcloud_batch_cache_init(pointcloud);
86  }
87 }
88 
90 {
91  return pointcloud->batch_cache;
92 }
93 
95 {
96  PointCloudBatchCache *cache = pointcloud->batch_cache;
97  if (cache == NULL) {
98  return;
99  }
100  switch (mode) {
102  cache->is_dirty = true;
103  break;
104  default:
105  BLI_assert(0);
106  }
107 }
108 
109 static void pointcloud_batch_cache_clear(PointCloud *pointcloud)
110 {
111  PointCloudBatchCache *cache = pointcloud->batch_cache;
112  if (!cache) {
113  return;
114  }
115 
121 
122  if (cache->surface_per_mat) {
123  for (int i = 0; i < cache->mat_len; i++) {
125  }
126  }
128 }
129 
131 {
132  pointcloud_batch_cache_clear(pointcloud);
133  MEM_SAFE_FREE(pointcloud->batch_cache);
134 }
135 
137 {
138  if (cache->pos != NULL) {
139  return;
140  }
141 
142  PointCloud *pointcloud = ob->data;
143  const float(*positions)[3] = (float(*)[3])CustomData_get_layer_named(
144  &pointcloud->pdata, CD_PROP_FLOAT3, "position");
145  const float *radii = (float *)CustomData_get_layer_named(
146  &pointcloud->pdata, CD_PROP_FLOAT, "radius");
147  const bool has_radius = radii != NULL;
148 
149  static GPUVertFormat format = {0};
150  static GPUVertFormat format_no_radius = {0};
151  static uint pos;
152  if (format.attr_len == 0) {
153  /* initialize vertex format */
154  /* From the opengl wiki:
155  * Note that size does not have to exactly match the size used by the vertex shader. If the
156  * vertex shader has fewer components than the attribute provides, then the extras are ignored.
157  * If the vertex shader has more components than the array provides, the extras are given
158  * values from the vector (0, 0, 0, 1) for the missing XYZW components.
159  */
160  pos = GPU_vertformat_attr_add(&format_no_radius, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
162  }
163 
164  cache->pos = GPU_vertbuf_create_with_format(has_radius ? &format : &format_no_radius);
165  GPU_vertbuf_data_alloc(cache->pos, pointcloud->totpoint);
166 
167  if (has_radius) {
168  float(*vbo_data)[4] = (float(*)[4])GPU_vertbuf_get_data(cache->pos);
169  for (int i = 0; i < pointcloud->totpoint; i++) {
170  copy_v3_v3(vbo_data[i], positions[i]);
171  /* TODO(fclem): remove multiplication here.
172  * Here only for keeping the size correct for now. */
173  vbo_data[i][3] = radii[i] * 100.0f;
174  }
175  }
176  else {
178  }
179 }
180 
181 static const float half_octahedron_normals[5][3] = {
182  {0.0f, 0.0f, 1.0f},
183  {1.0f, 0.0f, 0.0f},
184  {0.0f, 1.0f, 0.0f},
185  {-1.0f, 0.0f, 0.0f},
186  {0.0f, -1.0f, 0.0f},
187 };
188 
189 static const uint half_octahedron_tris[4][3] = {
190  {0, 1, 2},
191  {0, 2, 3},
192  {0, 3, 4},
193  {0, 4, 1},
194 };
195 
197 {
198  if (cache->geom != NULL) {
199  return;
200  }
201 
202  static GPUVertFormat format = {0};
203  static uint pos;
204  if (format.attr_len == 0) {
205  /* initialize vertex format */
208  }
209 
212 
214 
215  GPUIndexBufBuilder builder;
216  GPU_indexbuf_init(&builder,
220 
221  for (int i = 0; i < ARRAY_SIZE(half_octahedron_tris); i++) {
223  }
224 
225  cache->geom_indices = GPU_indexbuf_build(&builder);
226 }
227 
229 {
230  PointCloud *pointcloud = ob->data;
232 
233  if (cache->dots == NULL) {
235  cache->dots = GPU_batch_create(GPU_PRIM_POINTS, cache->pos, NULL);
236  }
237 
238  return cache->dots;
239 }
240 
242 {
243  PointCloud *pointcloud = ob->data;
245 
246  if (cache->surface == NULL) {
249 
250  cache->surface = GPU_batch_create(GPU_PRIM_TRIS, cache->geom, cache->geom_indices);
251  GPU_batch_instbuf_add_ex(cache->surface, cache->pos, false);
252  }
253 
254  return cache->surface;
255 }
256 
258  struct GPUMaterial **UNUSED(gpumat_array),
259  uint gpumat_array_len)
260 {
261  PointCloud *pointcloud = ob->data;
263  BLI_assert(cache->mat_len == gpumat_array_len);
264  UNUSED_VARS(gpumat_array_len);
265 
266  if (cache->surface_per_mat[0] == NULL) {
269 
270  cache->surface_per_mat[0] = GPU_batch_create(GPU_PRIM_TRIS, cache->geom, cache->geom_indices);
271  GPU_batch_instbuf_add_ex(cache->surface_per_mat[0], cache->pos, false);
272  }
273 
274  return cache->surface_per_mat;
275 }
276 
278 {
279  return max_ii(1, pointcloud->totcol);
280 }
typedef float(TangentPoint)[2]
CustomData interface, see also DNA_customdata_types.h.
void * CustomData_get_layer_named(const struct CustomData *data, int type, const char *name)
General operations for point clouds.
@ BKE_POINTCLOUD_BATCH_DIRTY_ALL
#define BLI_assert(a)
Definition: BLI_assert.h:46
MINLINE int max_ii(int a, int b)
MINLINE void copy_v3_v3(float r[3], const float a[3])
unsigned int uint
Definition: BLI_sys_types.h:67
#define ARRAY_SIZE(arr)
#define UNUSED_VARS(...)
#define UNUSED(x)
#define UNPACK3(a)
@ CD_PROP_FLOAT
@ CD_PROP_FLOAT3
Object is a sort of wrapper for general info.
GPUBatch
Definition: GPU_batch.h:78
#define GPU_batch_create(prim, verts, elem)
Definition: GPU_batch.h:95
#define GPU_BATCH_DISCARD_SAFE(batch)
Definition: GPU_batch.h:216
int GPU_batch_instbuf_add_ex(GPUBatch *, GPUVertBuf *, bool own_vbo)
Definition: gpu_batch.cc:148
struct GPUIndexBuf GPUIndexBuf
#define GPU_INDEXBUF_DISCARD_SAFE(elem)
void GPU_indexbuf_init(GPUIndexBufBuilder *, GPUPrimType, uint prim_len, uint vertex_len)
GPUIndexBuf * GPU_indexbuf_build(GPUIndexBufBuilder *)
void GPU_indexbuf_add_tri_verts(GPUIndexBufBuilder *, uint v1, uint v2, uint v3)
@ GPU_PRIM_POINTS
Definition: GPU_primitive.h:19
@ GPU_PRIM_TRIS
Definition: GPU_primitive.h:21
#define GPU_vertbuf_create_with_format(format)
struct GPUVertBuf GPUVertBuf
void GPU_vertbuf_data_alloc(GPUVertBuf *, uint v_len)
void * GPU_vertbuf_get_data(const GPUVertBuf *verts)
#define GPU_VERTBUF_DISCARD_SAFE(verts)
void GPU_vertbuf_attr_fill(GPUVertBuf *, uint a_idx, const void *data)
@ GPU_FETCH_FLOAT
uint GPU_vertformat_attr_add(GPUVertFormat *, const char *name, GPUVertCompType, uint comp_len, GPUVertFetchMode)
void GPU_vertformat_alias_add(GPUVertFormat *, const char *alias)
@ GPU_COMP_F32
Read Guarded memory(de)allocation.
#define MEM_SAFE_FREE(v)
static void pointcloud_batch_cache_ensure_geom(Object *UNUSED(ob), PointCloudBatchCache *cache)
static const uint half_octahedron_tris[4][3]
static void pointcloud_batch_cache_init(PointCloud *pointcloud)
static void pointcloud_batch_cache_ensure_pos(Object *ob, PointCloudBatchCache *cache)
struct PointCloudBatchCache PointCloudBatchCache
GPUBatch ** DRW_cache_pointcloud_surface_shaded_get(Object *ob, struct GPUMaterial **UNUSED(gpumat_array), uint gpumat_array_len)
int DRW_pointcloud_material_count_get(PointCloud *pointcloud)
GPUBatch * DRW_pointcloud_batch_cache_get_surface(Object *ob)
GPUBatch * DRW_pointcloud_batch_cache_get_dots(Object *ob)
void DRW_pointcloud_batch_cache_dirty_tag(PointCloud *pointcloud, int mode)
static void pointcloud_batch_cache_clear(PointCloud *pointcloud)
static bool pointcloud_batch_cache_valid(PointCloud *pointcloud)
static const float half_octahedron_normals[5][3]
void DRW_pointcloud_batch_cache_free(PointCloud *pointcloud)
void DRW_pointcloud_batch_cache_validate(PointCloud *pointcloud)
static PointCloudBatchCache * pointcloud_batch_cache_get(PointCloud *pointcloud)
uint pos
format
Definition: logImageCore.h:38
void *(* MEM_callocN)(size_t len, const char *str)
Definition: mallocn.c:31
MutableSpan< float3 > positions
MutableSpan< float > radii
void * data
struct CustomData pdata