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