diff options
Diffstat (limited to 'source/blender/draw/engines/clay/clay.c')
-rw-r--r-- | source/blender/draw/engines/clay/clay.c | 722 |
1 files changed, 722 insertions, 0 deletions
diff --git a/source/blender/draw/engines/clay/clay.c b/source/blender/draw/engines/clay/clay.c new file mode 100644 index 00000000000..f443606f11d --- /dev/null +++ b/source/blender/draw/engines/clay/clay.c @@ -0,0 +1,722 @@ +/* + * Copyright 2016, Blender Foundation. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Contributor(s): Blender Institute + * + */ + +#include "DRW_render.h" + +#include "BKE_icons.h" +#include "BKE_main.h" + +#include "BLI_dynstr.h" +#include "BLI_rand.h" + +#include "IMB_imbuf.h" +#include "IMB_imbuf_types.h" + +#include "UI_resources.h" +#include "UI_interface_icons.h" + +#include "clay.h" +#ifdef WITH_CLAY_ENGINE +/* Shaders */ + +extern char datatoc_clay_frag_glsl[]; +extern char datatoc_clay_vert_glsl[]; +extern char datatoc_ssao_alchemy_glsl[]; +extern char datatoc_ssao_groundtruth_glsl[]; + +/* Storage */ + +/* UBOs data needs to be 16 byte aligned (size of vec4) */ +/* Reminder : float, int, bool are 4 bytes */ +typedef struct CLAY_UBO_Material { + float ssao_params_var[4]; + /* - 16 -*/ + float matcap_hsv[3]; + float matcap_id; /* even float encoding have enough precision */ + /* - 16 -*/ + float matcap_rot[2]; + float pad[2]; /* ensure 16 bytes alignement */ +} CLAY_UBO_Material; /* 48 bytes */ + +typedef struct CLAY_UBO_Storage { + CLAY_UBO_Material materials[512]; /* 512 = 9 bit material id */ +} CLAY_UBO_Storage; + +static struct CLAY_data { + /* Depth Pre Pass */ + struct GPUShader *depth_sh; + /* Shading Pass */ + struct GPUShader *clay_sh; + + /* Materials Parameter UBO */ + struct GPUUniformBuffer *mat_ubo; + CLAY_UBO_Storage mat_storage; + short ubo_flag; + + /* Matcap textures */ + struct GPUTexture *matcap_array; + float matcap_colors[24][3]; + + /* Ssao */ + float winmat[4][4]; + float viewvecs[3][4]; + float ssao_params[4]; + struct GPUTexture *jitter_tx; + struct GPUTexture *sampling_tx; +} data = {NULL}; + +/* CLAY_data.ubo_flag */ +enum { + CLAY_UBO_CLEAR = (1 << 0), + CLAY_UBO_REFRESH = (1 << 1), +}; + +/* keep it under MAX_BUFFERS */ +typedef struct CLAY_FramebufferList{ + /* default */ + struct GPUFrameBuffer *default_fb; + /* engine specific */ + struct GPUFrameBuffer *downsample_depth; +} CLAY_FramebufferList; + +/* keep it under MAX_TEXTURES */ +typedef struct CLAY_TextureList{ + /* default */ + struct GPUTexture *color; + struct GPUTexture *depth; + /* engine specific */ + struct GPUTexture *depth_low; +} CLAY_TextureList; + +/* for clarity follow the same layout as CLAY_TextureList */ +enum { + SCENE_COLOR, + SCENE_DEPTH, + SCENE_DEPTH_LOW, +}; + +/* keep it under MAX_PASSES */ +typedef struct CLAY_PassList{ + /* default */ + struct DRWPass *non_meshes_pass; + struct DRWPass *ob_center_pass; + /* engine specific */ + struct DRWPass *depth_pass; + struct DRWPass *clay_pass; + struct DRWPass *wire_overlay_pass; + struct DRWPass *wire_outline_pass; +} CLAY_PassList; + +//#define GTAO + +/* Functions */ + +static void add_icon_to_rect(PreviewImage *prv, float *final_rect, int layer) +{ + int image_size = prv->w[0] * prv->h[0]; + float *new_rect = &final_rect[image_size * 4 * layer]; + + IMB_buffer_float_from_byte(new_rect, (unsigned char *)prv->rect[0], IB_PROFILE_SRGB, IB_PROFILE_SRGB, + false, prv->w[0], prv->h[0], prv->w[0], prv->w[0]); + + /* Find overall color */ + for (int y = 0; y < 4; ++y) { + for (int x = 0; x < 4; ++x) { + data.matcap_colors[layer][0] += new_rect[y * 512 * 128 * 4 + x * 128 * 4 + 0]; + data.matcap_colors[layer][1] += new_rect[y * 512 * 128 * 4 + x * 128 * 4 + 1]; + data.matcap_colors[layer][2] += new_rect[y * 512 * 128 * 4 + x * 128 * 4 + 2]; + } + } + + data.matcap_colors[layer][0] /= 16.0f * 2.0f; /* the * 2 is to darken for shadows */ + data.matcap_colors[layer][1] /= 16.0f * 2.0f; + data.matcap_colors[layer][2] /= 16.0f * 2.0f; +} + +static struct GPUTexture *load_matcaps(PreviewImage *prv[24], int nbr) +{ + struct GPUTexture *tex; + int w = prv[0]->w[0]; + int h = prv[0]->h[0]; + float *final_rect = MEM_callocN(sizeof(float) * 4 * w * h * nbr, "Clay Matcap array rect"); + + for (int i = 0; i < nbr; ++i) { + add_icon_to_rect(prv[i], final_rect, i); + BKE_previewimg_free(&prv[i]); + } + + tex = DRW_texture_create_2D_array(w, h, nbr, DRW_TEX_RGBA_8, DRW_TEX_FILTER, final_rect); + MEM_freeN(final_rect); + + return tex; +} + +static int matcap_to_index(int matcap) +{ + if (matcap == ICON_MATCAP_02) return 1; + else if (matcap == ICON_MATCAP_03) return 2; + else if (matcap == ICON_MATCAP_04) return 3; + else if (matcap == ICON_MATCAP_05) return 4; + else if (matcap == ICON_MATCAP_06) return 5; + else if (matcap == ICON_MATCAP_07) return 6; + else if (matcap == ICON_MATCAP_08) return 7; + else if (matcap == ICON_MATCAP_09) return 8; + else if (matcap == ICON_MATCAP_10) return 9; + else if (matcap == ICON_MATCAP_11) return 10; + else if (matcap == ICON_MATCAP_12) return 11; + else if (matcap == ICON_MATCAP_13) return 12; + else if (matcap == ICON_MATCAP_14) return 13; + else if (matcap == ICON_MATCAP_15) return 14; + else if (matcap == ICON_MATCAP_16) return 15; + else if (matcap == ICON_MATCAP_17) return 16; + else if (matcap == ICON_MATCAP_18) return 17; + else if (matcap == ICON_MATCAP_19) return 18; + else if (matcap == ICON_MATCAP_20) return 19; + else if (matcap == ICON_MATCAP_21) return 20; + else if (matcap == ICON_MATCAP_22) return 21; + else if (matcap == ICON_MATCAP_23) return 22; + else if (matcap == ICON_MATCAP_24) return 23; + return 0; +} + +static struct GPUTexture *create_spiral_sample_texture(int numsaples) +{ + struct GPUTexture *tex; + float (*texels)[2] = MEM_mallocN(sizeof(float[2]) * numsaples, "concentric_tex"); + const float numsaples_inv = 1.0f / numsaples; + int i; + /* arbitrary number to ensure we don't get conciding samples every circle */ + const float spirals = 7.357; + + for (i = 0; i < numsaples; i++) { + float r = (i + 0.5f) * numsaples_inv; + float phi = r * spirals * (float)(2.0 * M_PI); + texels[i][0] = r * cosf(phi); + texels[i][1] = r * sinf(phi); + } + + tex = DRW_texture_create_1D(numsaples, DRW_TEX_RG_16, 0, (float *)texels); + + MEM_freeN(texels); + return tex; +} + +static struct GPUTexture *create_jitter_texture(void) +{ + float jitter[64 * 64][2]; + int i; + + /* TODO replace by something more evenly distributed like blue noise */ + for (i = 0; i < 64 * 64; i++) { +#ifdef GTAO + jitter[i][0] = BLI_frand(); + jitter[i][1] = BLI_frand(); +#else + jitter[i][0] = 2.0f * BLI_frand() - 1.0f; + jitter[i][1] = 2.0f * BLI_frand() - 1.0f; + normalize_v2(jitter[i]); +#endif + } + + return DRW_texture_create_2D(64, 64, DRW_TEX_RG_16, DRW_TEX_FILTER | DRW_TEX_WRAP, &jitter[0][0]); +} + +static void clay_material_settings_init(MaterialEngineSettingsClay *ma) +{ + ma->matcap_icon = ICON_MATCAP_01; + ma->matcap_rot = 0.0f; + ma->matcap_hue = 0.5f; + ma->matcap_sat = 0.5f; + ma->matcap_val = 0.5f; + ma->ssao_distance = 0.2; + ma->ssao_attenuation = 1.0f; + ma->ssao_factor_cavity = 1.0f; + ma->ssao_factor_edge = 1.0f; +} + +RenderEngineSettings *CLAY_render_settings_create(void) +{ + RenderEngineSettingsClay *settings = MEM_callocN(sizeof(RenderEngineSettingsClay), "RenderEngineSettingsClay"); + + clay_material_settings_init((MaterialEngineSettingsClay *)settings); + + settings->ssao_samples = 32; + + return (RenderEngineSettings *)settings; +} + +MaterialEngineSettings *CLAY_material_settings_create(void) +{ + MaterialEngineSettingsClay *settings = MEM_callocN(sizeof(MaterialEngineSettingsClay), "MaterialEngineSettingsClay"); + + clay_material_settings_init(settings); + + return (MaterialEngineSettings *)settings; +} + +static void CLAY_engine_init(const bContext *C) +{ + Main *bmain = CTX_data_main(C); + + /* Create Texture Array */ + if (!data.matcap_array) { + PreviewImage *prv[24]; /* For now use all of the 24 internal matcaps */ + + /* TODO only load used matcaps */ + prv[0] = UI_icon_to_preview(ICON_MATCAP_01); + prv[1] = UI_icon_to_preview(ICON_MATCAP_02); + prv[2] = UI_icon_to_preview(ICON_MATCAP_03); + prv[3] = UI_icon_to_preview(ICON_MATCAP_04); + prv[4] = UI_icon_to_preview(ICON_MATCAP_05); + prv[5] = UI_icon_to_preview(ICON_MATCAP_06); + prv[6] = UI_icon_to_preview(ICON_MATCAP_07); + prv[7] = UI_icon_to_preview(ICON_MATCAP_08); + prv[8] = UI_icon_to_preview(ICON_MATCAP_09); + prv[9] = UI_icon_to_preview(ICON_MATCAP_10); + prv[10] = UI_icon_to_preview(ICON_MATCAP_11); + prv[11] = UI_icon_to_preview(ICON_MATCAP_12); + prv[12] = UI_icon_to_preview(ICON_MATCAP_13); + prv[13] = UI_icon_to_preview(ICON_MATCAP_14); + prv[14] = UI_icon_to_preview(ICON_MATCAP_15); + prv[15] = UI_icon_to_preview(ICON_MATCAP_16); + prv[16] = UI_icon_to_preview(ICON_MATCAP_17); + prv[17] = UI_icon_to_preview(ICON_MATCAP_18); + prv[18] = UI_icon_to_preview(ICON_MATCAP_19); + prv[19] = UI_icon_to_preview(ICON_MATCAP_20); + prv[20] = UI_icon_to_preview(ICON_MATCAP_21); + prv[21] = UI_icon_to_preview(ICON_MATCAP_22); + prv[22] = UI_icon_to_preview(ICON_MATCAP_23); + prv[23] = UI_icon_to_preview(ICON_MATCAP_24); + + data.matcap_array = load_matcaps(prv, 24); + } + + /* AO Jitter */ + if (!data.jitter_tx) { + data.jitter_tx = create_jitter_texture(); + } + + /* AO Samples */ + /* TODO use hammersley sequence */ + if (!data.sampling_tx) { + data.sampling_tx = create_spiral_sample_texture(500); + } + + /* Depth prepass */ + if (!data.depth_sh) { + data.depth_sh = DRW_shader_create_3D_depth_only(); + } + + if (!data.mat_ubo) { + data.mat_ubo = DRW_uniformbuffer_create(sizeof(CLAY_UBO_Storage), NULL); + } + + /* Shading pass */ + if (!data.clay_sh) { + DynStr *ds = BLI_dynstr_new(); + const char *max_mat = + "#define MAX_MATERIAL 512\n" + "#define USE_ROTATION\n" + "#define USE_AO\n" + "#define USE_HSV\n"; + char *matcap_with_ao; + + BLI_dynstr_append(ds, datatoc_clay_frag_glsl); +#ifdef GTAO + BLI_dynstr_append(ds, datatoc_ssao_groundtruth_glsl); +#else + BLI_dynstr_append(ds, datatoc_ssao_alchemy_glsl); +#endif + + matcap_with_ao = BLI_dynstr_get_cstring(ds); + + data.clay_sh = DRW_shader_create(datatoc_clay_vert_glsl, NULL, matcap_with_ao, max_mat); + + BLI_dynstr_free(ds); + MEM_freeN(matcap_with_ao); + } + + /* Cleanup all runtime data loaded from file */ + for (Scene *sce = bmain->scene.first; sce; sce = sce->id.next) { + /* Using render settings as material settings */ + MaterialEngineSettingsClay *res = DRW_render_settings_get(sce, RE_engine_id_BLENDER_CLAY); + res->flag = CLAY_OUTDATED; + res->ubo_index = -1; + + /* Update Collections Materials */ + for (SceneLayer *sl = sce->render_layers.first; sl; sl = sl->next) { + for (LayerCollection *lc = sl->layer_collections.first; lc; lc = lc->next) { + CollectionEngineSettings *ces; + ces = BKE_layer_collection_engine_get(lc, RE_engine_id_BLENDER_CLAY); + if (ces) { /* May not exists */ + BKE_collection_engine_property_value_set_int(ces, "flag", CLAY_OUTDATED); + BKE_collection_engine_property_value_set_int(ces, "ubo_index", -1); + } + } + } + } + + data.ubo_flag |= CLAY_UBO_REFRESH; +} + +static void CLAY_ssao_setup(void) +{ + float invproj[4][4]; + float dfdyfacs[2]; + bool is_persp = DRW_viewport_is_persp_get(); + /* view vectors for the corners of the view frustum. Can be used to recreate the world space position easily */ + float viewvecs[3][4] = { + {-1.0f, -1.0f, -1.0f, 1.0f}, + {1.0f, -1.0f, -1.0f, 1.0f}, + {-1.0f, 1.0f, -1.0f, 1.0f} + }; + int i; + float *size = DRW_viewport_size_get(); + RenderEngineSettingsClay *settings = DRW_render_settings_get(NULL, RE_engine_id_BLENDER_CLAY); + + DRW_get_dfdy_factors(dfdyfacs); + + data.ssao_params[0] = settings->ssao_samples; + data.ssao_params[1] = size[0] / 64.0; + data.ssao_params[2] = size[1] / 64.0; + data.ssao_params[3] = dfdyfacs[1]; /* dfdy sign for offscreen */ + + /* invert the view matrix */ + DRW_viewport_matrix_get(data.winmat, DRW_MAT_WIN); + invert_m4_m4(invproj, data.winmat); + + /* convert the view vectors to view space */ + for (i = 0; i < 3; i++) { + mul_m4_v4(invproj, viewvecs[i]); + /* normalized trick see http://www.derschmale.com/2014/01/26/reconstructing-positions-from-the-depth-buffer */ + mul_v3_fl(viewvecs[i], 1.0f / viewvecs[i][3]); + if (is_persp) + mul_v3_fl(viewvecs[i], 1.0f / viewvecs[i][2]); + viewvecs[i][3] = 1.0; + + copy_v4_v4(data.viewvecs[i], viewvecs[i]); + } + + /* we need to store the differences */ + data.viewvecs[1][0] -= data.viewvecs[0][0]; + data.viewvecs[1][1] = data.viewvecs[2][1] - data.viewvecs[0][1]; + + /* calculate a depth offset as well */ + if (!is_persp) { + float vec_far[] = {-1.0f, -1.0f, 1.0f, 1.0f}; + mul_m4_v4(invproj, vec_far); + mul_v3_fl(vec_far, 1.0f / vec_far[3]); + data.viewvecs[1][2] = vec_far[2] - data.viewvecs[0][2]; + } +} + +static DRWShadingGroup *CLAY_shgroup_create(DRWPass *pass, int *UNUSED(material_id)) +{ + const int depthloc = 0, matcaploc = 1, jitterloc = 2, sampleloc = 3; + + //CLAY_UBO_Material *mat = &data.mat_storage.materials[0]; + DRWShadingGroup *grp = DRW_shgroup_create(data.clay_sh, pass); + + DRW_shgroup_uniform_vec2(grp, "screenres", DRW_viewport_size_get(), 1); + DRW_shgroup_uniform_buffer(grp, "depthtex", SCENE_DEPTH, depthloc); + DRW_shgroup_uniform_texture(grp, "matcaps", data.matcap_array, matcaploc); + DRW_shgroup_uniform_mat4(grp, "WinMatrix", (float *)data.winmat); + DRW_shgroup_uniform_vec4(grp, "viewvecs", (float *)data.viewvecs, 3); + DRW_shgroup_uniform_vec4(grp, "ssao_params", data.ssao_params, 1); + DRW_shgroup_uniform_vec3(grp, "matcaps_color", (float *)data.matcap_colors, 24); + + //DRW_shgroup_uniform_int(grp, "material_id", material_id, 1); + +#ifndef GTAO + DRW_shgroup_uniform_texture(grp, "ssao_jitter", data.jitter_tx, jitterloc); + DRW_shgroup_uniform_texture(grp, "ssao_samples", data.sampling_tx, sampleloc); +#endif + + return grp; +} + +static void update_ubo_storage(float matcap_rot, float matcap_hue, float matcap_sat, float matcap_val, + float ssao_distance, float ssao_factor_cavity, float ssao_factor_edge, + float ssao_attenuation, int matcap_icon, unsigned int current_id) +{ + CLAY_UBO_Material *ubo = &data.mat_storage.materials[current_id]; + + ubo->matcap_rot[0] = cosf(matcap_rot * 3.14159f * 2.0f); + ubo->matcap_rot[1] = sinf(matcap_rot * 3.14159f * 2.0f); + + ubo->matcap_hsv[0] = matcap_hue + 0.5f; + ubo->matcap_hsv[1] = matcap_sat * 2.0f; + ubo->matcap_hsv[2] = matcap_val * 2.0f; + + ubo->ssao_params_var[0] = ssao_distance; + ubo->ssao_params_var[1] = ssao_factor_cavity; + ubo->ssao_params_var[2] = ssao_factor_edge; + ubo->ssao_params_var[3] = ssao_attenuation; + + + ubo->matcap_id = matcap_to_index(matcap_icon); +} + +static void CLAY_update_material_ubo(const struct bContext *C) +{ + Main *bmain = CTX_data_main(C); + + /* Update Default materials */ + for (Scene *sce = bmain->scene.first; sce; sce = sce->id.next) { + /* Using render settings as material settings */ + MaterialEngineSettingsClay *res = DRW_render_settings_get(sce, RE_engine_id_BLENDER_CLAY); + + if (res->flag & CLAY_OUTDATED) + data.ubo_flag |= CLAY_UBO_REFRESH; + + if (res->matcap_icon < ICON_MATCAP_01 || + res->matcap_icon > ICON_MATCAP_24) + { + res->matcap_icon = ICON_MATCAP_01; + } + + res->flag &= ~CLAY_OUTDATED; + + + /* Update Collections Materials */ + for (SceneLayer *sl = sce->render_layers.first; sl; sl = sl->next) { + for (LayerCollection *lc = sl->layer_collections.first; lc; lc = lc->next) { + CollectionEngineSettings *ces; + ces = BKE_layer_collection_engine_get(lc, RE_engine_id_BLENDER_CLAY); + + BKE_collection_engine_property_value_set_int(ces, "flag", 0); + BKE_collection_engine_property_value_set_int(ces, "ubo_index", 0); + } + } + } + + if (data.ubo_flag & CLAY_UBO_REFRESH) { + int current_id = 0; + + + /* Default materials */ + for (Scene *sce = bmain->scene.first; sce; sce = sce->id.next) { + MaterialEngineSettingsClay *res = DRW_render_settings_get(sce, RE_engine_id_BLENDER_CLAY); + + update_ubo_storage(res->matcap_rot, res->matcap_hue, res->matcap_sat, res->matcap_val, + res->ssao_distance, res->ssao_factor_cavity, res->ssao_factor_edge, + res->ssao_attenuation, res->matcap_icon, current_id); + current_id++; + + for (SceneLayer *sl = sce->render_layers.first; sl; sl = sl->next) { + for (LayerCollection *lc = sl->layer_collections.first; lc; lc = lc->next) { + /* TODO */ + current_id++; + } + } + current_id++; + } + + + DRW_uniformbuffer_update(data.mat_ubo, &data.mat_storage); + } + + data.ubo_flag = 0; +} + +static void CLAY_create_cache(CLAY_PassList *passes, const struct bContext *C) +{ + SceneLayer *sl = CTX_data_scene_layer(C); + DRWShadingGroup *default_shgrp, *depthbatch; + + /* Depth Pass */ + { + passes->depth_pass = DRW_pass_create("Depth Pass", DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS); + + depthbatch = DRW_shgroup_create(data.depth_sh, passes->depth_pass); + } + + /* Clay Pass */ + { + MaterialEngineSettingsClay *settings = DRW_render_settings_get(NULL, RE_engine_id_BLENDER_CLAY); + + passes->clay_pass = DRW_pass_create("Clay Pass", DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS); + + default_shgrp = CLAY_shgroup_create(passes->clay_pass, &settings->ubo_index); + DRW_shgroup_uniform_block(default_shgrp, "material_block", data.mat_ubo, 0); + } + + /* Object Mode */ + { + DRW_pass_setup_common(&passes->wire_overlay_pass, + &passes->wire_outline_pass, + &passes->non_meshes_pass, + &passes->ob_center_pass); + } + + /* TODO Create hash table of batch based on material id*/ + Object *ob; + DEG_OBJECT_ITER(sl, ob) + { + if ((ob->base_flag & BASE_VISIBLED) == 0) { + continue; + } + + struct Batch *geom; + //bool do_outlines; + + switch (ob->type) { + case OB_MESH: + geom = DRW_cache_surface_get(ob); + + /* Add everything for now */ + DRW_shgroup_call_add(depthbatch, geom, ob->obmat); + DRW_shgroup_call_add(default_shgrp, geom, ob->obmat); + + //DRW_shgroup_wire_overlay(passes->wire_overlay_pass, ob); + + //do_outlines = ((ob->base_flag & BASE_SELECTED) != 0); + //DRW_shgroup_wire_outline(passes->wire_outline_pass, ob, false, false, do_outlines); + + /* When encountering a new material : + * - Create new Batch + * - Initialize Batch + * - Push it to the hash table + * - The pass takes care of inserting it + * next to the same shader calls */ + + /* Free hash table */ + break; + case OB_LAMP: + case OB_CAMERA: + case OB_EMPTY: + default: + DRW_shgroup_non_meshes(passes->non_meshes_pass, ob); + break; + } + + DRW_shgroup_object_center(passes->ob_center_pass, ob); + DRW_shgroup_relationship_lines(passes->non_meshes_pass, ob); + } + DEG_OBJECT_ITER_END +} + +static void CLAY_view_draw(RenderEngine *UNUSED(engine), const bContext *context) +{ + /* This function may run for multiple viewports + * so get the current viewport buffers */ + CLAY_FramebufferList *buffers = NULL; + CLAY_TextureList *textures = NULL; + CLAY_PassList *passes = NULL; + + DRW_viewport_init(context, (void **)&buffers, (void **)&textures, (void **)&passes); + + CLAY_engine_init(context); + + CLAY_update_material_ubo(context); + + /* TODO : tag to refresh by the deps graph */ + /* ideally only refresh when objects are added/removed */ + /* or render properties / materials change */ +#ifdef WITH_VIEWPORT_CACHE_TEST + static bool once = false; +#endif + if (DRW_viewport_cache_is_dirty() +#ifdef WITH_VIEWPORT_CACHE_TEST + && !once +#endif + ) { +#ifdef WITH_VIEWPORT_CACHE_TEST + once = true; +#endif + CLAY_create_cache(passes, context); + } + + /* Start Drawing */ + DRW_draw_background(); + + /* Pass 1 : Depth pre-pass */ + DRW_draw_pass(passes->depth_pass); + + /* Pass 2 (Optionnal) : Separated Downsampled AO */ + DRW_framebuffer_texture_detach(textures->depth); + /* TODO */ + + /* Pass 3 : Shading */ + CLAY_ssao_setup(); + DRW_draw_pass(passes->clay_pass); + + /* Pass 4 : Overlays */ + DRW_framebuffer_texture_attach(buffers->default_fb, textures->depth, 0); + //DRW_draw_pass(passes->wire_overlay_pass); + //DRW_draw_pass(passes->wire_outline_pass); + DRW_draw_pass(passes->non_meshes_pass); + DRW_draw_pass(passes->ob_center_pass); + + /* Always finish by this */ + DRW_state_reset(); +} + +static void CLAY_collection_settings_create(RenderEngine *UNUSED(engine), CollectionEngineSettings *ces) +{ + BLI_assert(ces); + BKE_collection_engine_property_add_int(ces, "matcap_icon", ICON_MATCAP_01); + BKE_collection_engine_property_add_int(ces, "type", CLAY_MATCAP_NONE); + BKE_collection_engine_property_add_float(ces, "matcap_rotation", 0.0f); + BKE_collection_engine_property_add_float(ces, "matcap_hue", 0.5f); + BKE_collection_engine_property_add_float(ces, "matcap_saturation", 0.5f); + BKE_collection_engine_property_add_float(ces, "matcap_value", 0.5f); + BKE_collection_engine_property_add_float(ces, "ssao_distance", 0.2f); + BKE_collection_engine_property_add_float(ces, "ssao_attenuation", 1.0f); + BKE_collection_engine_property_add_float(ces, "ssao_factor_cavity", 1.0f); + BKE_collection_engine_property_add_float(ces, "ssao_factor_edge", 1.0f); + + /* Runtime data (not display in settings) */ + BKE_collection_engine_property_add_int(ces, "ubo_index", -1); + BKE_collection_engine_property_add_int(ces, "flag", CLAY_OUTDATED); +} + +void clay_engine_free(void) +{ + /* data.depth_sh Is builtin so it's automaticaly freed */ + if (data.clay_sh) { + DRW_shader_free(data.clay_sh); + } + + if (data.matcap_array) { + DRW_texture_free(data.matcap_array); + } + + if (data.jitter_tx) { + DRW_texture_free(data.jitter_tx); + } + + if (data.sampling_tx) { + DRW_texture_free(data.sampling_tx); + } + + if (data.mat_ubo) { + DRW_uniformbuffer_free(data.mat_ubo); + } +} + +RenderEngineType viewport_clay_type = { + NULL, NULL, + "BLENDER_CLAY", N_("Clay"), RE_INTERNAL | RE_USE_OGL_PIPELINE, + NULL, NULL, NULL, NULL, &CLAY_view_draw, NULL, &CLAY_collection_settings_create, + {NULL, NULL, NULL} +}; +#endif
\ No newline at end of file |