30887e3fb196458a108d40a5ec50eaf8a089349d
[blender.git] / source / blender / draw / engines / gpencil / gpencil_cache_utils.c
1 /*
2  * Copyright 2017, Blender Foundation.
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  * Contributor(s): Antonio Vazquez
19  *
20  */
21
22 /** \file blender/draw/engines/gpencil/gpencil_cache_utils.c
23  *  \ingroup draw
24  */
25
26 #include "DRW_engine.h"
27 #include "DRW_render.h"
28
29 #include "BKE_global.h"
30
31 #include "ED_gpencil.h"
32 #include "ED_view3d.h"
33
34 #include "DNA_gpencil_types.h"
35 #include "DNA_view3d_types.h"
36
37 #include "gpencil_engine.h"
38
39 #include "draw_cache_impl.h"
40
41 #include "DEG_depsgraph.h"
42 #include "DEG_depsgraph_query.h"
43
44 static bool gpencil_check_ob_duplicated(tGPencilObjectCache *cache_array,
45         int gp_cache_used, Object *ob, int *r_index)
46 {
47         if (gp_cache_used == 0) {
48                 return false;
49         }
50
51         for (int i = 0; i < gp_cache_used; i++) {
52                 tGPencilObjectCache *cache_elem = &cache_array[i];
53                 if (cache_elem->ob == ob) {
54                         *r_index = cache_elem->data_idx;
55                         return true;
56                 }
57         }
58         return false;
59 }
60
61 static bool gpencil_check_datablock_duplicated(
62         tGPencilObjectCache *cache_array, int gp_cache_used,
63         Object *ob, bGPdata *gpd)
64 {
65         if (gp_cache_used == 0) {
66                 return false;
67         }
68
69         for (int i = 0; i < gp_cache_used; i++) {
70                 tGPencilObjectCache *cache_elem = &cache_array[i];
71                 if ((cache_elem->ob != ob) &&
72                     (cache_elem->gpd == gpd))
73                 {
74                         return true;
75                 }
76         }
77         return false;
78 }
79
80 static int gpencil_len_datablock_duplicated(
81         tGPencilObjectCache *cache_array, int gp_cache_used,
82         Object *ob, bGPdata *gpd)
83 {
84         int tot = 0;
85         if (gp_cache_used == 0) {
86                 return 0;
87         }
88
89         for (int i = 0; i < gp_cache_used; i++) {
90                 tGPencilObjectCache *cache_elem = &cache_array[i];
91                 if ((cache_elem->ob != ob) &&
92                     (cache_elem->gpd == gpd) &&
93                     (!cache_elem->is_dup_ob))
94                 {
95                         tot++;
96                 }
97         }
98         return tot;
99 }
100
101  /* add a gpencil object to cache to defer drawing */
102 tGPencilObjectCache *gpencil_object_cache_add(
103         tGPencilObjectCache *cache_array, Object *ob,
104         int *gp_cache_size, int *gp_cache_used)
105 {
106         const DRWContextState *draw_ctx = DRW_context_state_get();
107         tGPencilObjectCache *cache_elem = NULL;
108         RegionView3D *rv3d = draw_ctx->rv3d;
109         tGPencilObjectCache *p = NULL;
110
111         /* By default a cache is created with one block with a predefined number of free slots,
112         if the size is not enough, the cache is reallocated adding a new block of free slots.
113         This is done in order to keep cache small */
114         if (*gp_cache_used + 1 > *gp_cache_size) {
115                 if ((*gp_cache_size == 0) || (cache_array == NULL)) {
116                         p = MEM_callocN(sizeof(struct tGPencilObjectCache) * GP_CACHE_BLOCK_SIZE, "tGPencilObjectCache");
117                         *gp_cache_size = GP_CACHE_BLOCK_SIZE;
118                 }
119                 else {
120                         *gp_cache_size += GP_CACHE_BLOCK_SIZE;
121                         p = MEM_recallocN(cache_array, sizeof(struct tGPencilObjectCache) * *gp_cache_size);
122                 }
123                 cache_array = p;
124         }
125         /* zero out all pointers */
126         cache_elem = &cache_array[*gp_cache_used];
127         memset(cache_elem, 0, sizeof(*cache_elem));
128
129         Object *ob_orig = (Object *)DEG_get_original_id(&ob->id);
130         cache_elem->ob = ob_orig;
131         cache_elem->gpd = (bGPdata *)ob_orig->data;
132         copy_v3_v3(cache_elem->loc, ob->loc);
133         copy_m4_m4(cache_elem->obmat, ob->obmat);
134         cache_elem->idx = *gp_cache_used;
135
136         /* check if object is duplicated */
137         cache_elem->is_dup_ob = gpencil_check_ob_duplicated(
138                 cache_array,
139                 *gp_cache_used, ob_orig,
140                 &cache_elem->data_idx);
141
142         if (!cache_elem->is_dup_ob) {
143                 /* check if object reuse datablock */
144                 cache_elem->is_dup_data = gpencil_check_datablock_duplicated(
145                         cache_array, *gp_cache_used,
146                         ob_orig, cache_elem->gpd);
147                 if (cache_elem->is_dup_data) {
148                         cache_elem->data_idx = gpencil_len_datablock_duplicated(
149                                 cache_array, *gp_cache_used,
150                                 ob_orig, cache_elem->gpd);
151
152                         cache_elem->gpd->flag |= GP_DATA_CACHE_IS_DIRTY;
153                 }
154                 else {
155                         cache_elem->data_idx = 0;
156                 }
157         }
158         else {
159                 cache_elem->is_dup_data = false;
160         }
161
162         /* save FXs */
163         cache_elem->pixfactor = cache_elem->gpd->pixfactor;
164         cache_elem->shader_fx = ob_orig->shader_fx;
165
166         cache_elem->init_grp = 0;
167         cache_elem->end_grp = -1;
168
169         /* calculate zdepth from point of view */
170         float zdepth = 0.0;
171         if (rv3d) {
172                 if (rv3d->is_persp) {
173                         zdepth = ED_view3d_calc_zfac(rv3d, ob->loc, NULL);
174                 }
175                 else {
176                         zdepth = -dot_v3v3(rv3d->viewinv[2], ob->loc);
177                 }
178         }
179         else {
180                 /* In render mode, rv3d is not available, so use the distance to camera.
181                  * The real distance is not important, but the relative distance to the camera plane
182                  * in order to sort by z_depth of the objects
183                  */
184                 float vn[3] = { 0.0f, 0.0f, -1.0f }; /* always face down */
185                 float plane_cam[4];
186                 struct Object *camera = draw_ctx->scene->camera;
187                 if (camera) {
188                         mul_m4_v3(camera->obmat, vn);
189                         normalize_v3(vn);
190                         plane_from_point_normal_v3(plane_cam, camera->loc, vn);
191                         zdepth = dist_squared_to_plane_v3(ob->loc, plane_cam);
192                 }
193         }
194         cache_elem->zdepth = zdepth;
195         /* increase slots used in cache */
196         (*gp_cache_used)++;
197
198         return cache_array;
199 }
200
201 /* get current cache data */
202 static GpencilBatchCache *gpencil_batch_get_element(Object *ob)
203 {
204         Object *ob_orig = (Object *)DEG_get_original_id(&ob->id);
205         return ob_orig->runtime.gpencil_cache;
206 }
207
208 /* verify if cache is valid */
209 static bool gpencil_batch_cache_valid(GpencilBatchCache *cache, bGPdata *gpd, int cfra)
210 {
211         if (cache == NULL) {
212                 return false;
213         }
214
215         cache->is_editmode = GPENCIL_ANY_EDIT_MODE(gpd);
216
217         if (cfra != cache->cache_frame) {
218                 return false;
219         }
220
221         if (gpd->flag & GP_DATA_CACHE_IS_DIRTY) {
222                 return false;
223         }
224
225         if (cache->is_editmode) {
226                 return false;
227         }
228
229         if (cache->is_dirty) {
230                 return false;
231         }
232
233         return true;
234 }
235
236 /* resize the cache to the number of slots */
237 static void gpencil_batch_cache_resize(GpencilBatchCache *cache, int slots)
238 {
239         cache->cache_size = slots;
240         cache->batch_stroke = MEM_recallocN(cache->batch_stroke, sizeof(struct Gwn_Batch *) * slots);
241         cache->batch_fill = MEM_recallocN(cache->batch_fill, sizeof(struct Gwn_Batch *) * slots);
242         cache->batch_edit = MEM_recallocN(cache->batch_edit, sizeof(struct Gwn_Batch *) * slots);
243         cache->batch_edlin = MEM_recallocN(cache->batch_edlin, sizeof(struct Gwn_Batch *) * slots);
244 }
245
246 /* check size and increase if no free slots */
247 void gpencil_batch_cache_check_free_slots(Object *ob)
248 {
249         GpencilBatchCache *cache = gpencil_batch_get_element(ob);
250
251         /* the memory is reallocated by chunks, not for one slot only to improve speed */
252         if (cache->cache_idx >= cache->cache_size) {
253                 cache->cache_size += GPENCIL_MIN_BATCH_SLOTS_CHUNK;
254                 gpencil_batch_cache_resize(cache, cache->cache_size);
255         }
256 }
257
258 /* cache init */
259 static GpencilBatchCache *gpencil_batch_cache_init(Object *ob, int cfra)
260 {
261         Object *ob_orig = (Object *)DEG_get_original_id(&ob->id);
262         bGPdata *gpd = (bGPdata *)ob_orig->data;
263
264         GpencilBatchCache *cache = gpencil_batch_get_element(ob);
265
266         if (G.debug_value >= 664) {
267                 printf("gpencil_batch_cache_init: %s\n", ob->id.name);
268         }
269
270         if (!cache) {
271                 cache = MEM_callocN(sizeof(*cache), __func__);
272                 ob_orig->runtime.gpencil_cache = cache;
273         }
274         else {
275                 memset(cache, 0, sizeof(*cache));
276         }
277
278         cache->cache_size = GPENCIL_MIN_BATCH_SLOTS_CHUNK;
279         cache->batch_stroke = MEM_callocN(sizeof(struct Gwn_Batch *) * cache->cache_size, "Gpencil_Batch_Stroke");
280         cache->batch_fill = MEM_callocN(sizeof(struct Gwn_Batch *) * cache->cache_size, "Gpencil_Batch_Fill");
281         cache->batch_edit = MEM_callocN(sizeof(struct Gwn_Batch *) * cache->cache_size, "Gpencil_Batch_Edit");
282         cache->batch_edlin = MEM_callocN(sizeof(struct Gwn_Batch *) * cache->cache_size, "Gpencil_Batch_Edlin");
283
284         cache->is_editmode = GPENCIL_ANY_EDIT_MODE(gpd);
285         gpd->flag &= ~GP_DATA_CACHE_IS_DIRTY;
286
287         cache->cache_idx = 0;
288         cache->is_dirty = true;
289         cache->cache_frame = cfra;
290
291         return cache;
292 }
293
294 /* clear cache */
295 static void gpencil_batch_cache_clear(GpencilBatchCache *cache)
296 {
297         if (!cache) {
298                 return;
299         }
300
301         if (cache->cache_size == 0) {
302                 return;
303         }
304
305         if (cache->cache_size > 0) {
306                 for (int i = 0; i < cache->cache_size; i++) {
307                         GPU_BATCH_DISCARD_SAFE(cache->batch_stroke[i]);
308                         GPU_BATCH_DISCARD_SAFE(cache->batch_fill[i]);
309                         GPU_BATCH_DISCARD_SAFE(cache->batch_edit[i]);
310                         GPU_BATCH_DISCARD_SAFE(cache->batch_edlin[i]);
311                 }
312                 MEM_SAFE_FREE(cache->batch_stroke);
313                 MEM_SAFE_FREE(cache->batch_fill);
314                 MEM_SAFE_FREE(cache->batch_edit);
315                 MEM_SAFE_FREE(cache->batch_edlin);
316         }
317
318         cache->cache_size = 0;
319 }
320
321 /* get cache */
322 GpencilBatchCache *gpencil_batch_cache_get(Object *ob, int cfra)
323 {
324         Object *ob_orig = (Object *)DEG_get_original_id(&ob->id);
325         bGPdata *gpd = (bGPdata *)ob_orig->data;
326
327         GpencilBatchCache *cache = gpencil_batch_get_element(ob);
328         if (!gpencil_batch_cache_valid(cache, gpd, cfra)) {
329                 if (G.debug_value >= 664) {
330                         printf("gpencil_batch_cache: %s\n", gpd->id.name);
331                 }
332
333                 if (cache) {
334                         gpencil_batch_cache_clear(cache);
335                 }
336                 return gpencil_batch_cache_init(ob, cfra);
337         }
338         else {
339                 return cache;
340         }
341 }
342
343 /* set cache as dirty */
344 void DRW_gpencil_batch_cache_dirty_tag(bGPdata *gpd)
345 {
346         bGPdata *gpd_orig = (bGPdata *)DEG_get_original_id(&gpd->id);
347         gpd_orig->flag |= GP_DATA_CACHE_IS_DIRTY;
348 }
349
350 /* free batch cache */
351 void DRW_gpencil_batch_cache_free(bGPdata *UNUSED(gpd))
352 {
353         return;
354 }
355
356 /* wrapper to clear cache */
357 void DRW_gpencil_freecache(struct Object *ob)
358 {
359         if ((ob) && (ob->type == OB_GPENCIL)) {
360                 gpencil_batch_cache_clear(ob->runtime.gpencil_cache);
361                 MEM_SAFE_FREE(ob->runtime.gpencil_cache);
362                 bGPdata *gpd = (bGPdata *)ob->data;
363                 if (gpd) {
364                         gpd->flag |= GP_DATA_CACHE_IS_DIRTY;
365                 }
366         }
367 }