844cd5b4ec416c55c4c34131d414d06c73fcc56d
[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_main.h"
26
27 #include "BLI_dynstr.h"
28 #include "BLI_rand.h"
29
30 #include "IMB_imbuf.h"
31 #include "IMB_imbuf_types.h"
32
33 #include "UI_resources.h"
34 #include "UI_interface_icons.h"
35
36 #include "clay.h"
37
38 /* Shaders */
39
40 extern char datatoc_clay_frag_glsl[];
41 extern char datatoc_clay_vert_glsl[];
42 extern char datatoc_ssao_alchemy_glsl[];
43 extern char datatoc_ssao_groundtruth_glsl[];
44
45 /* Storage */
46
47 /* UBOs data needs to be 16 byte aligned (size of vec4) */
48 /* Reminder : float, int, bool are 4 bytes */
49 typedef struct CLAY_UBO_Material {
50         float ssao_params_var[4];
51         /* - 16 -*/
52         float matcap_hsv[3];
53         float matcap_id; /* even float encoding have enough precision */
54         /* - 16 -*/
55         float matcap_rot[2];
56         float pad[2]; /* ensure 16 bytes alignement */
57 } CLAY_UBO_Material; /* 48 bytes */
58
59 typedef struct CLAY_UBO_Storage {
60         CLAY_UBO_Material materials[512]; /* 512 = 9 bit material id */
61 } CLAY_UBO_Storage;
62
63 static struct CLAY_data {
64         /* Depth Pre Pass */
65         struct GPUShader *depth_sh;
66         /* Shading Pass */
67         struct GPUShader *clay_sh;
68
69         /* Materials Parameter UBO */
70         struct GPUUniformBuffer *mat_ubo;
71         CLAY_UBO_Storage mat_storage;
72         short ubo_flag;
73
74         /* Matcap textures */
75         struct GPUTexture *matcap_array;
76         float matcap_colors[24][3];
77
78         /* Ssao */
79         float winmat[4][4];
80         float viewvecs[3][4];
81         float ssao_params[4];
82         struct GPUTexture *jitter_tx;
83         struct GPUTexture *sampling_tx;
84 } data = {NULL};
85
86 /* CLAY_data.ubo_flag */
87 #define CLAY_UBO_CLEAR     (1 << 0)
88 #define CLAY_UBO_REFRESH   (1 << 1)
89
90 /* keep it under MAX_BUFFERS */
91 typedef struct CLAY_FramebufferList{
92         /* default */
93         struct GPUFrameBuffer *default_fb;
94         /* engine specific */
95         struct GPUFrameBuffer *downsample_depth;
96 } CLAY_FramebufferList;
97
98 /* keep it under MAX_TEXTURES */
99 typedef struct CLAY_TextureList{
100         /* default */
101         struct GPUTexture *color;
102         struct GPUTexture *depth;
103         /* engine specific */
104         struct GPUTexture *depth_low;
105 } CLAY_TextureList;
106
107 /* for clarity follow the same layout as CLAY_TextureList */
108 #define SCENE_COLOR 0
109 #define SCENE_DEPTH 1
110 #define SCENE_DEPTH_LOW 2
111
112 /* keep it under MAX_PASSES */
113 typedef struct CLAY_PassList{
114         /* default */
115         struct DRWPass *non_meshes_pass;
116         struct DRWPass *ob_center_pass;
117         /* engine specific */
118         struct DRWPass *depth_pass;
119         struct DRWPass *clay_pass;
120         struct DRWPass *wire_overlay_pass;
121         struct DRWPass *wire_outline_pass;
122 } CLAY_PassList;
123
124 //#define GTAO
125
126 /* Functions */
127
128 static void add_icon_to_rect(PreviewImage *prv, float *final_rect, int layer)
129 {
130         int image_size = prv->w[0] * prv->h[0];
131         float *new_rect = &final_rect[image_size * 4 * layer];
132
133         IMB_buffer_float_from_byte(new_rect, (unsigned char *)prv->rect[0], IB_PROFILE_SRGB, IB_PROFILE_SRGB,
134                                    false, prv->w[0], prv->h[0], prv->w[0], prv->w[0]);
135
136         /* Find overall color */
137         for (int y = 0; y < 4; ++y)     {
138                 for (int x = 0; x < 4; ++x) {
139                         data.matcap_colors[layer][0] += new_rect[y * 512 * 128 * 4 + x * 128 * 4 + 0];
140                         data.matcap_colors[layer][1] += new_rect[y * 512 * 128 * 4 + x * 128 * 4 + 1];
141                         data.matcap_colors[layer][2] += new_rect[y * 512 * 128 * 4 + x * 128 * 4 + 2];
142                 }
143         }
144
145         data.matcap_colors[layer][0] /= 16.0f * 2.0f; /* the * 2 is to darken for shadows */
146         data.matcap_colors[layer][1] /= 16.0f * 2.0f;
147         data.matcap_colors[layer][2] /= 16.0f * 2.0f;
148 }
149
150 static struct GPUTexture *load_matcaps(PreviewImage *prv[24], int nbr)
151 {
152         struct GPUTexture *tex;
153         int w = prv[0]->w[0];
154         int h = prv[0]->h[0];
155         float *final_rect = MEM_callocN(sizeof(float) * 4 * w * h * nbr, "Clay Matcap array rect");
156
157         for (int i = 0; i < nbr; ++i) {
158                 add_icon_to_rect(prv[i], final_rect, i);
159                 BKE_previewimg_free(&prv[i]);
160         }
161
162         tex = DRW_texture_create_2D_array(w, h, nbr, DRW_TEX_RGBA_8, DRW_TEX_FILTER, final_rect);
163         MEM_freeN(final_rect);
164
165         return tex;
166 }
167
168 static int matcap_to_index(int matcap)
169 {
170         if (matcap == ICON_MATCAP_02) return 1;
171         else if (matcap == ICON_MATCAP_03) return 2;
172         else if (matcap == ICON_MATCAP_04) return 3;
173         else if (matcap == ICON_MATCAP_05) return 4;
174         else if (matcap == ICON_MATCAP_06) return 5;
175         else if (matcap == ICON_MATCAP_07) return 6;
176         else if (matcap == ICON_MATCAP_08) return 7;
177         else if (matcap == ICON_MATCAP_09) return 8;
178         else if (matcap == ICON_MATCAP_10) return 9;
179         else if (matcap == ICON_MATCAP_11) return 10;
180         else if (matcap == ICON_MATCAP_12) return 11;
181         else if (matcap == ICON_MATCAP_13) return 12;
182         else if (matcap == ICON_MATCAP_14) return 13;
183         else if (matcap == ICON_MATCAP_15) return 14;
184         else if (matcap == ICON_MATCAP_16) return 15;
185         else if (matcap == ICON_MATCAP_17) return 16;
186         else if (matcap == ICON_MATCAP_18) return 17;
187         else if (matcap == ICON_MATCAP_19) return 18;
188         else if (matcap == ICON_MATCAP_20) return 19;
189         else if (matcap == ICON_MATCAP_21) return 20;
190         else if (matcap == ICON_MATCAP_22) return 21;
191         else if (matcap == ICON_MATCAP_23) return 22;
192         else if (matcap == ICON_MATCAP_24) return 23;
193         return 0;
194 }
195
196 static struct GPUTexture *create_spiral_sample_texture(int numsaples)
197 {
198         struct GPUTexture *tex;
199         float (*texels)[2] = MEM_mallocN(sizeof(float[2]) * numsaples, "concentric_tex");
200         const float numsaples_inv = 1.0f / numsaples;
201         int i;
202         /* arbitrary number to ensure we don't get conciding samples every circle */
203         const float spirals = 7.357;
204
205         for (i = 0; i < numsaples; i++) {
206                 float r = (i + 0.5f) * numsaples_inv;
207                 float phi = r * spirals * (float)(2.0 * M_PI);
208                 texels[i][0] = r * cosf(phi);
209                 texels[i][1] = r * sinf(phi);
210         }
211
212         tex = DRW_texture_create_1D(numsaples, DRW_TEX_RG_16, 0, (float *)texels);
213
214         MEM_freeN(texels);
215         return tex;
216 }
217
218 static struct GPUTexture *create_jitter_texture(void)
219 {
220         float jitter[64 * 64][2];
221         int i;
222
223         /* TODO replace by something more evenly distributed like blue noise */
224         for (i = 0; i < 64 * 64; i++) {
225 #ifdef GTAO
226                 jitter[i][0] = BLI_frand();
227                 jitter[i][1] = BLI_frand();
228 #else
229                 jitter[i][0] = 2.0f * BLI_frand() - 1.0f;
230                 jitter[i][1] = 2.0f * BLI_frand() - 1.0f;
231                 normalize_v2(jitter[i]);
232 #endif
233         }
234
235         return DRW_texture_create_2D(64, 64, DRW_TEX_RG_16, DRW_TEX_FILTER | DRW_TEX_WRAP, &jitter[0][0]);
236 }
237
238 static void clay_material_settings_init(MaterialEngineSettingsClay *ma)
239 {
240         ma->matcap_icon = ICON_MATCAP_01;
241         ma->matcap_rot = 0.0f;
242         ma->matcap_hue = 0.5f;
243         ma->matcap_sat = 0.5f;
244         ma->matcap_val = 0.5f;
245         ma->ssao_distance = 0.2;
246         ma->ssao_attenuation = 1.0f;
247         ma->ssao_factor_cavity = 1.0f;
248         ma->ssao_factor_edge = 1.0f;
249 }
250
251 RenderEngineSettings *CLAY_render_settings_create(void)
252 {
253         RenderEngineSettingsClay *settings = MEM_callocN(sizeof(RenderEngineSettingsClay), "RenderEngineSettingsClay");
254
255         clay_material_settings_init((MaterialEngineSettingsClay *)settings);
256
257         settings->ssao_samples = 32;
258
259         return (RenderEngineSettings *)settings;
260 }
261
262 MaterialEngineSettings *CLAY_material_settings_create(void)
263 {
264         MaterialEngineSettingsClay *settings = MEM_callocN(sizeof(MaterialEngineSettingsClay), "MaterialEngineSettingsClay");
265
266         clay_material_settings_init(settings);
267
268         return (MaterialEngineSettings *)settings;
269 }
270
271 static void CLAY_engine_init(void)
272 {
273         /* Create Texture Array */
274         if (!data.matcap_array) {
275                 PreviewImage *prv[24]; /* For now use all of the 24 internal matcaps */
276
277                 /* TODO only load used matcaps */
278                 prv[0]  = UI_icon_to_preview(ICON_MATCAP_01);
279                 prv[1]  = UI_icon_to_preview(ICON_MATCAP_02);
280                 prv[2]  = UI_icon_to_preview(ICON_MATCAP_03);
281                 prv[3]  = UI_icon_to_preview(ICON_MATCAP_04);
282                 prv[4]  = UI_icon_to_preview(ICON_MATCAP_05);
283                 prv[5]  = UI_icon_to_preview(ICON_MATCAP_06);
284                 prv[6]  = UI_icon_to_preview(ICON_MATCAP_07);
285                 prv[7]  = UI_icon_to_preview(ICON_MATCAP_08);
286                 prv[8]  = UI_icon_to_preview(ICON_MATCAP_09);
287                 prv[9]  = UI_icon_to_preview(ICON_MATCAP_10);
288                 prv[10] = UI_icon_to_preview(ICON_MATCAP_11);
289                 prv[11] = UI_icon_to_preview(ICON_MATCAP_12);
290                 prv[12] = UI_icon_to_preview(ICON_MATCAP_13);
291                 prv[13] = UI_icon_to_preview(ICON_MATCAP_14);
292                 prv[14] = UI_icon_to_preview(ICON_MATCAP_15);
293                 prv[15] = UI_icon_to_preview(ICON_MATCAP_16);
294                 prv[16] = UI_icon_to_preview(ICON_MATCAP_17);
295                 prv[17] = UI_icon_to_preview(ICON_MATCAP_18);
296                 prv[18] = UI_icon_to_preview(ICON_MATCAP_19);
297                 prv[19] = UI_icon_to_preview(ICON_MATCAP_20);
298                 prv[20] = UI_icon_to_preview(ICON_MATCAP_21);
299                 prv[21] = UI_icon_to_preview(ICON_MATCAP_22);
300                 prv[22] = UI_icon_to_preview(ICON_MATCAP_23);
301                 prv[23] = UI_icon_to_preview(ICON_MATCAP_24);
302
303                 data.matcap_array = load_matcaps(prv, 24);
304         }
305
306         /* AO Jitter */
307         if (!data.jitter_tx) {
308                 data.jitter_tx = create_jitter_texture();
309         }
310
311         /* AO Samples */
312         /* TODO use hammersley sequence */
313         if (!data.sampling_tx) {
314                 data.sampling_tx = create_spiral_sample_texture(500);
315         }
316
317         /* Depth prepass */
318         if (!data.depth_sh) {
319                 data.depth_sh = DRW_shader_create_3D_depth_only();
320         }
321
322         if (!data.mat_ubo) {
323                 data.mat_ubo = DRW_uniformbuffer_create(sizeof(CLAY_UBO_Storage), NULL);
324         }
325
326         /* Shading pass */
327         if (!data.clay_sh) {
328                 DynStr *ds = BLI_dynstr_new();
329                 const char *max_mat =
330                         "#define MAX_MATERIAL 512\n"
331                         "#define USE_ROTATION\n"
332                         "#define USE_AO\n"
333                         "#define USE_HSV\n";
334                 char *matcap_with_ao;
335
336                 BLI_dynstr_append(ds, datatoc_clay_frag_glsl);
337 #ifdef GTAO
338                 BLI_dynstr_append(ds, datatoc_ssao_groundtruth_glsl);
339 #else
340                 BLI_dynstr_append(ds, datatoc_ssao_alchemy_glsl);
341 #endif
342
343                 matcap_with_ao = BLI_dynstr_get_cstring(ds);
344
345                 data.clay_sh = DRW_shader_create(datatoc_clay_vert_glsl, NULL, matcap_with_ao, max_mat);
346
347                 BLI_dynstr_free(ds);
348                 MEM_freeN(matcap_with_ao);
349         }
350 }
351
352 static void CLAY_ssao_setup(void)
353 {
354         float invproj[4][4];
355         float dfdyfacs[2];
356         bool is_persp = DRW_viewport_is_persp_get();
357         /* view vectors for the corners of the view frustum. Can be used to recreate the world space position easily */
358         float viewvecs[3][4] = {
359             {-1.0f, -1.0f, -1.0f, 1.0f},
360             {1.0f, -1.0f, -1.0f, 1.0f},
361             {-1.0f, 1.0f, -1.0f, 1.0f}
362         };
363         int i;
364         float *size = DRW_viewport_size_get();
365         RenderEngineSettingsClay *settings = DRW_render_settings_get(NULL, RE_engine_id_BLENDER_CLAY, NULL);
366
367         DRW_get_dfdy_factors(dfdyfacs);
368
369         data.ssao_params[0] = settings->ssao_samples;
370         data.ssao_params[1] = size[0] / 64.0;
371         data.ssao_params[2] = size[1] / 64.0;
372         data.ssao_params[3] = dfdyfacs[1]; /* dfdy sign for offscreen */
373
374         /* invert the view matrix */
375         DRW_viewport_matrix_get(data.winmat, DRW_MAT_WIN);
376         invert_m4_m4(invproj, data.winmat);
377
378         /* convert the view vectors to view space */
379         for (i = 0; i < 3; i++) {
380                 mul_m4_v4(invproj, viewvecs[i]);
381                 /* normalized trick see http://www.derschmale.com/2014/01/26/reconstructing-positions-from-the-depth-buffer */
382                 mul_v3_fl(viewvecs[i], 1.0f / viewvecs[i][3]);
383                 if (is_persp)
384                         mul_v3_fl(viewvecs[i], 1.0f / viewvecs[i][2]);
385                 viewvecs[i][3] = 1.0;
386
387                 copy_v4_v4(data.viewvecs[i], viewvecs[i]);
388         }
389
390         /* we need to store the differences */
391         data.viewvecs[1][0] -= data.viewvecs[0][0];
392         data.viewvecs[1][1] = data.viewvecs[2][1] - data.viewvecs[0][1];
393
394         /* calculate a depth offset as well */
395         if (!is_persp) {
396                 float vec_far[] = {-1.0f, -1.0f, 1.0f, 1.0f};
397                 mul_m4_v4(invproj, vec_far);
398                 mul_v3_fl(vec_far, 1.0f / vec_far[3]);
399                 data.viewvecs[1][2] = vec_far[2] - data.viewvecs[0][2];
400         }
401 }
402
403 static DRWShadingGroup *CLAY_shgroup_create(DRWPass *pass, int *UNUSED(material_id))
404 {
405         const int depthloc = 0, matcaploc = 1, jitterloc = 2, sampleloc = 3;
406
407         //CLAY_UBO_Material *mat = &data.mat_storage.materials[0];
408         DRWShadingGroup *grp = DRW_shgroup_create(data.clay_sh, pass);
409
410         DRW_shgroup_uniform_vec2(grp, "screenres", DRW_viewport_size_get(), 1);
411         DRW_shgroup_uniform_buffer(grp, "depthtex", SCENE_DEPTH, depthloc);
412         DRW_shgroup_uniform_texture(grp, "matcaps", data.matcap_array, matcaploc);
413         DRW_shgroup_uniform_mat4(grp, "WinMatrix", (float *)data.winmat);
414         DRW_shgroup_uniform_vec4(grp, "viewvecs", (float *)data.viewvecs, 3);
415         DRW_shgroup_uniform_vec4(grp, "ssao_params", data.ssao_params, 1);
416         DRW_shgroup_uniform_vec3(grp, "matcaps_color", (float *)data.matcap_colors, 24);
417
418         //DRW_shgroup_uniform_int(grp, "material_id", material_id, 1);
419
420 #ifndef GTAO
421         DRW_shgroup_uniform_texture(grp, "ssao_jitter", data.jitter_tx, jitterloc);
422         DRW_shgroup_uniform_texture(grp, "ssao_samples", data.sampling_tx, sampleloc);
423 #endif
424
425         return grp;
426 }
427
428 static void CLAY_update_material_runtime(MaterialEngineSettingsClay *settings, MaterialRuntimeClay **runtime)
429 {
430         MaterialRuntimeClay *rt;
431
432         if (*runtime == NULL) {
433                 rt = MEM_mallocN(sizeof(MaterialRuntimeClay), "MaterialRuntimeClay");
434                 rt->flag = CLAY_OUTDATED;
435                 data.ubo_flag |= CLAY_UBO_CLEAR;
436                 *runtime = rt;
437         }
438
439         rt = *runtime;
440
441         if (rt->flag & CLAY_OUTDATED) {
442
443                 /* Update default material */
444                 rt->matcap_rot[0] = cosf(settings->matcap_rot * 3.14159f * 2.0f);
445                 rt->matcap_rot[1] = sinf(settings->matcap_rot * 3.14159f * 2.0f);
446
447                 rt->matcap_hsv[0] = settings->matcap_hue + 0.5f;
448                 rt->matcap_hsv[1] = settings->matcap_sat * 2.0f;
449                 rt->matcap_hsv[2] = settings->matcap_val * 2.0f;
450
451                 rt->ssao_params_var[0] = settings->ssao_distance;
452                 rt->ssao_params_var[1] = settings->ssao_factor_cavity;
453                 rt->ssao_params_var[2] = settings->ssao_factor_edge;
454                 rt->ssao_params_var[3] = settings->ssao_attenuation;
455
456                 if (settings->matcap_icon < ICON_MATCAP_01 ||
457                     settings->matcap_icon > ICON_MATCAP_24)
458                 {
459                         settings->matcap_icon = ICON_MATCAP_01;
460                 }
461
462                 rt->matcap_id = matcap_to_index(settings->matcap_icon);
463
464                 if ((rt->type != settings->type)) {
465                         data.ubo_flag |= CLAY_UBO_CLEAR;
466                 }
467
468                 rt->type = settings->type;
469
470                 data.ubo_flag |= CLAY_UBO_REFRESH;
471                 rt->flag &= ~CLAY_OUTDATED;
472         }
473 }
474
475 static void update_ubo_storage(MaterialRuntimeClay *runtime, unsigned int current_id)
476 {
477         CLAY_UBO_Material *ubo = &data.mat_storage.materials[current_id];
478
479         ubo->matcap_id = runtime->matcap_id;
480         copy_v3_v3(ubo->matcap_hsv, runtime->matcap_hsv);
481         copy_v2_v2(ubo->matcap_rot, runtime->matcap_rot);
482         copy_v4_v4(ubo->ssao_params_var, runtime->ssao_params_var);
483
484         runtime->material_id = current_id;
485 }
486
487 static void CLAY_update_material_ubo(const struct bContext *C)
488 {
489         Main *bmain = CTX_data_main(C);
490         MaterialRuntimeClay **runtime;
491
492         /* Update Default materials */
493         for (Scene *sce = bmain->scene.first; sce; sce = sce->id.next) {
494                 /* Using render settings as material settings */
495                 MaterialEngineSettingsClay *res = DRW_render_settings_get(sce, RE_engine_id_BLENDER_CLAY, (void ***)&runtime);
496                 CLAY_update_material_runtime(res, runtime);
497         }
498
499         /* Update Scene Materials */
500         for (Material *mat = bmain->mat.first; mat; mat = mat->id.next) {
501                 MaterialEngineSettingsClay *mesc = DRW_material_settings_get(mat, RE_engine_id_BLENDER_CLAY, (void ***)&runtime);
502                 CLAY_update_material_runtime(mesc, runtime);
503         }
504
505         if (data.ubo_flag & CLAY_UBO_REFRESH) {
506                 int current_id = 0;
507
508                 /* Default materials */
509                 for (Scene *sce = bmain->scene.first; sce; sce = sce->id.next) {
510                         DRW_render_settings_get(sce, RE_engine_id_BLENDER_CLAY, (void ***)&runtime);
511                         update_ubo_storage(*runtime, current_id);
512                         current_id++;
513                 }
514
515                 /* TODO only add materials linked to geometry */
516                 for (Material *mat = bmain->mat.first; mat; mat = mat->id.next) {
517                         DRW_material_settings_get(mat, RE_engine_id_BLENDER_CLAY, (void ***)&runtime);
518                         update_ubo_storage(*runtime, current_id);
519                         current_id++;
520                 }
521
522                 DRW_uniformbuffer_update(data.mat_ubo, &data.mat_storage);
523         }
524
525         data.ubo_flag = 0;
526 }
527
528 static void CLAY_create_cache(CLAY_PassList *passes, const struct bContext *C)
529 {
530         SceneLayer *sl = CTX_data_scene_layer(C);
531         DRWShadingGroup *default_shgrp, *depthbatch;
532
533         /* Depth Pass */
534         {
535                 passes->depth_pass = DRW_pass_create("Depth Pass", DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS);
536
537                 depthbatch = DRW_shgroup_create(data.depth_sh, passes->depth_pass);
538         }
539
540         /* Clay Pass */
541         {
542                 MaterialRuntimeClay **runtime;
543                 DRW_render_settings_get(NULL, RE_engine_id_BLENDER_CLAY, (void ***)&runtime);
544
545                 passes->clay_pass = DRW_pass_create("Clay Pass", DRW_STATE_WRITE_COLOR);
546
547                 default_shgrp = CLAY_shgroup_create(passes->clay_pass, &(*runtime)->material_id);
548                 DRW_shgroup_uniform_block(default_shgrp, "material_block", data.mat_ubo, 0);
549         }
550
551         /* Object Mode */
552         {
553                 DRW_pass_setup_common(&passes->wire_overlay_pass,
554                                           &passes->wire_outline_pass,
555                                           &passes->non_meshes_pass,
556                                           &passes->ob_center_pass);
557         }
558
559         /* TODO Create hash table of batch based on material id*/
560         Object *ob;
561         DEG_OBJECT_ITER(sl, ob)
562         {
563                 if ((ob->base_flag & BASE_VISIBLED) == 0) {
564                         continue;
565                 }
566
567                 struct Batch *geom;
568                 switch (ob->type) {
569                         case OB_MESH:
570                                 geom = DRW_cache_surface_get(ob);
571
572                                 /* Add everything for now */
573                                 DRW_shgroup_call_add(depthbatch, geom, ob->obmat);
574                                 DRW_shgroup_call_add(default_shgrp, geom, ob->obmat);
575
576                                 /* When encountering a new material :
577                                  * - Create new Batch
578                                  * - Initialize Batch
579                                  * - Push it to the hash table
580                                  * - The pass takes care of inserting it
581                                  * next to the same shader calls */
582
583                                 /* Free hash table */
584                                 break;
585                         case OB_LAMP:
586                         case OB_CAMERA:
587                         case OB_EMPTY:
588                         default:
589                             DRW_shgroup_non_meshes(passes->non_meshes_pass, ob);
590                                 break;
591                 }
592
593                 DRW_shgroup_object_center(passes->ob_center_pass, ob);
594                 DRW_shgroup_relationship_lines(passes->non_meshes_pass, ob);
595         }
596         DEG_OBJECT_ITER_END
597 }
598
599 static void CLAY_view_draw(RenderEngine *UNUSED(engine), const struct bContext *context)
600 {
601         /* This function may run for multiple viewports
602          * so get the current viewport buffers */
603         CLAY_FramebufferList *buffers = NULL;
604         CLAY_TextureList *textures = NULL;
605         CLAY_PassList *passes = NULL;
606
607         DRW_viewport_init(context, (void **)&buffers, (void **)&textures, (void **)&passes);
608
609         CLAY_engine_init();
610
611         CLAY_update_material_ubo(context);
612
613         /* TODO : tag to refresh by the deps graph */
614         /* ideally only refresh when objects are added/removed */
615         /* or render properties / materials change */
616 #ifdef WITH_VIEWPORT_CACHE_TEST
617         static bool once = false;
618 #endif
619         if (DRW_viewport_cache_is_dirty()
620 #ifdef WITH_VIEWPORT_CACHE_TEST
621                 && !once
622 #endif
623                 ) {
624 #ifdef WITH_VIEWPORT_CACHE_TEST
625                 once = true;
626 #endif
627                 CLAY_create_cache(passes, context);
628         }
629
630         /* Start Drawing */
631         DRW_draw_background();
632
633         /* Pass 1 : Depth pre-pass */
634         DRW_draw_pass(passes->depth_pass);
635
636         /* Pass 2 (Optionnal) : Separated Downsampled AO */
637         DRW_framebuffer_texture_detach(textures->depth);
638         /* TODO */
639
640         /* Pass 3 : Shading */
641         CLAY_ssao_setup();
642         DRW_draw_pass(passes->clay_pass);
643
644         /* Pass 4 : Overlays */
645         DRW_framebuffer_texture_attach(buffers->default_fb, textures->depth, 0);
646         DRW_draw_pass(passes->non_meshes_pass);
647         DRW_draw_pass(passes->ob_center_pass);
648
649         /* Always finish by this */
650         DRW_state_reset();
651 }
652
653 void clay_engine_free(void)
654 {
655         /* data.depth_sh Is builtin so it's automaticaly freed */
656         if (data.clay_sh) {
657                 DRW_shader_free(data.clay_sh);
658         }
659
660         if (data.matcap_array) {
661                 DRW_texture_free(data.matcap_array);
662         }
663
664         if (data.jitter_tx) {
665                 DRW_texture_free(data.jitter_tx);
666         }
667
668         if (data.sampling_tx) {
669                 DRW_texture_free(data.sampling_tx);
670         }
671
672         if (data.mat_ubo) {
673                 DRW_uniformbuffer_free(data.mat_ubo);
674         }
675 }
676
677 RenderEngineType viewport_clay_type = {
678         NULL, NULL,
679         "BLENDER_CLAY", N_("Clay"), RE_INTERNAL | RE_USE_OGL_PIPELINE,
680         NULL, NULL, NULL, NULL, &CLAY_view_draw, NULL,
681         {NULL, NULL, NULL}
682 };