Blender  V2.93
draw_cache_impl_pointcloud.c
Go to the documentation of this file.
1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  *
16  * The Original Code is Copyright (C) 2017 by Blender Foundation.
17  * All rights reserved.
18  */
19 
26 #include <string.h>
27 
28 #include "MEM_guardedalloc.h"
29 
30 #include "BLI_math_base.h"
31 #include "BLI_math_vector.h"
32 #include "BLI_utildefines.h"
33 
34 #include "DNA_object_types.h"
35 #include "DNA_pointcloud_types.h"
36 
37 #include "BKE_pointcloud.h"
38 
39 #include "GPU_batch.h"
40 
41 #include "draw_cache_impl.h" /* own include */
42 
43 static void pointcloud_batch_cache_clear(PointCloud *pointcloud);
44 
45 /* ---------------------------------------------------------------------- */
46 /* PointCloud GPUBatch Cache */
47 
48 typedef struct PointCloudBatchCache {
49  GPUVertBuf *pos; /* Position and radius. */
50  GPUVertBuf *geom; /* Instanced geometry for each point in the cloud (small sphere). */
52 
56 
57  /* settings to determine if cache is invalid */
58  bool is_dirty;
59 
60  int mat_len;
62 
63 /* GPUBatch cache management. */
64 
65 static bool pointcloud_batch_cache_valid(PointCloud *pointcloud)
66 {
67  PointCloudBatchCache *cache = pointcloud->batch_cache;
68 
69  if (cache == NULL) {
70  return false;
71  }
72  if (cache->mat_len != DRW_pointcloud_material_count_get(pointcloud)) {
73  return false;
74  }
75  return cache->is_dirty == false;
76 }
77 
78 static void pointcloud_batch_cache_init(PointCloud *pointcloud)
79 {
80  PointCloudBatchCache *cache = pointcloud->batch_cache;
81 
82  if (!cache) {
83  cache = pointcloud->batch_cache = MEM_callocN(sizeof(*cache), __func__);
84  }
85  else {
86  memset(cache, 0, sizeof(*cache));
87  }
88 
89  cache->mat_len = DRW_pointcloud_material_count_get(pointcloud);
90  cache->surface_per_mat = MEM_callocN(sizeof(GPUBatch *) * cache->mat_len,
91  "pointcloud suface_per_mat");
92 
93  cache->is_dirty = false;
94 }
95 
97 {
98  if (!pointcloud_batch_cache_valid(pointcloud)) {
99  pointcloud_batch_cache_clear(pointcloud);
100  pointcloud_batch_cache_init(pointcloud);
101  }
102 }
103 
105 {
106  return pointcloud->batch_cache;
107 }
108 
110 {
111  PointCloudBatchCache *cache = pointcloud->batch_cache;
112  if (cache == NULL) {
113  return;
114  }
115  switch (mode) {
117  cache->is_dirty = true;
118  break;
119  default:
120  BLI_assert(0);
121  }
122 }
123 
124 static void pointcloud_batch_cache_clear(PointCloud *pointcloud)
125 {
126  PointCloudBatchCache *cache = pointcloud->batch_cache;
127  if (!cache) {
128  return;
129  }
130 
136 
137  if (cache->surface_per_mat) {
138  for (int i = 0; i < cache->mat_len; i++) {
140  }
141  }
143 }
144 
146 {
147  pointcloud_batch_cache_clear(pointcloud);
148  MEM_SAFE_FREE(pointcloud->batch_cache);
149 }
150 
152 {
153  if (cache->pos != NULL) {
154  return;
155  }
156 
157  PointCloud *pointcloud = ob->data;
158  const bool has_radius = pointcloud->radius != NULL;
159 
160  static GPUVertFormat format = {0};
161  static GPUVertFormat format_no_radius = {0};
162  static uint pos;
163  if (format.attr_len == 0) {
164  /* initialize vertex format */
165  /* From the opengl wiki:
166  * Note that size does not have to exactly match the size used by the vertex shader. If the
167  * vertex shader has fewer components than the attribute provides, then the extras are ignored.
168  * If the vertex shader has more components than the array provides, the extras are given
169  * values from the vector (0, 0, 0, 1) for the missing XYZW components.
170  */
171  pos = GPU_vertformat_attr_add(&format_no_radius, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
173  }
174 
175  cache->pos = GPU_vertbuf_create_with_format(has_radius ? &format : &format_no_radius);
176  GPU_vertbuf_data_alloc(cache->pos, pointcloud->totpoint);
177 
178  if (has_radius) {
179  float(*vbo_data)[4] = (float(*)[4])GPU_vertbuf_get_data(cache->pos);
180  for (int i = 0; i < pointcloud->totpoint; i++) {
181  copy_v3_v3(vbo_data[i], pointcloud->co[i]);
182  /* TODO(fclem): remove multiplication here.
183  * Here only for keeping the size correct for now. */
184  vbo_data[i][3] = pointcloud->radius[i] * 100.0f;
185  }
186  }
187  else {
188  GPU_vertbuf_attr_fill(cache->pos, pos, pointcloud->co);
189  }
190 }
191 
192 static const float half_octahedron_normals[5][3] = {
193  {0.0f, 0.0f, 1.0f},
194  {1.0f, 0.0f, 0.0f},
195  {0.0f, 1.0f, 0.0f},
196  {-1.0f, 0.0f, 0.0f},
197  {0.0f, -1.0f, 0.0f},
198 };
199 
200 static const uint half_octahedron_tris[4][3] = {
201  {0, 1, 2},
202  {0, 2, 3},
203  {0, 3, 4},
204  {0, 4, 1},
205 };
206 
208 {
209  if (cache->geom != NULL) {
210  return;
211  }
212 
213  static GPUVertFormat format = {0};
214  static uint pos;
215  if (format.attr_len == 0) {
216  /* initialize vertex format */
219  }
220 
223 
225 
226  GPUIndexBufBuilder builder;
227  GPU_indexbuf_init(&builder,
231 
232  for (int i = 0; i < ARRAY_SIZE(half_octahedron_tris); i++) {
234  }
235 
236  cache->geom_indices = GPU_indexbuf_build(&builder);
237 }
238 
240 {
241  PointCloud *pointcloud = ob->data;
243 
244  if (cache->dots == NULL) {
246  cache->dots = GPU_batch_create(GPU_PRIM_POINTS, cache->pos, NULL);
247  }
248 
249  return cache->dots;
250 }
251 
253 {
254  PointCloud *pointcloud = ob->data;
256 
257  if (cache->surface == NULL) {
260 
261  cache->surface = GPU_batch_create(GPU_PRIM_TRIS, cache->geom, cache->geom_indices);
262  GPU_batch_instbuf_add_ex(cache->surface, cache->pos, false);
263  }
264 
265  return cache->surface;
266 }
267 
269  struct GPUMaterial **UNUSED(gpumat_array),
270  uint gpumat_array_len)
271 {
272  PointCloud *pointcloud = ob->data;
274  BLI_assert(cache->mat_len == gpumat_array_len);
275  UNUSED_VARS(gpumat_array_len);
276 
277  if (cache->surface_per_mat[0] == NULL) {
280 
281  cache->surface_per_mat[0] = GPU_batch_create(GPU_PRIM_TRIS, cache->geom, cache->geom_indices);
282  GPU_batch_instbuf_add_ex(cache->surface_per_mat[0], cache->pos, false);
283  }
284 
285  return cache->surface_per_mat;
286 }
287 
289 {
290  return max_ii(1, pointcloud->totcol);
291 }
typedef float(TangentPoint)[2]
General operations for point-clouds.
@ BKE_POINTCLOUD_BATCH_DIRTY_ALL
#define BLI_assert(a)
Definition: BLI_assert.h:58
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:83
#define ARRAY_SIZE(arr)
#define UNUSED_VARS(...)
#define UNUSED(x)
#define UNPACK3(a)
Object is a sort of wrapper for general info.
GPUBatch
Definition: GPU_batch.h:93
#define GPU_batch_create(prim, verts, elem)
Definition: GPU_batch.h:107
#define GPU_BATCH_DISCARD_SAFE(batch)
Definition: GPU_batch.h:199
int GPU_batch_instbuf_add_ex(GPUBatch *, GPUVertBuf *, bool own_vbo)
Definition: gpu_batch.cc:168
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:35
@ GPU_PRIM_TRIS
Definition: GPU_primitive.h:37
#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:47
void *(* MEM_callocN)(size_t len, const char *str)
Definition: mallocn.c:45
void * data
float(* co)[3]