Merge branch 'master' into blender2.8
[blender.git] / source / blender / draw / intern / draw_cache_impl_metaball.c
1 /*
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  * The Original Code is Copyright (C) 2017 by Blender Foundation.
19  * All rights reserved.
20  *
21  * ***** END GPL LICENSE BLOCK *****
22  */
23
24 /** \file draw_cache_impl_metaball.c
25  *  \ingroup draw
26  *
27  * \brief MetaBall API for render engines
28  */
29
30 #include "MEM_guardedalloc.h"
31
32 #include "BLI_utildefines.h"
33
34 #include "DNA_meta_types.h"
35 #include "DNA_object_types.h"
36
37 #include "BKE_curve.h"
38 #include "BKE_mball.h"
39
40 #include "GPU_batch.h"
41
42 #include "DRW_render.h"
43
44 #include "draw_cache_impl.h"  /* own include */
45
46
47 static void metaball_batch_cache_clear(MetaBall *mb);
48
49 /* ---------------------------------------------------------------------- */
50 /* MetaBall GPUBatch Cache */
51
52 typedef struct MetaBallBatchCache {
53         GPUBatch *batch;
54         GPUBatch **shaded_triangles;
55         int mat_len;
56
57         /* Shared */
58         GPUVertBuf *pos_nor_in_order;
59
60         /* Wireframe */
61         struct {
62                 GPUVertBuf *elem_vbo;
63                 GPUTexture *elem_tx;
64                 GPUTexture *verts_tx;
65                 int tri_count;
66         } face_wire;
67
68         /* settings to determine if cache is invalid */
69         bool is_dirty;
70 } MetaBallBatchCache;
71
72 /* GPUBatch cache management. */
73
74 static bool metaball_batch_cache_valid(MetaBall *mb)
75 {
76         MetaBallBatchCache *cache = mb->batch_cache;
77
78         if (cache == NULL) {
79                 return false;
80         }
81
82         return cache->is_dirty == false;
83 }
84
85 static void metaball_batch_cache_init(MetaBall *mb)
86 {
87         MetaBallBatchCache *cache = mb->batch_cache;
88
89         if (!cache) {
90                 cache = mb->batch_cache = MEM_mallocN(sizeof(*cache), __func__);
91         }
92         cache->batch = NULL;
93         cache->mat_len = 0;
94         cache->shaded_triangles = NULL;
95         cache->is_dirty = false;
96         cache->pos_nor_in_order = NULL;
97         cache->face_wire.elem_vbo = NULL;
98         cache->face_wire.elem_tx = NULL;
99         cache->face_wire.verts_tx = NULL;
100         cache->face_wire.tri_count = 0;
101 }
102
103 static MetaBallBatchCache *metaball_batch_cache_get(MetaBall *mb)
104 {
105         if (!metaball_batch_cache_valid(mb)) {
106                 metaball_batch_cache_clear(mb);
107                 metaball_batch_cache_init(mb);
108         }
109         return mb->batch_cache;
110 }
111
112 void DRW_mball_batch_cache_dirty_tag(MetaBall *mb, int mode)
113 {
114         MetaBallBatchCache *cache = mb->batch_cache;
115         if (cache == NULL) {
116                 return;
117         }
118         switch (mode) {
119                 case BKE_MBALL_BATCH_DIRTY_ALL:
120                         cache->is_dirty = true;
121                         break;
122                 default:
123                         BLI_assert(0);
124         }
125 }
126
127 static void metaball_batch_cache_clear(MetaBall *mb)
128 {
129         MetaBallBatchCache *cache = mb->batch_cache;
130         if (!cache) {
131                 return;
132         }
133
134         GPU_VERTBUF_DISCARD_SAFE(cache->face_wire.elem_vbo);
135         DRW_TEXTURE_FREE_SAFE(cache->face_wire.elem_tx);
136         DRW_TEXTURE_FREE_SAFE(cache->face_wire.verts_tx);
137
138         GPU_BATCH_DISCARD_SAFE(cache->batch);
139         GPU_VERTBUF_DISCARD_SAFE(cache->pos_nor_in_order);
140         /* Note: shaded_triangles[0] is already freed by cache->batch */
141         MEM_SAFE_FREE(cache->shaded_triangles);
142         cache->mat_len = 0;
143 }
144
145 void DRW_mball_batch_cache_free(MetaBall *mb)
146 {
147         metaball_batch_cache_clear(mb);
148         MEM_SAFE_FREE(mb->batch_cache);
149 }
150
151 static GPUVertBuf *mball_batch_cache_get_pos_and_normals(Object *ob, MetaBallBatchCache *cache)
152 {
153         if (cache->pos_nor_in_order == NULL) {
154                 ListBase *lb = &ob->runtime.curve_cache->disp;
155                 cache->pos_nor_in_order = DRW_displist_vertbuf_calc_pos_with_normals(lb);
156         }
157         return cache->pos_nor_in_order;
158 }
159
160 static GPUTexture *mball_batch_cache_get_edges_overlay_texture_buf(Object *ob, MetaBallBatchCache *cache)
161 {
162         if (cache->face_wire.elem_tx != NULL) {
163                 return cache->face_wire.elem_tx;
164         }
165
166         ListBase *lb = &ob->runtime.curve_cache->disp;
167
168         /* We need a special index buffer. */
169         GPUVertBuf *vbo = cache->face_wire.elem_vbo = DRW_displist_create_edges_overlay_texture_buf(lb);
170
171         /* Upload data early because we need to create the texture for it. */
172         GPU_vertbuf_use(vbo);
173         cache->face_wire.elem_tx = GPU_texture_create_from_vertbuf(vbo);
174         cache->face_wire.tri_count = vbo->vertex_alloc / 3;
175
176         return cache->face_wire.elem_tx;
177 }
178
179 static GPUTexture *mball_batch_cache_get_vert_pos_and_nor_in_order_buf(Object *ob, MetaBallBatchCache *cache)
180 {
181         if (cache->face_wire.verts_tx == NULL) {
182                 GPUVertBuf *vbo = mball_batch_cache_get_pos_and_normals(ob, cache);
183                 GPU_vertbuf_use(vbo); /* Upload early for buffer texture creation. */
184                 cache->face_wire.verts_tx = GPU_texture_create_buffer(GPU_R32F, vbo->vbo_id);
185         }
186
187         return cache->face_wire.verts_tx;
188 }
189
190 /* -------------------------------------------------------------------- */
191
192 /** \name Public Object/MetaBall API
193  * \{ */
194
195 GPUBatch *DRW_metaball_batch_cache_get_triangles_with_normals(Object *ob)
196 {
197         if (!BKE_mball_is_basis(ob)) {
198                 return NULL;
199         }
200
201         MetaBall *mb = ob->data;
202         MetaBallBatchCache *cache = metaball_batch_cache_get(mb);
203
204         if (cache->batch == NULL) {
205                 ListBase *lb = &ob->runtime.curve_cache->disp;
206                 cache->batch = GPU_batch_create_ex(
207                         GPU_PRIM_TRIS,
208                         mball_batch_cache_get_pos_and_normals(ob, cache),
209                         DRW_displist_indexbuf_calc_triangles_in_order(lb),
210                         GPU_BATCH_OWNS_INDEX);
211         }
212
213         return cache->batch;
214 }
215
216 GPUBatch **DRW_metaball_batch_cache_get_surface_shaded(Object *ob, MetaBall *mb, struct GPUMaterial **UNUSED(gpumat_array), uint gpumat_array_len)
217 {
218         if (!BKE_mball_is_basis(ob)) {
219                 return NULL;
220         }
221
222         MetaBallBatchCache *cache = metaball_batch_cache_get(mb);
223         if (cache->shaded_triangles == NULL) {
224                 cache->mat_len = gpumat_array_len;
225                 cache->shaded_triangles = MEM_callocN(sizeof(*cache->shaded_triangles) * cache->mat_len, __func__);
226                 cache->shaded_triangles[0] = DRW_metaball_batch_cache_get_triangles_with_normals(ob);
227                 for (int i = 1; i < cache->mat_len; ++i) {
228                         cache->shaded_triangles[i] = NULL;
229                 }
230         }
231         return cache->shaded_triangles;
232
233 }
234
235 void DRW_metaball_batch_cache_get_wireframes_face_texbuf(
236         Object *ob, struct GPUTexture **verts_data, struct GPUTexture **face_indices, int *tri_count, bool UNUSED(reduce_len))
237 {
238         if (!BKE_mball_is_basis(ob)) {
239                 *verts_data = NULL;
240                 *face_indices = NULL;
241                 *tri_count = 0;
242                 return;
243         }
244
245         MetaBall *mb = ob->data;
246         MetaBallBatchCache *cache = metaball_batch_cache_get(mb);
247
248         if (cache->face_wire.verts_tx == NULL) {
249                 *verts_data = mball_batch_cache_get_vert_pos_and_nor_in_order_buf(ob, cache);
250                 *face_indices = mball_batch_cache_get_edges_overlay_texture_buf(ob, cache);
251         }
252         else {
253                 *verts_data = cache->face_wire.verts_tx;
254                 *face_indices = cache->face_wire.elem_tx;
255         }
256         *tri_count = cache->face_wire.tri_count;
257 }