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                 GPUBatch *batch;
63         } face_wire;
64
65         /* settings to determine if cache is invalid */
66         bool is_dirty;
67 } MetaBallBatchCache;
68
69 /* GPUBatch cache management. */
70
71 static bool metaball_batch_cache_valid(MetaBall *mb)
72 {
73         MetaBallBatchCache *cache = mb->batch_cache;
74
75         if (cache == NULL) {
76                 return false;
77         }
78
79         return cache->is_dirty == false;
80 }
81
82 static void metaball_batch_cache_init(MetaBall *mb)
83 {
84         MetaBallBatchCache *cache = mb->batch_cache;
85
86         if (!cache) {
87                 cache = mb->batch_cache = MEM_mallocN(sizeof(*cache), __func__);
88         }
89         cache->batch = NULL;
90         cache->mat_len = 0;
91         cache->shaded_triangles = NULL;
92         cache->is_dirty = false;
93         cache->pos_nor_in_order = NULL;
94         cache->face_wire.batch = NULL;
95 }
96
97 static MetaBallBatchCache *metaball_batch_cache_get(MetaBall *mb)
98 {
99         if (!metaball_batch_cache_valid(mb)) {
100                 metaball_batch_cache_clear(mb);
101                 metaball_batch_cache_init(mb);
102         }
103         return mb->batch_cache;
104 }
105
106 void DRW_mball_batch_cache_dirty_tag(MetaBall *mb, int mode)
107 {
108         MetaBallBatchCache *cache = mb->batch_cache;
109         if (cache == NULL) {
110                 return;
111         }
112         switch (mode) {
113                 case BKE_MBALL_BATCH_DIRTY_ALL:
114                         cache->is_dirty = true;
115                         break;
116                 default:
117                         BLI_assert(0);
118         }
119 }
120
121 static void metaball_batch_cache_clear(MetaBall *mb)
122 {
123         MetaBallBatchCache *cache = mb->batch_cache;
124         if (!cache) {
125                 return;
126         }
127
128         GPU_BATCH_DISCARD_SAFE(cache->face_wire.batch);
129         GPU_BATCH_DISCARD_SAFE(cache->batch);
130         GPU_VERTBUF_DISCARD_SAFE(cache->pos_nor_in_order);
131         /* Note: shaded_triangles[0] is already freed by cache->batch */
132         MEM_SAFE_FREE(cache->shaded_triangles);
133         cache->mat_len = 0;
134 }
135
136 void DRW_mball_batch_cache_free(MetaBall *mb)
137 {
138         metaball_batch_cache_clear(mb);
139         MEM_SAFE_FREE(mb->batch_cache);
140 }
141
142 static GPUVertBuf *mball_batch_cache_get_pos_and_normals(Object *ob, MetaBallBatchCache *cache)
143 {
144         if (cache->pos_nor_in_order == NULL) {
145                 ListBase *lb = &ob->runtime.curve_cache->disp;
146                 cache->pos_nor_in_order = DRW_displist_vertbuf_calc_pos_with_normals(lb);
147         }
148         return cache->pos_nor_in_order;
149 }
150
151 /* -------------------------------------------------------------------- */
152
153 /** \name Public Object/MetaBall API
154  * \{ */
155
156 GPUBatch *DRW_metaball_batch_cache_get_triangles_with_normals(Object *ob)
157 {
158         if (!BKE_mball_is_basis(ob)) {
159                 return NULL;
160         }
161
162         MetaBall *mb = ob->data;
163         MetaBallBatchCache *cache = metaball_batch_cache_get(mb);
164
165         if (cache->batch == NULL) {
166                 ListBase *lb = &ob->runtime.curve_cache->disp;
167                 cache->batch = GPU_batch_create_ex(
168                         GPU_PRIM_TRIS,
169                         mball_batch_cache_get_pos_and_normals(ob, cache),
170                         DRW_displist_indexbuf_calc_triangles_in_order(lb),
171                         GPU_BATCH_OWNS_INDEX);
172         }
173
174         return cache->batch;
175 }
176
177 GPUBatch **DRW_metaball_batch_cache_get_surface_shaded(Object *ob, MetaBall *mb, struct GPUMaterial **UNUSED(gpumat_array), uint gpumat_array_len)
178 {
179         if (!BKE_mball_is_basis(ob)) {
180                 return NULL;
181         }
182
183         MetaBallBatchCache *cache = metaball_batch_cache_get(mb);
184         if (cache->shaded_triangles == NULL) {
185                 cache->mat_len = gpumat_array_len;
186                 cache->shaded_triangles = MEM_callocN(sizeof(*cache->shaded_triangles) * cache->mat_len, __func__);
187                 cache->shaded_triangles[0] = DRW_metaball_batch_cache_get_triangles_with_normals(ob);
188                 for (int i = 1; i < cache->mat_len; ++i) {
189                         cache->shaded_triangles[i] = NULL;
190                 }
191         }
192         return cache->shaded_triangles;
193
194 }
195
196 GPUBatch *DRW_metaball_batch_cache_get_wireframes_face(Object *ob)
197 {
198         if (!BKE_mball_is_basis(ob)) {
199                 return NULL;
200         }
201
202         MetaBall *mb = ob->data;
203         MetaBallBatchCache *cache = metaball_batch_cache_get(mb);
204
205         if (cache->face_wire.batch == NULL) {
206                 ListBase *lb = &ob->runtime.curve_cache->disp;
207                 cache->face_wire.batch = DRW_displist_create_edges_overlay_batch(lb);
208         }
209
210         return cache->face_wire.batch;
211 }