Cleanup: use const pointer for view access API
[blender.git] / source / blender / draw / engines / clay / clay.c
1 /*
2  * Copyright 2016, 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): Blender Institute
19  *
20  */
21
22 #include "DRW_render.h"
23
24 #include "BKE_icons.h"
25 #include "BKE_idprop.h"
26 #include "BKE_main.h"
27
28 #include "BLI_dynstr.h"
29 #include "BLI_rand.h"
30
31 #include "IMB_imbuf.h"
32 #include "IMB_imbuf_types.h"
33
34 #include "UI_resources.h"
35 #include "UI_interface_icons.h"
36
37 #include "clay.h"
38 #ifdef WITH_CLAY_ENGINE
39 /* Shaders */
40
41 #define CLAY_ENGINE "BLENDER_CLAY"
42
43 extern char datatoc_clay_frag_glsl[];
44 extern char datatoc_clay_vert_glsl[];
45 extern char datatoc_ssao_alchemy_glsl[];
46
47 /* *********** LISTS *********** */
48
49 /* UBOs data needs to be 16 byte aligned (size of vec4) */
50 /* Reminder : float, int, bool are 4 bytes */
51 typedef struct CLAY_UBO_Material {
52         float ssao_params_var[4];
53         /* - 16 -*/
54         float matcap_hsv[3];
55         float matcap_id; /* even float encoding have enough precision */
56         /* - 16 -*/
57         float matcap_rot[2];
58         float pad[2]; /* ensure 16 bytes alignement */
59 } CLAY_UBO_Material; /* 48 bytes */
60
61 #define MAX_CLAY_MAT 512 /* 512 = 9 bit material id */
62
63 typedef struct CLAY_UBO_Storage {
64         CLAY_UBO_Material materials[MAX_CLAY_MAT];
65 } CLAY_UBO_Storage;
66
67 /* GPUViewport.storage
68  * Is freed everytime the viewport engine changes */
69 typedef struct CLAY_Storage {
70         /* Materials Parameter UBO */
71         CLAY_UBO_Storage mat_storage;
72         int ubo_current_id;
73         DRWShadingGroup *shgrps[MAX_CLAY_MAT];
74 } CLAY_Storage;
75
76 /* keep it under MAX_STORAGE */
77 typedef struct CLAY_StorageList {
78         struct CLAY_Storage *storage;
79         struct GPUUniformBuffer *mat_ubo;
80         struct g_data *g_data;
81 } CLAY_StorageList;
82
83 /* keep it under MAX_BUFFERS */
84 typedef struct CLAY_FramebufferList {
85         /* default */
86         struct GPUFrameBuffer *default_fb;
87         /* engine specific */
88         struct GPUFrameBuffer *dupli_depth;
89 } CLAY_FramebufferList;
90
91 /* keep it under MAX_TEXTURES */
92 typedef struct CLAY_TextureList {
93         /* default */
94         struct GPUTexture *color;
95         struct GPUTexture *depth;
96         /* engine specific */
97         struct GPUTexture *depth_dup;
98 } CLAY_TextureList;
99
100 /* keep it under MAX_PASSES */
101 typedef struct CLAY_PassList {
102         struct DRWPass *depth_pass;
103         struct DRWPass *depth_pass_cull;
104         struct DRWPass *clay_pass;
105         struct g_data *g_data;
106 } CLAY_PassList;
107
108 typedef struct CLAY_Data {
109         void *engine_type;
110         CLAY_FramebufferList *fbl;
111         CLAY_TextureList *txl;
112         CLAY_PassList *psl;
113         CLAY_StorageList *stl;
114 } CLAY_Data;
115
116 /* *********** STATIC *********** */
117
118 static struct {
119         /* Depth Pre Pass */
120         struct GPUShader *depth_sh;
121         /* Shading Pass */
122         struct GPUShader *clay_sh;
123
124         /* Matcap textures */
125         struct GPUTexture *matcap_array;
126         float matcap_colors[24][3];
127
128         /* Ssao */
129         float winmat[4][4];
130         float viewvecs[3][4];
131         float ssao_params[4];
132         int cached_sample_num;
133         struct GPUTexture *jitter_tx;
134         struct GPUTexture *sampling_tx;
135
136         /* Just a serie of int from 0 to MAX_CLAY_MAT-1 */
137         int ubo_mat_idxs[MAX_CLAY_MAT];
138 } e_data = {NULL}; /* Engine data */
139
140 typedef struct g_data {
141         DRWShadingGroup *depth_shgrp;
142         DRWShadingGroup *depth_shgrp_select;
143         DRWShadingGroup *depth_shgrp_active;
144         DRWShadingGroup *depth_shgrp_cull;
145         DRWShadingGroup *depth_shgrp_cull_select;
146         DRWShadingGroup *depth_shgrp_cull_active;
147 } g_data; /* Transient data */
148
149 /* Functions */
150
151 static void add_icon_to_rect(PreviewImage *prv, float *final_rect, int layer)
152 {
153         int image_size = prv->w[0] * prv->h[0];
154         float *new_rect = &final_rect[image_size * 4 * layer];
155
156         IMB_buffer_float_from_byte(new_rect, (unsigned char *)prv->rect[0], IB_PROFILE_SRGB, IB_PROFILE_SRGB,
157                                    false, prv->w[0], prv->h[0], prv->w[0], prv->w[0]);
158
159         /* Find overall color */
160         for (int y = 0; y < 4; ++y)     {
161                 for (int x = 0; x < 4; ++x) {
162                         e_data.matcap_colors[layer][0] += new_rect[y * 512 * 128 * 4 + x * 128 * 4 + 0];
163                         e_data.matcap_colors[layer][1] += new_rect[y * 512 * 128 * 4 + x * 128 * 4 + 1];
164                         e_data.matcap_colors[layer][2] += new_rect[y * 512 * 128 * 4 + x * 128 * 4 + 2];
165                 }
166         }
167
168         e_data.matcap_colors[layer][0] /= 16.0f * 2.0f; /* the * 2 is to darken for shadows */
169         e_data.matcap_colors[layer][1] /= 16.0f * 2.0f;
170         e_data.matcap_colors[layer][2] /= 16.0f * 2.0f;
171 }
172
173 static struct GPUTexture *load_matcaps(PreviewImage *prv[24], int nbr)
174 {
175         struct GPUTexture *tex;
176         int w = prv[0]->w[0];
177         int h = prv[0]->h[0];
178         float *final_rect = MEM_callocN(sizeof(float) * 4 * w * h * nbr, "Clay Matcap array rect");
179
180         for (int i = 0; i < nbr; ++i) {
181                 add_icon_to_rect(prv[i], final_rect, i);
182                 BKE_previewimg_free(&prv[i]);
183         }
184
185         tex = DRW_texture_create_2D_array(w, h, nbr, DRW_TEX_RGBA_8, DRW_TEX_FILTER, final_rect);
186         MEM_freeN(final_rect);
187
188         return tex;
189 }
190
191 static int matcap_to_index(int matcap)
192 {
193         if (matcap == ICON_MATCAP_02) return 1;
194         else if (matcap == ICON_MATCAP_03) return 2;
195         else if (matcap == ICON_MATCAP_04) return 3;
196         else if (matcap == ICON_MATCAP_05) return 4;
197         else if (matcap == ICON_MATCAP_06) return 5;
198         else if (matcap == ICON_MATCAP_07) return 6;
199         else if (matcap == ICON_MATCAP_08) return 7;
200         else if (matcap == ICON_MATCAP_09) return 8;
201         else if (matcap == ICON_MATCAP_10) return 9;
202         else if (matcap == ICON_MATCAP_11) return 10;
203         else if (matcap == ICON_MATCAP_12) return 11;
204         else if (matcap == ICON_MATCAP_13) return 12;
205         else if (matcap == ICON_MATCAP_14) return 13;
206         else if (matcap == ICON_MATCAP_15) return 14;
207         else if (matcap == ICON_MATCAP_16) return 15;
208         else if (matcap == ICON_MATCAP_17) return 16;
209         else if (matcap == ICON_MATCAP_18) return 17;
210         else if (matcap == ICON_MATCAP_19) return 18;
211         else if (matcap == ICON_MATCAP_20) return 19;
212         else if (matcap == ICON_MATCAP_21) return 20;
213         else if (matcap == ICON_MATCAP_22) return 21;
214         else if (matcap == ICON_MATCAP_23) return 22;
215         else if (matcap == ICON_MATCAP_24) return 23;
216         return 0;
217 }
218
219 static struct GPUTexture *create_spiral_sample_texture(int numsaples)
220 {
221         struct GPUTexture *tex;
222         float (*texels)[2] = MEM_mallocN(sizeof(float[2]) * numsaples, "concentric_tex");
223         const float numsaples_inv = 1.0f / numsaples;
224         int i;
225         /* arbitrary number to ensure we don't get conciding samples every circle */
226         const float spirals = 7.357;
227
228         for (i = 0; i < numsaples; i++) {
229                 float r = (i + 0.5f) * numsaples_inv;
230                 float phi = r * spirals * (float)(2.0 * M_PI);
231                 texels[i][0] = r * cosf(phi);
232                 texels[i][1] = r * sinf(phi);
233         }
234
235         tex = DRW_texture_create_1D(numsaples, DRW_TEX_RG_16, 0, (float *)texels);
236
237         MEM_freeN(texels);
238         return tex;
239 }
240
241 static struct GPUTexture *create_jitter_texture(void)
242 {
243         float jitter[64 * 64][2];
244         int i;
245
246         /* TODO replace by something more evenly distributed like blue noise */
247         for (i = 0; i < 64 * 64; i++) {
248                 jitter[i][0] = 2.0f * BLI_frand() - 1.0f;
249                 jitter[i][1] = 2.0f * BLI_frand() - 1.0f;
250                 normalize_v2(jitter[i]);
251         }
252
253         return DRW_texture_create_2D(64, 64, DRW_TEX_RG_16, DRW_TEX_FILTER | DRW_TEX_WRAP, &jitter[0][0]);
254 }
255
256 static void CLAY_engine_init(void *vedata)
257 {
258         CLAY_StorageList *stl = ((CLAY_Data *)vedata)->stl;
259         CLAY_TextureList *txl = ((CLAY_Data *)vedata)->txl;
260         CLAY_FramebufferList *fbl = ((CLAY_Data *)vedata)->fbl;
261
262         /* Create Texture Array */
263         if (!e_data.matcap_array) {
264                 PreviewImage *prv[24]; /* For now use all of the 24 internal matcaps */
265
266                 /* TODO only load used matcaps */
267                 prv[0]  = UI_icon_to_preview(ICON_MATCAP_01);
268                 prv[1]  = UI_icon_to_preview(ICON_MATCAP_02);
269                 prv[2]  = UI_icon_to_preview(ICON_MATCAP_03);
270                 prv[3]  = UI_icon_to_preview(ICON_MATCAP_04);
271                 prv[4]  = UI_icon_to_preview(ICON_MATCAP_05);
272                 prv[5]  = UI_icon_to_preview(ICON_MATCAP_06);
273                 prv[6]  = UI_icon_to_preview(ICON_MATCAP_07);
274                 prv[7]  = UI_icon_to_preview(ICON_MATCAP_08);
275                 prv[8]  = UI_icon_to_preview(ICON_MATCAP_09);
276                 prv[9]  = UI_icon_to_preview(ICON_MATCAP_10);
277                 prv[10] = UI_icon_to_preview(ICON_MATCAP_11);
278                 prv[11] = UI_icon_to_preview(ICON_MATCAP_12);
279                 prv[12] = UI_icon_to_preview(ICON_MATCAP_13);
280                 prv[13] = UI_icon_to_preview(ICON_MATCAP_14);
281                 prv[14] = UI_icon_to_preview(ICON_MATCAP_15);
282                 prv[15] = UI_icon_to_preview(ICON_MATCAP_16);
283                 prv[16] = UI_icon_to_preview(ICON_MATCAP_17);
284                 prv[17] = UI_icon_to_preview(ICON_MATCAP_18);
285                 prv[18] = UI_icon_to_preview(ICON_MATCAP_19);
286                 prv[19] = UI_icon_to_preview(ICON_MATCAP_20);
287                 prv[20] = UI_icon_to_preview(ICON_MATCAP_21);
288                 prv[21] = UI_icon_to_preview(ICON_MATCAP_22);
289                 prv[22] = UI_icon_to_preview(ICON_MATCAP_23);
290                 prv[23] = UI_icon_to_preview(ICON_MATCAP_24);
291
292                 e_data.matcap_array = load_matcaps(prv, 24);
293         }
294
295         /* AO Jitter */
296         if (!e_data.jitter_tx) {
297                 e_data.jitter_tx = create_jitter_texture();
298         }
299
300
301         /* Depth prepass */
302         if (!e_data.depth_sh) {
303                 e_data.depth_sh = DRW_shader_create_3D_depth_only();
304         }
305
306         /* Shading pass */
307         if (!e_data.clay_sh) {
308                 DynStr *ds = BLI_dynstr_new();
309                 const char *max_mat =
310                         "#define MAX_MATERIAL 512\n"
311                         "#define USE_ROTATION\n"
312                         "#define USE_AO\n"
313                         "#define USE_HSV\n";
314                 char *matcap_with_ao;
315
316                 BLI_dynstr_append(ds, datatoc_clay_frag_glsl);
317                 BLI_dynstr_append(ds, datatoc_ssao_alchemy_glsl);
318
319                 matcap_with_ao = BLI_dynstr_get_cstring(ds);
320
321                 e_data.clay_sh = DRW_shader_create(datatoc_clay_vert_glsl, NULL, matcap_with_ao, max_mat);
322
323                 BLI_dynstr_free(ds);
324                 MEM_freeN(matcap_with_ao);
325         }
326
327         if (!stl->storage) {
328                 stl->storage = MEM_callocN(sizeof(CLAY_Storage), "CLAY_Storage");
329         }
330
331         if (!stl->mat_ubo) {
332                 stl->mat_ubo = DRW_uniformbuffer_create(sizeof(CLAY_UBO_Storage), NULL);
333         }
334
335         if (e_data.ubo_mat_idxs[1] == 0) {
336                 /* Just int to have pointers to them */
337                 for (int i = 0; i < MAX_CLAY_MAT; ++i) {
338                         e_data.ubo_mat_idxs[i] = i;
339                 }
340         }
341
342         {
343                 const float *viewport_size = DRW_viewport_size_get();
344                 DRWFboTexture tex = {&txl->depth_dup, DRW_BUF_DEPTH_24, 0};
345                 DRW_framebuffer_init(&fbl->dupli_depth,
346                                      (int)viewport_size[0], (int)viewport_size[1],
347                                      &tex, 1);
348         }
349
350         /* SSAO setup */
351         {
352                 int ssao_samples = 32; /* XXX get from render settings */
353                 float invproj[4][4];
354                 float dfdyfacs[2];
355                 bool is_persp = DRW_viewport_is_persp_get();
356                 /* view vectors for the corners of the view frustum. Can be used to recreate the world space position easily */
357                 float viewvecs[3][4] = {
358                     {-1.0f, -1.0f, -1.0f, 1.0f},
359                     {1.0f, -1.0f, -1.0f, 1.0f},
360                     {-1.0f, 1.0f, -1.0f, 1.0f}
361                 };
362                 int i;
363                 const float *size = DRW_viewport_size_get();
364
365                 DRW_get_dfdy_factors(dfdyfacs);
366
367                 e_data.ssao_params[0] = ssao_samples;
368                 e_data.ssao_params[1] = size[0] / 64.0;
369                 e_data.ssao_params[2] = size[1] / 64.0;
370                 e_data.ssao_params[3] = dfdyfacs[1]; /* dfdy sign for offscreen */
371
372                 /* invert the view matrix */
373                 DRW_viewport_matrix_get(e_data.winmat, DRW_MAT_WIN);
374                 invert_m4_m4(invproj, e_data.winmat);
375
376                 /* convert the view vectors to view space */
377                 for (i = 0; i < 3; i++) {
378                         mul_m4_v4(invproj, viewvecs[i]);
379                         /* normalized trick see http://www.derschmale.com/2014/01/26/reconstructing-positions-from-the-depth-buffer */
380                         mul_v3_fl(viewvecs[i], 1.0f / viewvecs[i][3]);
381                         if (is_persp)
382                                 mul_v3_fl(viewvecs[i], 1.0f / viewvecs[i][2]);
383                         viewvecs[i][3] = 1.0;
384
385                         copy_v4_v4(e_data.viewvecs[i], viewvecs[i]);
386                 }
387
388                 /* we need to store the differences */
389                 e_data.viewvecs[1][0] -= e_data.viewvecs[0][0];
390                 e_data.viewvecs[1][1] = e_data.viewvecs[2][1] - e_data.viewvecs[0][1];
391
392                 /* calculate a depth offset as well */
393                 if (!is_persp) {
394                         float vec_far[] = {-1.0f, -1.0f, 1.0f, 1.0f};
395                         mul_m4_v4(invproj, vec_far);
396                         mul_v3_fl(vec_far, 1.0f / vec_far[3]);
397                         e_data.viewvecs[1][2] = vec_far[2] - e_data.viewvecs[0][2];
398                 }
399
400                 /* AO Samples Tex */
401                 if (e_data.sampling_tx && (e_data.cached_sample_num != ssao_samples)) {
402                         DRW_texture_free(e_data.sampling_tx);
403                         e_data.sampling_tx = NULL;
404                 }
405
406                 if (!e_data.sampling_tx) {
407                         e_data.sampling_tx = create_spiral_sample_texture(ssao_samples);
408                         e_data.cached_sample_num = ssao_samples;
409                 }
410         }
411 }
412
413 static DRWShadingGroup *CLAY_shgroup_create(CLAY_Data *vedata, DRWPass *pass, int *material_id)
414 {
415         CLAY_TextureList *txl = ((CLAY_Data *)vedata)->txl;
416         const int depthloc = 0, matcaploc = 1, jitterloc = 2, sampleloc = 3;
417
418         DRWShadingGroup *grp = DRW_shgroup_create(e_data.clay_sh, pass);
419
420         DRW_shgroup_uniform_vec2(grp, "screenres", DRW_viewport_size_get(), 1);
421         DRW_shgroup_uniform_buffer(grp, "depthtex", &txl->depth_dup, depthloc);
422         DRW_shgroup_uniform_texture(grp, "matcaps", e_data.matcap_array, matcaploc);
423         DRW_shgroup_uniform_mat4(grp, "WinMatrix", (float *)e_data.winmat);
424         DRW_shgroup_uniform_vec4(grp, "viewvecs", (float *)e_data.viewvecs, 3);
425         DRW_shgroup_uniform_vec4(grp, "ssao_params", e_data.ssao_params, 1);
426         DRW_shgroup_uniform_vec3(grp, "matcaps_color", (float *)e_data.matcap_colors, 24);
427
428         DRW_shgroup_uniform_int(grp, "mat_id", material_id, 1);
429
430         DRW_shgroup_uniform_texture(grp, "ssao_jitter", e_data.jitter_tx, jitterloc);
431         DRW_shgroup_uniform_texture(grp, "ssao_samples", e_data.sampling_tx, sampleloc);
432
433         return grp;
434 }
435
436 static int search_mat_to_ubo(CLAY_Storage *storage, float matcap_rot, float matcap_hue, float matcap_sat,
437                              float matcap_val, float ssao_distance, float ssao_factor_cavity,
438                              float ssao_factor_edge, float ssao_attenuation, int matcap_icon)
439 {
440         /* For now just use a linear search and test all parameters */
441         /* TODO make a hash table */
442         for (int i = 0; i < storage->ubo_current_id; ++i) {
443                 CLAY_UBO_Material *ubo = &storage->mat_storage.materials[i];
444
445                 if ((ubo->matcap_rot[0] == cosf(matcap_rot * 3.14159f * 2.0f)) &&
446                     (ubo->matcap_hsv[0] == matcap_hue + 0.5f) &&
447                     (ubo->matcap_hsv[1] == matcap_sat * 2.0f) &&
448                     (ubo->matcap_hsv[2] == matcap_val * 2.0f) &&
449                     (ubo->ssao_params_var[0] == ssao_distance) &&
450                     (ubo->ssao_params_var[1] == ssao_factor_cavity) &&
451                     (ubo->ssao_params_var[2] == ssao_factor_edge) &&
452                     (ubo->ssao_params_var[3] == ssao_attenuation) &&
453                     (ubo->matcap_id == matcap_to_index(matcap_icon)))
454                 {
455                         return i;
456                 }
457         }
458
459         return -1;
460 }
461
462 static int push_mat_to_ubo(CLAY_Storage *storage, float matcap_rot, float matcap_hue, float matcap_sat,
463                             float matcap_val, float ssao_distance, float ssao_factor_cavity,
464                             float ssao_factor_edge, float ssao_attenuation, int matcap_icon)
465 {
466         int id = storage->ubo_current_id;
467         CLAY_UBO_Material *ubo = &storage->mat_storage.materials[id];
468
469         ubo->matcap_rot[0] = cosf(matcap_rot * 3.14159f * 2.0f);
470         ubo->matcap_rot[1] = sinf(matcap_rot * 3.14159f * 2.0f);
471
472         ubo->matcap_hsv[0] = matcap_hue + 0.5f;
473         ubo->matcap_hsv[1] = matcap_sat * 2.0f;
474         ubo->matcap_hsv[2] = matcap_val * 2.0f;
475
476         /* small optimisation : make samples not spread if we don't need ssao */
477         ubo->ssao_params_var[0] = (ssao_factor_cavity + ssao_factor_edge > 0.0f) ? ssao_distance : 0.0f;
478         ubo->ssao_params_var[1] = ssao_factor_cavity;
479         ubo->ssao_params_var[2] = ssao_factor_edge;
480         ubo->ssao_params_var[3] = ssao_attenuation;
481
482         ubo->matcap_id = matcap_to_index(matcap_icon);
483
484         storage->ubo_current_id++;
485
486         return id;
487 }
488
489 static int mat_in_ubo(CLAY_Storage *storage, float matcap_rot, float matcap_hue, float matcap_sat,
490                       float matcap_val, float ssao_distance, float ssao_factor_cavity,
491                       float ssao_factor_edge, float ssao_attenuation, int matcap_icon)
492 {
493         /* Search material in UBO */
494         int id = search_mat_to_ubo(storage, matcap_rot, matcap_hue, matcap_sat, matcap_val,
495                                    ssao_distance, ssao_factor_cavity, ssao_factor_edge,
496                                    ssao_attenuation, matcap_icon);
497
498         /* if not found create it */
499         if (id == -1) {
500                 id = push_mat_to_ubo(storage, matcap_rot, matcap_hue, matcap_sat, matcap_val,
501                                      ssao_distance, ssao_factor_cavity, ssao_factor_edge,
502                                      ssao_attenuation, matcap_icon);
503         }
504
505         return id;
506 }
507
508 static DRWShadingGroup *CLAY_object_shgrp_get(CLAY_Data *vedata, Object *ob, CLAY_StorageList *stl, CLAY_PassList *psl)
509 {
510         DRWShadingGroup **shgrps = stl->storage->shgrps;
511         IDProperty *props = BKE_object_collection_engine_get(ob, COLLECTION_MODE_NONE, RE_engine_id_BLENDER_CLAY);
512
513         /* Default Settings */
514         float matcap_rot = BKE_collection_engine_property_value_get_float(props, "matcap_rotation");
515         float matcap_hue = BKE_collection_engine_property_value_get_float(props, "matcap_hue");
516         float matcap_sat = BKE_collection_engine_property_value_get_float(props, "matcap_saturation");
517         float matcap_val = BKE_collection_engine_property_value_get_float(props, "matcap_value");
518         float ssao_distance = BKE_collection_engine_property_value_get_float(props, "ssao_distance");
519         float ssao_factor_cavity = BKE_collection_engine_property_value_get_float(props, "ssao_factor_cavity");
520         float ssao_factor_edge = BKE_collection_engine_property_value_get_float(props, "ssao_factor_edge");
521         float ssao_attenuation = BKE_collection_engine_property_value_get_float(props, "ssao_attenuation");
522         int matcap_icon = BKE_collection_engine_property_value_get_int(props, "matcap_icon");
523
524         int id = mat_in_ubo(stl->storage, matcap_rot, matcap_hue, matcap_sat, matcap_val,
525                             ssao_distance, ssao_factor_cavity, ssao_factor_edge,
526                             ssao_attenuation, matcap_icon);
527
528         if (shgrps[id] == NULL) {
529                 shgrps[id] = CLAY_shgroup_create(vedata, psl->clay_pass, &e_data.ubo_mat_idxs[id]);
530                 /* if it's the first shgrp, pass bind the material UBO */
531                 if (stl->storage->ubo_current_id == 1) {
532                         DRW_shgroup_uniform_block(shgrps[0], "material_block", stl->mat_ubo, 0);
533                 }
534         }
535
536         return shgrps[id];
537 }
538
539 static void CLAY_cache_init(void *vedata)
540 {
541         CLAY_PassList *psl = ((CLAY_Data *)vedata)->psl;
542         CLAY_StorageList *stl = ((CLAY_Data *)vedata)->stl;
543
544         if (!stl->g_data) {
545                 /* Alloc transient pointers */
546                 stl->g_data = MEM_mallocN(sizeof(g_data), "g_data");
547         }
548
549         /* Depth Pass */
550         {
551                 psl->depth_pass = DRW_pass_create("Depth Pass", DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS);
552                 stl->g_data->depth_shgrp = DRW_shgroup_create(e_data.depth_sh, psl->depth_pass);
553
554                 psl->depth_pass_cull = DRW_pass_create("Depth Pass Cull", DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS | DRW_STATE_CULL_BACK);
555                 stl->g_data->depth_shgrp_cull = DRW_shgroup_create(e_data.depth_sh, psl->depth_pass_cull);
556         }
557
558         /* Clay Pass */
559         {
560                 psl->clay_pass = DRW_pass_create("Clay Pass", DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_EQUAL);
561                 stl->storage->ubo_current_id = 0;
562                 memset(stl->storage->shgrps, 0, sizeof(DRWShadingGroup *) * MAX_CLAY_MAT);
563         }
564 }
565
566 static void CLAY_cache_populate(void *vedata, Object *ob)
567 {
568         CLAY_PassList *psl = ((CLAY_Data *)vedata)->psl;
569         CLAY_StorageList *stl = ((CLAY_Data *)vedata)->stl;
570
571         struct Batch *geom;
572         DRWShadingGroup *clay_shgrp;
573
574         if (!DRW_is_object_renderable(ob))
575                 return;
576
577         IDProperty *ces_mode_ob = BKE_object_collection_engine_get(ob, COLLECTION_MODE_OBJECT, "");
578         bool do_cull = BKE_collection_engine_property_value_get_bool(ces_mode_ob, "show_backface_culling");
579
580         /* TODO all renderable */
581         if (ob->type == OB_MESH) {
582                 geom = DRW_cache_surface_get(ob);
583
584                 /* Depth Prepass */
585                 DRW_shgroup_call_add((do_cull) ? stl->g_data->depth_shgrp_cull : stl->g_data->depth_shgrp, geom, ob->obmat);
586
587                 /* Shading */
588                 clay_shgrp = CLAY_object_shgrp_get(vedata, ob, stl, psl);
589                 DRW_shgroup_call_add(clay_shgrp, geom, ob->obmat);
590         }
591 }
592
593 static void CLAY_cache_finish(void *vedata)
594 {
595         CLAY_StorageList *stl = ((CLAY_Data *)vedata)->stl;
596
597         DRW_uniformbuffer_update(stl->mat_ubo, &stl->storage->mat_storage);
598 }
599
600 static void CLAY_draw_scene(void *vedata)
601 {
602
603         CLAY_PassList *psl = ((CLAY_Data *)vedata)->psl;
604         CLAY_FramebufferList *fbl = ((CLAY_Data *)vedata)->fbl;
605         DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get();
606
607         /* Pass 1 : Depth pre-pass */
608         DRW_draw_pass(psl->depth_pass);
609         DRW_draw_pass(psl->depth_pass_cull);
610
611         /* Pass 2 : Duplicate depth */
612         /* Unless we go for deferred shading we need this to avoid manual depth test and artifacts */
613         DRW_framebuffer_blit(dfbl->default_fb, fbl->dupli_depth, true);
614
615         /* Pass 3 : Shading */
616         DRW_draw_pass(psl->clay_pass);
617 }
618
619 static void CLAY_collection_settings_create(RenderEngine *UNUSED(engine), IDProperty *props)
620 {
621         BLI_assert(props &&
622                    props->type == IDP_GROUP &&
623                    props->subtype == IDP_GROUP_SUB_ENGINE_RENDER);
624
625         BKE_collection_engine_property_add_int(props, "matcap_icon", ICON_MATCAP_01);
626         BKE_collection_engine_property_add_int(props, "type", CLAY_MATCAP_NONE);
627         BKE_collection_engine_property_add_float(props, "matcap_rotation", 0.0f);
628         BKE_collection_engine_property_add_float(props, "matcap_hue", 0.5f);
629         BKE_collection_engine_property_add_float(props, "matcap_saturation", 0.5f);
630         BKE_collection_engine_property_add_float(props, "matcap_value", 0.5f);
631         BKE_collection_engine_property_add_float(props, "ssao_distance", 0.2f);
632         BKE_collection_engine_property_add_float(props, "ssao_attenuation", 1.0f);
633         BKE_collection_engine_property_add_float(props, "ssao_factor_cavity", 1.0f);
634         BKE_collection_engine_property_add_float(props, "ssao_factor_edge", 1.0f);
635 }
636
637 static void CLAY_engine_free(void)
638 {
639         if (e_data.clay_sh) {
640                 DRW_shader_free(e_data.clay_sh);
641         }
642         if (e_data.matcap_array) {
643                 DRW_texture_free(e_data.matcap_array);
644         }
645         if (e_data.jitter_tx) {
646                 DRW_texture_free(e_data.jitter_tx);
647         }
648         if (e_data.sampling_tx) {
649                 DRW_texture_free(e_data.sampling_tx);
650         }
651 }
652
653 DrawEngineType draw_engine_clay_type = {
654         NULL, NULL,
655         N_("Clay"),
656         &CLAY_engine_init,
657         &CLAY_engine_free,
658         &CLAY_cache_init,
659         &CLAY_cache_populate,
660         &CLAY_cache_finish,
661         NULL,
662         &CLAY_draw_scene
663 };
664
665 RenderEngineType viewport_clay_type = {
666         NULL, NULL,
667         CLAY_ENGINE, N_("Clay"), RE_INTERNAL | RE_USE_OGL_PIPELINE,
668         NULL, NULL, NULL, NULL, NULL, NULL, &CLAY_collection_settings_create,
669         &draw_engine_clay_type,
670         {NULL, NULL, NULL}
671 };
672
673
674 #undef CLAY_ENGINE
675
676 #endif