diff options
author | Clément Foucault <foucault.clem@gmail.com> | 2017-02-07 13:20:15 +0300 |
---|---|---|
committer | Dalai Felinto <dfelinto@gmail.com> | 2017-02-07 13:31:22 +0300 |
commit | 83adc544382689217e19564fd5f2dd62160956cb (patch) | |
tree | 1026a590c1079b4907a6cab43e2c5759339c4350 /source/blender/draw | |
parent | aeb8e81f2741aabc95d14bce7a83cef45481959c (diff) |
Clay-Engine (merge clay-engine)
Initial work by Clément Foucault with contributions from Dalai Felinto
(mainly per-collection engine settings logic, and depsgraph iterator placeholder).
This makes Blender require OpenGL 3.3. Which means Intel graphic card
and OSX will break. Disable CLAY_ENGINE in CMake in those cases.
This is a prototype render engine intended to help the design of real
render engines. This is mainly an engine with enphasis in matcap and
ambient occlusion.
Implemented Features
--------------------
* Clay Render Engine, following the new API, to be used as reference for
future engines
* A more complete Matcap customization with more options
* Per-Collection render engine settings
* New Ground Truth AO - not enabled
Missing Features
----------------
* Finish object edit mode
- Fix shaders to use new matrix
- Fix artifacts when edge does off screen
- Fix depth issue
- Selection sillhouette
- Mesh wires
- Use mesh normals (for higher quality matcap)
- Non-Mesh objects drawing
- Widget drawing
- Performance issues
* Finish mesh edit mode
- Derived-Mesh-less edit mode API (mesh_rende.c)
* General edit mode
- Per-collection edit mode settings
* General engines
- Per-collection engine settings
(they are their, but they still need to be flushed by depsgraph, and
used by the drawing code)
Diffstat (limited to 'source/blender/draw')
-rw-r--r-- | source/blender/draw/CMakeLists.txt | 40 | ||||
-rw-r--r-- | source/blender/draw/DRW_engine.h | 45 | ||||
-rw-r--r-- | source/blender/draw/DRW_engines.h | 0 | ||||
-rw-r--r-- | source/blender/draw/engines/clay/clay.c | 722 | ||||
-rw-r--r-- | source/blender/draw/engines/clay/clay.h (renamed from source/blender/draw/DRW_defines.h) | 17 | ||||
-rw-r--r-- | source/blender/draw/engines/clay/shaders/clay_frag.glsl | 207 | ||||
-rw-r--r-- | source/blender/draw/engines/clay/shaders/clay_vert.glsl | 20 | ||||
-rw-r--r-- | source/blender/draw/engines/clay/shaders/ssao_alchemy.glsl | 73 | ||||
-rw-r--r-- | source/blender/draw/engines/clay/shaders/ssao_groundtruth.glsl | 120 | ||||
-rw-r--r-- | source/blender/draw/intern/DRW_render.h | 221 | ||||
-rw-r--r-- | source/blender/draw/intern/draw_cache.c | 543 | ||||
-rw-r--r-- | source/blender/draw/intern/draw_cache.h | 56 | ||||
-rw-r--r-- | source/blender/draw/intern/draw_manager.c | 1148 | ||||
-rw-r--r-- | source/blender/draw/intern/draw_mode_pass.c | 787 | ||||
-rw-r--r-- | source/blender/draw/intern/draw_mode_pass.h | 45 |
15 files changed, 4029 insertions, 15 deletions
diff --git a/source/blender/draw/CMakeLists.txt b/source/blender/draw/CMakeLists.txt index 60449ebc600..d5b54e8a746 100644 --- a/source/blender/draw/CMakeLists.txt +++ b/source/blender/draw/CMakeLists.txt @@ -26,37 +26,53 @@ set(INC . intern - nodes - operations + engines/clay + ../blenkernel ../blenlib ../blentranslation ../imbuf + ../depsgraph ../makesdna ../makesrna - ../windowmanager - ../nodes - ../nodes/composite - ../nodes/intern + ../gpu + ../editors/include + ../editors/space_view3d ../render/extern/include ../render/intern/include - ../../../extern/clew/include + + ../../../intern/glew-mx ../../../intern/guardedalloc - ../../../intern/atomic ) set(INC_SYS - + ${GLEW_INCLUDE_PATH} ) set(SRC - DRW_defines.h + intern/draw_manager.c + intern/draw_mode_pass.c + intern/draw_cache.c + engines/clay/clay.c -) + intern/DRW_render.h + intern/draw_mode_pass.h + intern/draw_cache.h + engines/clay/clay.h -list(APPEND INC + ./DRW_engine.h ) +if(WITH_CLAY_ENGINE) + add_definitions(-DWITH_CLAY_ENGINE) endif() +data_to_c_simple(engines/clay/shaders/clay_frag.glsl SRC) +data_to_c_simple(engines/clay/shaders/clay_vert.glsl SRC) +data_to_c_simple(engines/clay/shaders/ssao_alchemy.glsl SRC) +data_to_c_simple(engines/clay/shaders/ssao_groundtruth.glsl SRC) + +list(APPEND INC +) + blender_add_lib(bf_draw "${SRC}" "${INC}" "${INC_SYS}") diff --git a/source/blender/draw/DRW_engine.h b/source/blender/draw/DRW_engine.h new file mode 100644 index 00000000000..4f86e3fcd91 --- /dev/null +++ b/source/blender/draw/DRW_engine.h @@ -0,0 +1,45 @@ +/* + * 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 + * + */ + +/** \file DRW_engine.h + * \ingroup draw + */ + +#ifndef __DRW_ENGINE_H__ +#define __DRW_ENGINE_H__ + +//#define WITH_VIEWPORT_CACHE_TEST + +struct DRWPass; +struct Material; +struct Scene; + +void DRW_engines_init(void); +void DRW_engines_free(void); + +/* This is here because GPUViewport needs it */ +void DRW_pass_free(struct DRWPass *pass); + +/* Settings */ +void *DRW_material_settings_get(struct Material *ma, const char *engine_name); +void *DRW_render_settings_get(struct Scene *scene, const char *engine_name); + +#endif /* __DRW_ENGINE_H__ */
\ No newline at end of file diff --git a/source/blender/draw/DRW_engines.h b/source/blender/draw/DRW_engines.h deleted file mode 100644 index e69de29bb2d..00000000000 --- a/source/blender/draw/DRW_engines.h +++ /dev/null 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 diff --git a/source/blender/draw/DRW_defines.h b/source/blender/draw/engines/clay/clay.h index 212c39e203b..404924be2a1 100644 --- a/source/blender/draw/DRW_defines.h +++ b/source/blender/draw/engines/clay/clay.h @@ -19,7 +19,18 @@ * */ -#ifndef __DRW_DEFINES_H__ -#define __DRW_DEFINES_H__ +/** \file clay.h + * \ingroup DNA + */ + +#ifndef __ENGINE_CLAY_H__ +#define __ENGINE_CLAY_H__ + +extern RenderEngineType viewport_clay_type; + +struct RenderEngineSettings *CLAY_render_settings_create(void); +struct MaterialEngineSettings *CLAY_material_settings_create(void); + +void clay_engine_free(void); -#endif /* __DRW_DEFINES_H__ */ +#endif /* __ENGINE_CLAY_H__ */
\ No newline at end of file diff --git a/source/blender/draw/engines/clay/shaders/clay_frag.glsl b/source/blender/draw/engines/clay/shaders/clay_frag.glsl new file mode 100644 index 00000000000..d9b372b652a --- /dev/null +++ b/source/blender/draw/engines/clay/shaders/clay_frag.glsl @@ -0,0 +1,207 @@ +uniform vec2 screenres; +uniform sampler2D depthtex; +uniform mat4 WinMatrix; + +/* Matcap */ +uniform sampler2DArray matcaps; +uniform vec3 matcaps_color[24]; + +/* Screen Space Occlusion */ +/* store the view space vectors for the corners of the view frustum here. + * It helps to quickly reconstruct view space vectors by using uv coordinates, + * see http://www.derschmale.com/2014/01/26/reconstructing-positions-from-the-depth-buffer */ +uniform vec4 viewvecs[3]; +uniform vec4 ssao_params; + +uniform sampler2D ssao_jitter; +uniform sampler1D ssao_samples; + +/* Material Parameters packed in an UBO */ +struct Material { + vec4 ssao_params_var; + vec4 matcap_hsv_id; + vec4 matcap_rot; /* vec4 to ensure 16 bytes alignement (don't trust compiler) */ +}; + +layout(std140) uniform material_block { + Material matcaps_param[MAX_MATERIAL]; +}; + +int mat_id; + +/* Aliases */ +#define ssao_samples_num ssao_params.x +#define jitter_tilling ssao_params.yz +#define dfdy_sign ssao_params.w + +#define matcap_hsv matcaps_param[mat_id].matcap_hsv_id.xyz +#define matcap_index matcaps_param[mat_id].matcap_hsv_id.w +#define matcap_rotation matcaps_param[mat_id].matcap_rot.xy + +in vec3 normal; +out vec4 fragColor; + +/* TODO Move this to SSAO modules */ +/* simple depth reconstruction, see http://www.derschmale.com/2014/01/26/reconstructing-positions-from-the-depth-buffer + * we change the factors from the article to fit the OpennGL model. */ +vec3 get_view_space_from_depth(in vec2 uvcoords, in float depth) +{ + if (WinMatrix[3][3] == 0.0) { + /* Perspective */ + float d = 2.0 * depth - 1.0; + + float zview = -WinMatrix[3][2] / (d + WinMatrix[2][2]); + + return zview * (viewvecs[0].xyz + vec3(uvcoords, 0.0) * viewvecs[1].xyz); + } + else { + /* Orthographic */ + vec3 offset = vec3(uvcoords, depth); + + return viewvecs[0].xyz + offset * viewvecs[1].xyz; + } +} + +/* TODO remove this when switching to geometric normals */ +vec3 calculate_view_space_normal(in vec3 viewposition) +{ + vec3 normal = cross(normalize(dFdx(viewposition)), dfdy_sign * normalize(dFdy(viewposition))); + return normalize(normal); +} + +#ifdef USE_HSV +void rgb_to_hsv(vec3 rgb, out vec3 outcol) +{ + float cmax, cmin, h, s, v, cdelta; + vec3 c; + + cmax = max(rgb[0], max(rgb[1], rgb[2])); + cmin = min(rgb[0], min(rgb[1], rgb[2])); + cdelta = cmax - cmin; + + v = cmax; + if (cmax != 0.0) + s = cdelta / cmax; + else { + s = 0.0; + h = 0.0; + } + + if (s == 0.0) { + h = 0.0; + } + else { + c = (vec3(cmax, cmax, cmax) - rgb.xyz) / cdelta; + + if (rgb.x == cmax) h = c[2] - c[1]; + else if (rgb.y == cmax) h = 2.0 + c[0] - c[2]; + else h = 4.0 + c[1] - c[0]; + + h /= 6.0; + + if (h < 0.0) + h += 1.0; + } + + outcol = vec3(h, s, v); +} + +void hsv_to_rgb(vec3 hsv, out vec3 outcol) +{ + float i, f, p, q, t, h, s, v; + vec3 rgb; + + h = hsv[0]; + s = hsv[1]; + v = hsv[2]; + + if (s == 0.0) { + rgb = vec3(v, v, v); + } + else { + if (h == 1.0) + h = 0.0; + + h *= 6.0; + i = floor(h); + f = h - i; + rgb = vec3(f, f, f); + p = v * (1.0 - s); + q = v * (1.0 - (s * f)); + t = v * (1.0 - (s * (1.0 - f))); + + if (i == 0.0) rgb = vec3(v, t, p); + else if (i == 1.0) rgb = vec3(q, v, p); + else if (i == 2.0) rgb = vec3(p, v, t); + else if (i == 3.0) rgb = vec3(p, q, v); + else if (i == 4.0) rgb = vec3(t, p, v); + else rgb = vec3(v, p, q); + } + + outcol = rgb; +} + +void hue_sat(float hue, float sat, float value, inout vec3 col) +{ + vec3 hsv; + + rgb_to_hsv(col, hsv); + + hsv.x += hue; + hsv.x -= floor(hsv.x); + hsv.y *= sat; + hsv.y = clamp(hsv.y, 0.0, 1.0); + hsv.z *= value; + hsv.z = clamp(hsv.z, 0.0, 1.0); + + hsv_to_rgb(hsv, col); +} +#endif + +#ifdef USE_AO +/* Prototype */ +void ssao_factors(in float depth, in vec3 normal, in vec3 position, in vec2 screenco, out float cavities, out float edges); +#endif + +void main() { + vec2 screenco = vec2(gl_FragCoord.xy) / screenres; + float depth = texture(depthtex, screenco).r; + + vec3 position = get_view_space_from_depth(screenco, depth); + vec3 normal = calculate_view_space_normal(position); + + //mat_id = int(screenco.x*3.0); + + /* Manual Depth test */ + /* Doing this test earlier gives problem with dfdx calculations + * TODO move this before when we have proper geometric normals */ + if (gl_FragCoord.z > depth + 1e-5) + discard; + +#ifdef USE_ROTATION + /* Rotate texture coordinates */ + vec2 rotY = vec2(-matcap_rotation.y, matcap_rotation.x); + vec2 texco = abs(vec2(dot(normal.xy, matcap_rotation), dot(normal.xy, rotY)) * .49 + 0.5); +#else + vec2 texco = abs(normal.xy * .49 + 0.5); +#endif + vec3 col = texture(matcaps, vec3(texco, matcap_index)).rgb; + +#ifdef USE_AO + float cavity, edges; + ssao_factors(depth, normal, position, screenco, cavity, edges); + + col *= mix(vec3(1.0), matcaps_color[int(matcap_index)], cavity); +#endif + +#ifdef USE_HSV + hue_sat(matcap_hsv.x, matcap_hsv.y, matcap_hsv.z, col); +#endif + +#ifdef USE_AO + /* Apply highlights after hue shift */ + col *= edges + 1.0; +#endif + + fragColor = vec4(col, 1.0); +} diff --git a/source/blender/draw/engines/clay/shaders/clay_vert.glsl b/source/blender/draw/engines/clay/shaders/clay_vert.glsl new file mode 100644 index 00000000000..0b598ea0291 --- /dev/null +++ b/source/blender/draw/engines/clay/shaders/clay_vert.glsl @@ -0,0 +1,20 @@ +uniform mat4 ModelViewProjectionMatrix; +uniform mat3 NormalMatrix; + +#if __VERSION__ == 120 +attribute vec3 pos; +attribute vec3 nor; +varying vec3 normal; +#else +in vec3 pos; +in vec3 nor; +out vec3 normal; +#endif + + +void main() +{ + normal = normalize(NormalMatrix * nor); + gl_Position = ModelViewProjectionMatrix * vec4(pos, 1.0); +} + diff --git a/source/blender/draw/engines/clay/shaders/ssao_alchemy.glsl b/source/blender/draw/engines/clay/shaders/ssao_alchemy.glsl new file mode 100644 index 00000000000..d032fb91c01 --- /dev/null +++ b/source/blender/draw/engines/clay/shaders/ssao_alchemy.glsl @@ -0,0 +1,73 @@ +#define ssao_distance matcaps_param[mat_id].ssao_params_var.x +#define ssao_factor_cavity matcaps_param[mat_id].ssao_params_var.y +#define ssao_factor_edge matcaps_param[mat_id].ssao_params_var.z +#define ssao_attenuation matcaps_param[mat_id].ssao_params_var.w + +/* from The Alchemy screen-space ambient obscurance algorithm + * http://graphics.cs.williams.edu/papers/AlchemyHPG11/VV11AlchemyAO.pdf */ + +void ssao_factors(in float depth, in vec3 normal, in vec3 position, in vec2 screenco, out float cavities, out float edges) +{ + /* take the normalized ray direction here */ + vec2 rotX = texture2D(ssao_jitter, screenco.xy * jitter_tilling).rg; + vec2 rotY = vec2(-rotX.y, rotX.x); + + /* find the offset in screen space by multiplying a point + * in camera space at the depth of the point by the projection matrix. */ + vec2 offset; + float homcoord = WinMatrix[2][3] * position.z + WinMatrix[3][3]; + offset.x = WinMatrix[0][0] * ssao_distance / homcoord; + offset.y = WinMatrix[1][1] * ssao_distance / homcoord; + /* convert from -1.0...1.0 range to 0.0..1.0 for easy use with texture coordinates */ + offset *= 0.5; + + cavities = edges = 0.0; + int x; + int num_samples = int(ssao_samples_num); + + for (x = 0; x < num_samples; x++) { + /* TODO : optimisation replace by constant */ + vec2 dir_sample = texture1D(ssao_samples, (float(x) + 0.5) / ssao_samples_num).rg; + + /* rotate with random direction to get jittered result */ + vec2 dir_jittered = vec2(dot(dir_sample, rotX), dot(dir_sample, rotY)); + + vec2 uvcoords = screenco.xy + dir_jittered * offset; + + if (uvcoords.x > 1.0 || uvcoords.x < 0.0 || uvcoords.y > 1.0 || uvcoords.y < 0.0) + continue; + + float depth_new = texture2D(depthtex, uvcoords).r; + + /* Handle Background case */ + bool is_background = (depth_new == 1.0); + + /* This trick provide good edge effect even if no neighboor is found. */ + vec3 pos_new = get_view_space_from_depth(uvcoords, (is_background) ? depth : depth_new); + + if (is_background) + pos_new.z -= ssao_distance; + + vec3 dir = pos_new - position; + float len = length(dir); + float f_cavities = dot(dir, normal); + float f_edge = -f_cavities; + float f_bias = 0.05 * len + 0.0001; + + float attenuation = 1.0 / (len * (1.0 + len * len * ssao_attenuation)); + + /* use minor bias here to avoid self shadowing */ + if (f_cavities > -f_bias) + cavities += f_cavities * attenuation; + + if (f_edge > f_bias) + edges += f_edge * attenuation; + } + + cavities /= ssao_samples_num; + edges /= ssao_samples_num; + + /* don't let cavity wash out the surface appearance */ + cavities = clamp(cavities * ssao_factor_cavity, 0.0, 1.0); + edges = edges * ssao_factor_edge; +} diff --git a/source/blender/draw/engines/clay/shaders/ssao_groundtruth.glsl b/source/blender/draw/engines/clay/shaders/ssao_groundtruth.glsl new file mode 100644 index 00000000000..2f29624824e --- /dev/null +++ b/source/blender/draw/engines/clay/shaders/ssao_groundtruth.glsl @@ -0,0 +1,120 @@ +#define ssao_distance matcaps_param[mat_id].ssao_params_var.x +#define ssao_factor_cavity matcaps_param[mat_id].ssao_params_var.y +#define ssao_factor_edge matcaps_param[mat_id].ssao_params_var.z +#define ssao_attenuation matcaps_param[mat_id].ssao_params_var.w + +/* Based on Practical Realtime Strategies for Accurate Indirect Occlusion + * http://blog.selfshadow.com/publications/s2016-shading-course/activision/s2016_pbs_activision_occlusion.pdf + * http://blog.selfshadow.com/publications/s2016-shading-course/activision/s2016_pbs_activision_occlusion.pptx */ + +#define COSINE_WEIGHTING + +float integrate_arc(in float h1, in float h2, in float gamma, in float n_proj_len) +{ + float a = 0.0; +#ifdef COSINE_WEIGHTING + float cos_gamma = cos(gamma); + float sin_gamma_2 = 2.0 * sin(gamma); + a += -cos(2.0 * h1 - gamma) + cos_gamma + h1 * sin_gamma_2; + a += -cos(2.0 * h2 - gamma) + cos_gamma + h2 * sin_gamma_2; + a *= 0.25; /* 1/4 */ + a *= n_proj_len; +#else + /* Uniform weighting (slide 59) */ + a += 1 - cos(h1); + a += 1 - cos(h2); +#endif + return a; +} + +float get_max_horizon(in vec2 co, in vec3 x, in vec3 omega_o, in float h) +{ + if (co.x > 1.0 || co.x < 0.0 || co.y > 1.0 || co.y < 0.0) + return h; + + float depth = texture2D(depthtex, co).r; + + /* Background case */ + if (depth == 1.0) + return h; + + vec3 s = get_view_space_from_depth(co, depth); /* s View coordinate */ + vec3 omega_s = s - x; + float len = length(omega_s); + + if (len < ssao_distance) { + omega_s /= len; + h = max(h, dot(omega_s, omega_o)); + } + return h; +} + +void ssao_factors(in float depth, in vec3 normal, in vec3 position, in vec2 screenco, out float cavities, out float edges) +{ + /* Renaming */ + vec3 omega_o = -normalize(position); /* viewvec */ + vec2 x_ = screenco; /* x^ Screen coordinate */ + vec3 x = position; /* x view space coordinate */ + +#ifdef SPATIAL_DENOISE + float noise_dir = (1.0 / 16.0) * float(((int(gl_FragCoord.x + gl_FragCoord.y) & 0x3) << 2) + (int(gl_FragCoord.x) & 0x3)); + float noise_offset = (1.0 / 4.0) * float(int(gl_FragCoord.y - gl_FragCoord.x) & 0x3); +#else + float noise_dir = (1.0 / 16.0) * float(((int(gl_FragCoord.x + gl_FragCoord.y) & 0x3) << 2) + (int(gl_FragCoord.x) & 0x3)); + float noise_offset = (0.5 / 16.0) + (1.0 / 16.0) * float(((int(gl_FragCoord.x - gl_FragCoord.y) & 0x3) << 2) + (int(gl_FragCoord.x) & 0x3)); +#endif + + const float phi_step = 16.0; + const float theta_step = 16.0; + const float m_pi = 3.14159265358979323846; + vec2 pixel_ratio = vec2(screenres.y / screenres.x, 1.0); + vec2 pixel_size = vec2(1.0) / screenres.xy; + float min_stride = length(pixel_size); + float homcco = WinMatrix[2][3] * position.z + WinMatrix[3][3]; + float n = max(min_stride * theta_step, ssao_distance / homcco); /* Search distance */ + + /* Integral over PI */ + float A = 0.0; + for (float i = 0.0; i < phi_step; i++) { + float phi = m_pi * ((noise_dir + i) / phi_step); + + vec2 t_phi = vec2(cos(phi), sin(phi)); /* Screen space direction */ + + /* Search maximum horizon angles Theta1 and Theta2 */ + float theta1 = -1.0, theta2 = -1.0; /* init at cos(pi) */ + for (float j = 0.0; j < theta_step; j++) { + vec2 s_ = t_phi * pixel_ratio * n * ((j + noise_offset)/ theta_step); /* s^ Screen coordinate */ + vec2 co; + + co = x_ + s_; + theta1 = get_max_horizon(co, x, omega_o, theta1); + + co = x_ - s_; + theta2 = get_max_horizon(co, x, omega_o, theta2); + } + + /* (Slide 54) */ + theta1 = -acos(theta1); + theta2 = acos(theta2); + + /* Projecting Normal to Plane P defined by t_phi and omega_o */ + vec3 h = normalize(cross(vec3(t_phi, 0.0), omega_o)); /* Normal vector to Integration plane */ + vec3 t = cross(h, omega_o); /* Normal vector to plane */ + vec3 n_proj = normal - h * dot(normal, h); + float n_proj_len = length(n_proj); + vec3 n_proj_norm = normalize(n_proj); + + /* Clamping thetas (slide 58) */ + float gamma = sign(dot(n_proj_norm, t)) * acos(dot(normal, omega_o)); /* Angle between view vec and normal */ + theta1 = gamma + max(theta1 - gamma, -m_pi * 0.5); + theta2 = gamma + min(theta2 - gamma, m_pi * 0.5); + + /* Solving inner integral */ + A += integrate_arc(theta1, theta2, gamma, n_proj_len); + } + + A /= phi_step; + + cavities = 1.0 - A; + edges = 0.0; +}
\ No newline at end of file diff --git a/source/blender/draw/intern/DRW_render.h b/source/blender/draw/intern/DRW_render.h new file mode 100644 index 00000000000..90412e65a51 --- /dev/null +++ b/source/blender/draw/intern/DRW_render.h @@ -0,0 +1,221 @@ +/* + * 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 + * + */ + +/** \file DRW_render.h + * \ingroup draw + */ + +/* This is the Render Functions used by Realtime engines to draw with OpenGL */ + +#ifndef __DRW_RENDER_H__ +#define __DRW_RENDER_H__ + +#include "BKE_context.h" +#include "BKE_layer.h" +#include "BKE_scene.h" + +#include "BLI_listbase.h" +#include "BLI_math_matrix.h" +#include "BLI_math_vector.h" +#include "BLI_string.h" + +#include "BLT_translation.h" + +#include "DNA_object_types.h" +#include "DNA_lamp_types.h" +#include "DNA_material_types.h" +#include "DNA_scene_types.h" + +#include "draw_mode_pass.h" +#include "draw_cache.h" + +#include "MEM_guardedalloc.h" + +#include "RE_engine.h" + +//#define WITH_VIEWPORT_CACHE_TEST + +struct GPUFrameBuffer; +struct GPUShader; +struct GPUTexture; +struct GPUUniformBuffer; +struct Object; +struct Batch; + +typedef struct DRWUniform DRWUniform; +typedef struct DRWInterface DRWInterface; +typedef struct DRWPass DRWPass; +typedef struct DRWShadingGroup DRWShadingGroup; + +/* Textures */ + +typedef enum { + DRW_TEX_RGBA_8, + DRW_TEX_RGBA_16, + DRW_TEX_RGBA_32, + DRW_TEX_RGB_8, + DRW_TEX_RGB_16, + DRW_TEX_RGB_32, + DRW_TEX_RG_8, + DRW_TEX_RG_16, + DRW_TEX_RG_32, + DRW_TEX_R_8, + DRW_TEX_R_16, + DRW_TEX_R_32, + DRW_TEX_DEPTH_16, + DRW_TEX_DEPTH_24, + DRW_TEX_DEPTH_32, +} DRWTextureFormat; + +typedef enum { + DRW_TEX_FILTER = (1 << 0), + DRW_TEX_WRAP = (1 << 1), + DRW_TEX_COMPARE = (1 << 2), +} DRWTextureFlag; + +struct GPUTexture *DRW_texture_create_1D( + int w, DRWTextureFormat format, DRWTextureFlag flags, const float *fpixels); +struct GPUTexture *DRW_texture_create_2D( + int w, int h, DRWTextureFormat format, DRWTextureFlag flags, const float *fpixels); +struct GPUTexture *DRW_texture_create_2D_array( + int w, int h, int d, DRWTextureFormat UNUSED(format), DRWTextureFlag flags, const float *fpixels); +void DRW_texture_free(struct GPUTexture *tex); + +/* UBOs */ +struct GPUUniformBuffer *DRW_uniformbuffer_create(int size, const void *data); +void DRW_uniformbuffer_update(struct GPUUniformBuffer *ubo, const void *data); +void DRW_uniformbuffer_free(struct GPUUniformBuffer *ubo); + +/* Buffers */ + +/* DRWFboTexture->format */ +#define DRW_BUF_DEPTH_16 1 +#define DRW_BUF_DEPTH_24 2 +#define DRW_BUF_R_8 3 +#define DRW_BUF_R_16 4 +#define DRW_BUF_R_32 5 +#define DRW_BUF_RG_8 6 +#define DRW_BUF_RG_16 7 +#define DRW_BUF_RG_32 8 +#define DRW_BUF_RGB_8 9 +#define DRW_BUF_RGB_16 10 +#define DRW_BUF_RGB_32 11 +#define DRW_BUF_RGBA_8 12 +#define DRW_BUF_RGBA_16 13 +#define DRW_BUF_RGBA_32 14 + +#define MAX_FBO_TEX 5 + +typedef struct DRWFboTexture { + struct GPUTexture **tex; + int format; +} DRWFboTexture; + +void DRW_framebuffer_init(struct GPUFrameBuffer **fb, int width, int height, DRWFboTexture textures[MAX_FBO_TEX], int texnbr); +void DRW_framebuffer_bind(struct GPUFrameBuffer *fb); +void DRW_framebuffer_texture_attach(struct GPUFrameBuffer *fb, struct GPUTexture *tex, int slot); +void DRW_framebuffer_texture_detach(struct GPUTexture *tex); +/* Shaders */ +struct GPUShader *DRW_shader_create(const char *vert, const char *geom, const char *frag, const char *defines); +struct GPUShader *DRW_shader_create_2D(const char *frag, const char *defines); +struct GPUShader *DRW_shader_create_3D(const char *frag, const char *defines); +struct GPUShader *DRW_shader_create_3D_depth_only(void); +void DRW_shader_free(struct GPUShader *shader); + +/* Batches */ + +typedef enum { + DRW_STATE_WRITE_DEPTH = (1 << 0), + DRW_STATE_WRITE_COLOR = (1 << 1), + DRW_STATE_DEPTH_LESS = (1 << 2), + DRW_STATE_DEPTH_EQUAL = (1 << 3), + DRW_STATE_CULL_BACK = (1 << 4), + DRW_STATE_CULL_FRONT = (1 << 5), + DRW_STATE_WIRE = (1 << 6), + DRW_STATE_WIRE_LARGE = (1 << 7), + DRW_STATE_POINT = (1 << 8), + DRW_STATE_STIPPLE_2 = (1 << 9), + DRW_STATE_STIPPLE_3 = (1 << 10), + DRW_STATE_STIPPLE_4 = (1 << 11), + DRW_STATE_BLEND = (1 << 12), +} DRWState; + +/* Used by DRWShadingGroup.dyntype */ +#define DRW_DYN_POINTS 1 +#define DRW_DYN_LINES 2 +#define DRW_DYN_INSTANCE 3 + +DRWShadingGroup *DRW_shgroup_create(struct GPUShader *shader, DRWPass *pass); +void DRW_shgroup_free(struct DRWShadingGroup *shgroup); +void DRW_shgroup_call_add(DRWShadingGroup *shgroup, struct Batch *geom, float (*obmat)[4]); +void DRW_shgroup_state_set(DRWShadingGroup *shgroup, DRWState state); +void DRW_shgroup_dyntype_set(DRWShadingGroup *shgroup, int type); + +void DRW_shgroup_uniform_texture(DRWShadingGroup *shgroup, const char *name, const struct GPUTexture *tex, int loc); +void DRW_shgroup_uniform_block(DRWShadingGroup *shgroup, const char *name, const struct GPUUniformBuffer *ubo, int loc); +void DRW_shgroup_uniform_buffer(DRWShadingGroup *shgroup, const char *name, const int value, int loc); +void DRW_shgroup_uniform_bool(DRWShadingGroup *shgroup, const char *name, const bool *value, int arraysize); +void DRW_shgroup_uniform_float(DRWShadingGroup *shgroup, const char *name, const float *value, int arraysize); +void DRW_shgroup_uniform_vec2(DRWShadingGroup *shgroup, const char *name, const float *value, int arraysize); +void DRW_shgroup_uniform_vec3(DRWShadingGroup *shgroup, const char *name, const float *value, int arraysize); +void DRW_shgroup_uniform_vec4(DRWShadingGroup *shgroup, const char *name, const float *value, int arraysize); +void DRW_shgroup_uniform_int(DRWShadingGroup *shgroup, const char *name, const int *value, int arraysize); +void DRW_shgroup_uniform_ivec2(DRWShadingGroup *shgroup, const char *name, const int *value, int arraysize); +void DRW_shgroup_uniform_ivec3(DRWShadingGroup *shgroup, const char *name, const int *value, int arraysize); +void DRW_shgroup_uniform_mat3(DRWShadingGroup *shgroup, const char *name, const float *value); +void DRW_shgroup_uniform_mat4(DRWShadingGroup *shgroup, const char *name, const float *value); + +/* Passes */ +DRWPass *DRW_pass_create(const char *name, DRWState state); +DRWShadingGroup *DRW_pass_nth_shgroup_get(DRWPass *pass, int n); + +/* Viewport */ +typedef enum { + DRW_MAT_PERS, + DRW_MAT_WIEW, + DRW_MAT_WIN, +} DRWViewportMatrixType; + +void DRW_viewport_init(const bContext *C, void **buffers, void **textures, void **passes); +void DRW_viewport_matrix_get(float mat[4][4], DRWViewportMatrixType type); +float *DRW_viewport_size_get(void); +float *DRW_viewport_screenvecs_get(void); +float *DRW_viewport_pixelsize_get(void); +bool DRW_viewport_is_persp_get(void); +bool DRW_viewport_cache_is_dirty(void); + +/* Settings */ +#ifndef __DRW_ENGINE_H__ +void *DRW_material_settings_get(Material *ma, const char *engine_name); +void *DRW_render_settings_get(Scene *scene, const char *engine_name); +#endif /* __DRW_ENGINE_H__ */ + +/* Draw commands */ +void DRW_draw_background(void); +void DRW_centercircle(const float co[3]); +void DRW_draw_pass(DRWPass *pass); + +void DRW_state_reset(void); + +/* Other */ +void DRW_get_dfdy_factors(float dfdyfac[2]); + +#endif /* __DRW_RENDER_H__ */
\ No newline at end of file diff --git a/source/blender/draw/intern/draw_cache.c b/source/blender/draw/intern/draw_cache.c new file mode 100644 index 00000000000..1255a083b82 --- /dev/null +++ b/source/blender/draw/intern/draw_cache.c @@ -0,0 +1,543 @@ +/* + * 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 + * + */ + +/** \file draw_cache.c + * \ingroup draw + */ + + +#include "DNA_scene_types.h" +#include "DNA_mesh_types.h" +#include "DNA_object_types.h" + +#include "BLI_utildefines.h" +#include "BLI_math.h" + +#include "BKE_mesh_render.h" + +#include "GPU_batch.h" + +#include "draw_cache.h" + +static struct DRWShapeCache{ + Batch *drw_single_vertice; + Batch *drw_fullscreen_quad; + Batch *drw_plain_axes; + Batch *drw_single_arrow; + Batch *drw_single_arrow_line; + Batch *drw_cube; + Batch *drw_circle; + Batch *drw_empty_sphere; + Batch *drw_empty_cone; + Batch *drw_arrows; + Batch *drw_lamp; + Batch *drw_lamp_sunrays; +} SHC = {NULL}; + +void DRW_shape_cache_free(void) +{ + if (SHC.drw_single_vertice) + Batch_discard_all(SHC.drw_single_vertice); + if (SHC.drw_fullscreen_quad) + Batch_discard_all(SHC.drw_fullscreen_quad); + if (SHC.drw_plain_axes) + Batch_discard_all(SHC.drw_plain_axes); + if (SHC.drw_single_arrow) + Batch_discard_all(SHC.drw_single_arrow); + if (SHC.drw_single_arrow_line) + Batch_discard_all(SHC.drw_single_arrow_line); + if (SHC.drw_cube) + Batch_discard_all(SHC.drw_cube); + if (SHC.drw_circle) + Batch_discard_all(SHC.drw_circle); + if (SHC.drw_empty_sphere) + Batch_discard_all(SHC.drw_empty_sphere); + if (SHC.drw_empty_cone) + Batch_discard_all(SHC.drw_empty_cone); + if (SHC.drw_arrows) + Batch_discard_all(SHC.drw_arrows); + if (SHC.drw_lamp) + Batch_discard_all(SHC.drw_lamp); + if (SHC.drw_lamp_sunrays) + Batch_discard_all(SHC.drw_lamp_sunrays); +} + +/* Quads */ +Batch *DRW_cache_fullscreen_quad_get(void) +{ + if (!SHC.drw_fullscreen_quad) { + float v1[2] = {-1.0f, -1.0f}; + float v2[2] = { 1.0f, -1.0f}; + float v3[2] = {-1.0f, 1.0f}; + float v4[2] = { 1.0f, 1.0f}; + + /* Position Only 3D format */ + static VertexFormat format = { 0 }; + static unsigned pos_id; + if (format.attrib_ct == 0) { + pos_id = add_attrib(&format, "pos", GL_FLOAT, 3, KEEP_FLOAT); + } + + VertexBuffer *vbo = VertexBuffer_create_with_format(&format); + VertexBuffer_allocate_data(vbo, 6); + + setAttrib(vbo, pos_id, 0, v1); + setAttrib(vbo, pos_id, 1, v2); + setAttrib(vbo, pos_id, 2, v3); + + setAttrib(vbo, pos_id, 3, v2); + setAttrib(vbo, pos_id, 4, v3); + setAttrib(vbo, pos_id, 5, v4); + + SHC.drw_fullscreen_quad = Batch_create(GL_TRIANGLES, vbo, NULL); + } + return SHC.drw_fullscreen_quad; +} + +/* Common */ + +Batch *DRW_cache_cube_get(void) +{ + if (!SHC.drw_cube) { + const GLfloat verts[8][3] = { + {-1.0f, -1.0f, -1.0f}, + {-1.0f, -1.0f, 1.0f}, + {-1.0f, 1.0f, -1.0f}, + {-1.0f, 1.0f, 1.0f}, + { 1.0f, -1.0f, -1.0f}, + { 1.0f, -1.0f, 1.0f}, + { 1.0f, 1.0f, -1.0f}, + { 1.0f, 1.0f, 1.0f} + }; + + const GLubyte indices[24] = {0,1,1,3,3,2,2,0,0,4,4,5,5,7,7,6,6,4,1,5,3,7,2,6}; + + /* Position Only 3D format */ + static VertexFormat format = { 0 }; + static unsigned pos_id; + if (format.attrib_ct == 0) { + pos_id = add_attrib(&format, "pos", GL_FLOAT, 3, KEEP_FLOAT); + } + + VertexBuffer *vbo = VertexBuffer_create_with_format(&format); + VertexBuffer_allocate_data(vbo, 24); + + for (int i = 0; i < 24; ++i) { + setAttrib(vbo, pos_id, i, verts[indices[i]]); + } + + SHC.drw_cube = Batch_create(GL_LINES, vbo, NULL); + } + return SHC.drw_cube; +} + + +Batch *DRW_cache_circle_get(void) +{ +#define CIRCLE_RESOL 32 + if (!SHC.drw_circle) { + float v[3] = {0.0f, 0.0f, 0.0f}; + + /* Position Only 3D format */ + static VertexFormat format = { 0 }; + static unsigned pos_id; + if (format.attrib_ct == 0) { + pos_id = add_attrib(&format, "pos", GL_FLOAT, 3, KEEP_FLOAT); + } + + VertexBuffer *vbo = VertexBuffer_create_with_format(&format); + VertexBuffer_allocate_data(vbo, CIRCLE_RESOL * 2); + + for (int a = 0; a < CIRCLE_RESOL; a++) { + v[0] = sinf((2.0f * M_PI * a) / ((float)CIRCLE_RESOL)); + v[1] = cosf((2.0f * M_PI * a) / ((float)CIRCLE_RESOL)); + v[2] = 0.0f; + setAttrib(vbo, pos_id, a * 2, v); + + v[0] = sinf((2.0f * M_PI * (a + 1)) / ((float)CIRCLE_RESOL)); + v[1] = cosf((2.0f * M_PI * (a + 1)) / ((float)CIRCLE_RESOL)); + v[2] = 0.0f; + setAttrib(vbo, pos_id, a * 2 + 1, v); + } + + SHC.drw_circle = Batch_create(GL_LINES, vbo, NULL); + } + return SHC.drw_circle; +#undef CIRCLE_RESOL +} + +/* Empties */ +Batch *DRW_cache_plain_axes_get(void) +{ + if (!SHC.drw_plain_axes) { + int axis; + float v1[3] = {0.0f, 0.0f, 0.0f}; + float v2[3] = {0.0f, 0.0f, 0.0f}; + + /* Position Only 3D format */ + static VertexFormat format = { 0 }; + static unsigned pos_id; + if (format.attrib_ct == 0) { + pos_id = add_attrib(&format, "pos", GL_FLOAT, 3, KEEP_FLOAT); + } + + VertexBuffer *vbo = VertexBuffer_create_with_format(&format); + VertexBuffer_allocate_data(vbo, 6); + + for (axis = 0; axis < 3; axis++) { + v1[axis] = 1.0f; + v2[axis] = -1.0f; + + setAttrib(vbo, pos_id, axis * 2, v1); + setAttrib(vbo, pos_id, axis * 2 + 1, v2); + + /* reset v1 & v2 to zero for next axis */ + v1[axis] = v2[axis] = 0.0f; + } + + SHC.drw_plain_axes = Batch_create(GL_LINES, vbo, NULL); + } + return SHC.drw_plain_axes; +} + +Batch *DRW_cache_single_arrow_get(Batch **line) +{ + if (!SHC.drw_single_arrow_line || !SHC.drw_single_arrow) { + float v1[3] = {0.0f, 0.0f, 0.0f}, v2[3], v3[3]; + + /* Position Only 3D format */ + static VertexFormat format = { 0 }; + static unsigned pos_id; + if (format.attrib_ct == 0) { + pos_id = add_attrib(&format, "pos", GL_FLOAT, 3, KEEP_FLOAT); + } + + /* Line */ + VertexBuffer *vbo = VertexBuffer_create_with_format(&format); + VertexBuffer_allocate_data(vbo, 2); + + setAttrib(vbo, pos_id, 0, v1); + v1[2] = 1.0f; + setAttrib(vbo, pos_id, 1, v1); + + SHC.drw_single_arrow_line = Batch_create(GL_LINES, vbo, NULL); + + /* Square Pyramid */ + vbo = VertexBuffer_create_with_format(&format); + VertexBuffer_allocate_data(vbo, 12); + + v2[0] = 0.035f; v2[1] = 0.035f; + v3[0] = -0.035f; v3[1] = 0.035f; + v2[2] = v3[2] = 0.75f; + + for (int sides = 0; sides < 4; sides++) { + if (sides % 2 == 1) { + v2[0] = -v2[0]; + v3[1] = -v3[1]; + } + else { + v2[1] = -v2[1]; + v3[0] = -v3[0]; + } + + setAttrib(vbo, pos_id, sides * 3 + 0, v1); + setAttrib(vbo, pos_id, sides * 3 + 1, v2); + setAttrib(vbo, pos_id, sides * 3 + 2, v3); + } + + SHC.drw_single_arrow = Batch_create(GL_TRIANGLES, vbo, NULL); + } + *line = SHC.drw_single_arrow_line; + return SHC.drw_single_arrow; +} + +Batch *DRW_cache_empty_sphere_get(void) +{ +#define NSEGMENTS 16 + if (!SHC.drw_empty_sphere) { + /* a single ring of vertices */ + float p[NSEGMENTS][2]; + for (int i = 0; i < NSEGMENTS; ++i) { + float angle = 2 * M_PI * ((float)i / (float)NSEGMENTS); + p[i][0] = cosf(angle); + p[i][1] = sinf(angle); + } + + /* Position Only 3D format */ + static VertexFormat format = { 0 }; + static unsigned pos_id; + if (format.attrib_ct == 0) { + pos_id = add_attrib(&format, "pos", GL_FLOAT, 3, KEEP_FLOAT); + } + + VertexBuffer *vbo = VertexBuffer_create_with_format(&format); + VertexBuffer_allocate_data(vbo, NSEGMENTS * 2 * 3); + + for (int axis = 0; axis < 3; ++axis) { + for (int i = 0; i < NSEGMENTS; ++i) { + for (int j = 0; j < 2; ++j) { + float cv[2], v[3]; + + cv[0] = p[(i+j) % NSEGMENTS][0]; + cv[1] = p[(i+j) % NSEGMENTS][1]; + + if (axis == 0) + v[0] = cv[0], v[1] = cv[1], v[2] = 0.0f; + else if (axis == 1) + v[0] = cv[0], v[1] = 0.0f, v[2] = cv[1]; + else + v[0] = 0.0f, v[1] = cv[0], v[2] = cv[1]; + + setAttrib(vbo, pos_id, i*2 + j + (NSEGMENTS * 2 * axis), v); + } + } + } + + SHC.drw_empty_sphere = Batch_create(GL_LINES, vbo, NULL); + } + return SHC.drw_empty_sphere; +#undef NSEGMENTS +} + +Batch *DRW_cache_empty_cone_get(void) +{ +#define NSEGMENTS 8 + if (!SHC.drw_empty_cone) { + /* a single ring of vertices */ + float p[NSEGMENTS][2]; + for (int i = 0; i < NSEGMENTS; ++i) { + float angle = 2 * M_PI * ((float)i / (float)NSEGMENTS); + p[i][0] = cosf(angle); + p[i][1] = sinf(angle); + } + + /* Position Only 3D format */ + static VertexFormat format = { 0 }; + static unsigned pos_id; + if (format.attrib_ct == 0) { + pos_id = add_attrib(&format, "pos", GL_FLOAT, 3, KEEP_FLOAT); + } + + VertexBuffer *vbo = VertexBuffer_create_with_format(&format); + VertexBuffer_allocate_data(vbo, NSEGMENTS * 4); + + for (int i = 0; i < NSEGMENTS; ++i) { + float cv[2], v[3]; + cv[0] = p[(i) % NSEGMENTS][0]; + cv[1] = p[(i) % NSEGMENTS][1]; + + /* cone sides */ + v[0] = cv[0], v[1] = 0.0f, v[2] = cv[1]; + setAttrib(vbo, pos_id, i*4, v); + v[0] = 0.0f, v[1] = 2.0f, v[2] = 0.0f; + setAttrib(vbo, pos_id, i*4 + 1, v); + + /* end ring */ + v[0] = cv[0], v[1] = 0.0f, v[2] = cv[1]; + setAttrib(vbo, pos_id, i*4 + 2, v); + cv[0] = p[(i+1) % NSEGMENTS][0]; + cv[1] = p[(i+1) % NSEGMENTS][1]; + v[0] = cv[0], v[1] = 0.0f, v[2] = cv[1]; + setAttrib(vbo, pos_id, i*4 + 3, v); + } + + SHC.drw_empty_cone = Batch_create(GL_LINES, vbo, NULL); + } + return SHC.drw_empty_cone; +#undef NSEGMENTS +} + +Batch *DRW_cache_arrows_get(void) +{ + if (!SHC.drw_arrows) { + float v1[3] = {0.0, 0.0, 0.0}; + float v2[3] = {0.0, 0.0, 0.0}; + + /* Position Only 3D format */ + static VertexFormat format = { 0 }; + static unsigned pos_id; + if (format.attrib_ct == 0) { + pos_id = add_attrib(&format, "pos", GL_FLOAT, 3, KEEP_FLOAT); + } + + /* Line */ + VertexBuffer *vbo = VertexBuffer_create_with_format(&format); + VertexBuffer_allocate_data(vbo, 6 * 3); + + for (int axis = 0; axis < 3; axis++) { + const int arrow_axis = (axis == 0) ? 1 : 0; + + v2[axis] = 1.0f; + setAttrib(vbo, pos_id, axis * 6 + 0, v1); + setAttrib(vbo, pos_id, axis * 6 + 1, v2); + + v1[axis] = 0.85f; + v1[arrow_axis] = -0.08f; + setAttrib(vbo, pos_id, axis * 6 + 2, v1); + setAttrib(vbo, pos_id, axis * 6 + 3, v2); + + v1[arrow_axis] = 0.08f; + setAttrib(vbo, pos_id, axis * 6 + 4, v1); + setAttrib(vbo, pos_id, axis * 6 + 5, v2); + + /* reset v1 & v2 to zero */ + v1[arrow_axis] = v1[axis] = v2[axis] = 0.0f; + } + + SHC.drw_arrows = Batch_create(GL_LINES, vbo, NULL); + } + return SHC.drw_arrows; +} + +/* Lamps */ +Batch *DRW_cache_lamp_get(void) +{ +#define NSEGMENTS 8 + if (!SHC.drw_lamp) { + float v[2]; + + /* Position Only 3D format */ + static VertexFormat format = { 0 }; + static unsigned pos_id; + if (format.attrib_ct == 0) { + pos_id = add_attrib(&format, "pos", GL_FLOAT, 2, KEEP_FLOAT); + } + + VertexBuffer *vbo = VertexBuffer_create_with_format(&format); + VertexBuffer_allocate_data(vbo, NSEGMENTS * 2); + + for (int a = 0; a < NSEGMENTS; a++) { + v[0] = sinf((2.0f * M_PI * a) / ((float)NSEGMENTS)); + v[1] = cosf((2.0f * M_PI * a) / ((float)NSEGMENTS)); + setAttrib(vbo, pos_id, a * 2, v); + + v[0] = sinf((2.0f * M_PI * (a + 1)) / ((float)NSEGMENTS)); + v[1] = cosf((2.0f * M_PI * (a + 1)) / ((float)NSEGMENTS)); + setAttrib(vbo, pos_id, a * 2 + 1, v); + } + + SHC.drw_lamp = Batch_create(GL_LINES, vbo, NULL); + } + return SHC.drw_lamp; +#undef NSEGMENTS +} + +Batch *DRW_cache_lamp_sunrays_get(void) +{ + if (!SHC.drw_lamp_sunrays) { + float v[2], v1[2], v2[2]; + + /* Position Only 3D format */ + static VertexFormat format = { 0 }; + static unsigned pos_id; + if (format.attrib_ct == 0) { + pos_id = add_attrib(&format, "pos", GL_FLOAT, 2, KEEP_FLOAT); + } + + VertexBuffer *vbo = VertexBuffer_create_with_format(&format); + VertexBuffer_allocate_data(vbo, 16); + + for (int a = 0; a < 8; a++) { + v[0] = sinf((2.0f * M_PI * a) / 8.0f); + v[1] = cosf((2.0f * M_PI * a) / 8.0f); + + mul_v2_v2fl(v1, v, 1.2f); + mul_v2_v2fl(v2, v, 2.5f); + + setAttrib(vbo, pos_id, a * 2, v1); + setAttrib(vbo, pos_id, a * 2 + 1, v2); + } + + SHC.drw_lamp_sunrays = Batch_create(GL_LINES, vbo, NULL); + } + return SHC.drw_lamp_sunrays; +} + + +/* Object Center */ +Batch *DRW_cache_single_vert_get(void) +{ + if (!SHC.drw_single_vertice) { + float v1[3] = {0.0f, 0.0f, 0.0f}; + + /* Position Only 3D format */ + static VertexFormat format = { 0 }; + static unsigned pos_id; + if (format.attrib_ct == 0) { + pos_id = add_attrib(&format, "pos", GL_FLOAT, 3, KEEP_FLOAT); + } + + VertexBuffer *vbo = VertexBuffer_create_with_format(&format); + VertexBuffer_allocate_data(vbo, 1); + + setAttrib(vbo, pos_id, 0, v1); + + SHC.drw_single_vertice = Batch_create(GL_POINTS, vbo, NULL); + } + return SHC.drw_single_vertice; +} + +/* Meshes */ +Batch *DRW_cache_wire_overlay_get(Object *ob) +{ + Batch *overlay_wire = NULL; + + BLI_assert(ob->type == OB_MESH); + + Mesh *me = ob->data; +#if 1 /* new version not working */ + overlay_wire = BKE_mesh_batch_cache_get_overlay_edges(me); +#else + overlay_wire = BKE_mesh_batch_cache_get_all_edges(me); +#endif + return overlay_wire; +} + +Batch *DRW_cache_wire_outline_get(Object *ob) +{ + Batch *fancy_wire = NULL; + + BLI_assert(ob->type == OB_MESH); + + Mesh *me = ob->data; + fancy_wire = BKE_mesh_batch_cache_get_fancy_edges(me); + + return fancy_wire; +} + +Batch *DRW_cache_surface_get(Object *ob) +{ + Batch *surface = NULL; + + BLI_assert(ob->type == OB_MESH); + + Mesh *me = ob->data; + surface = BKE_mesh_batch_cache_get_all_triangles(me); + + return surface; +} + +#if 0 /* TODO */ +struct Batch *DRW_cache_surface_material_get(Object *ob, int nr) { + /* TODO */ + return NULL; +} +#endif
\ No newline at end of file diff --git a/source/blender/draw/intern/draw_cache.h b/source/blender/draw/intern/draw_cache.h new file mode 100644 index 00000000000..c53f3d88af3 --- /dev/null +++ b/source/blender/draw/intern/draw_cache.h @@ -0,0 +1,56 @@ +/* + * 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 + * + */ + +/** \file draw_cache.h + * \ingroup draw + */ + +#ifndef __DRAW_CACHE_H__ +#define __DRAW_CACHE_H__ + +struct Batch; +struct Object; + +void DRW_shape_cache_free(void); + +/* Common Shapes */ +struct Batch *DRW_cache_fullscreen_quad_get(void); +struct Batch *DRW_cache_single_vert_get(void); + +/* Empties */ +struct Batch *DRW_cache_plain_axes_get(void); +struct Batch *DRW_cache_single_arrow_get(struct Batch **line); +struct Batch *DRW_cache_cube_get(void); +struct Batch *DRW_cache_circle_get(void); +struct Batch *DRW_cache_empty_sphere_get(void); +struct Batch *DRW_cache_empty_cone_get(void); +struct Batch *DRW_cache_arrows_get(void); + +/* Lamps */ +struct Batch *DRW_cache_lamp_get(void); +struct Batch *DRW_cache_lamp_sunrays_get(void); + +/* Meshes */ +struct Batch *DRW_cache_wire_overlay_get(struct Object *ob); +struct Batch *DRW_cache_wire_outline_get(struct Object *ob); +struct Batch *DRW_cache_surface_get(struct Object *ob); + +#endif /* __DRAW_CACHE_H__ */
\ No newline at end of file diff --git a/source/blender/draw/intern/draw_manager.c b/source/blender/draw/intern/draw_manager.c new file mode 100644 index 00000000000..a7ce65060e6 --- /dev/null +++ b/source/blender/draw/intern/draw_manager.c @@ -0,0 +1,1148 @@ +/* + * 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 + * + */ + +/** \file blender/draw/draw_manager.c + * \ingroup draw + */ + +#include <stdio.h> + +#include "BLI_listbase.h" +#include "BLI_rect.h" +#include "BLI_string.h" + +#include "BIF_glutil.h" + +#include "BKE_global.h" + +#include "BLT_translation.h" + +#include "DRW_engine.h" +#include "DRW_render.h" + +#include "DNA_view3d_types.h" + +#include "GPU_basic_shader.h" +#include "GPU_batch.h" +#include "GPU_draw.h" +#include "GPU_extensions.h" +#include "GPU_framebuffer.h" +#include "GPU_immediate.h" +#include "GPU_matrix.h" +#include "GPU_shader.h" +#include "GPU_texture.h" +#include "GPU_uniformbuffer.h" +#include "GPU_viewport.h" + +#include "RE_engine.h" + +#include "UI_resources.h" + +#include "clay.h" + +extern char datatoc_gpu_shader_2D_vert_glsl[]; +extern char datatoc_gpu_shader_3D_vert_glsl[]; +extern char datatoc_gpu_shader_basic_vert_glsl[]; + +/* Structures */ +typedef enum { + DRW_UNIFORM_BOOL, + DRW_UNIFORM_INT, + DRW_UNIFORM_FLOAT, + DRW_UNIFORM_TEXTURE, + DRW_UNIFORM_BUFFER, + DRW_UNIFORM_MAT3, + DRW_UNIFORM_MAT4, + DRW_UNIFORM_BLOCK +} DRWUniformType; + +struct DRWUniform { + struct DRWUniform *next, *prev; + DRWUniformType type; + int location; + int length; + int arraysize; + int bindloc; + const void *value; +}; + +struct DRWInterface { + ListBase uniforms; + /* matrices locations */ + int modelview; + int projection; + int modelviewprojection; + int viewprojection; + int normal; + int eye; +}; + +struct DRWPass { + ListBase shgroups; + DRWState state; + float state_param; /* Line / Point width */ +}; + +typedef struct DRWCall { + struct DRWCall *next, *prev; + Batch *geometry; + float(*obmat)[4]; +} DRWCall; + +struct DRWShadingGroup { + struct DRWShadingGroup *next, *prev; + struct GPUShader *shader; /* Shader to bind */ + struct DRWInterface *interface; /* Uniforms pointers */ + ListBase calls; /* List with all geometry and transforms */ + int state; /* State changes for this batch only */ + short dyntype; /* Dynamic Batch type, 0 is normal */ + Batch *dyngeom; /* Dynamic batch */ + GLuint instance_vbo; /* Dynamic batch VBO storing Model Matrices */ + int instance_count; /* Dynamic batch Number of instance to render */ +}; + +/* Render State */ +static struct DRWGlobalState{ + GPUShader *shader; + struct GPUFrameBuffer *default_framebuffer; + FramebufferList *current_fbl; + TextureList *current_txl; + PassList *current_psl; + ListBase bound_texs; + int tex_bind_id; + float size[2]; + float screenvecs[2][3]; + float pixsize; + /* Current rendering context set by DRW_viewport_init */ + const struct bContext *context; +} DST = {NULL}; + +/* ***************************************** TEXTURES ******************************************/ +static void drw_texture_get_format(DRWTextureFormat format, GPUTextureFormat *data_type, int *channels) +{ + switch (format) { + case DRW_TEX_RGBA_8: *data_type = GPU_RGBA8; break; + case DRW_TEX_RGBA_16: *data_type = GPU_RGBA16F; break; + case DRW_TEX_RG_16: *data_type = GPU_RG16F; break; + case DRW_TEX_RG_32: *data_type = GPU_RG32F; break; + case DRW_TEX_R_8: *data_type = GPU_R8; break; +#if 0 + case DRW_TEX_RGBA_32: *data_type = GPU_RGBA32F; break; + case DRW_TEX_RGB_8: *data_type = GPU_RGB8; break; + case DRW_TEX_RGB_16: *data_type = GPU_RGB16F; break; + case DRW_TEX_RGB_32: *data_type = GPU_RGB32F; break; + case DRW_TEX_RG_8: *data_type = GPU_RG8; break; + case DRW_TEX_R_16: *data_type = GPU_R16F; break; + case DRW_TEX_R_32: *data_type = GPU_R32F; break; +#endif + case DRW_TEX_DEPTH_16: *data_type = GPU_DEPTH_COMPONENT16; break; + case DRW_TEX_DEPTH_24: *data_type = GPU_DEPTH_COMPONENT24; break; + case DRW_TEX_DEPTH_32: *data_type = GPU_DEPTH_COMPONENT32F; break; + default : + /* file type not supported you must uncomment it from above */ + BLI_assert(false); + break; + } + + switch (format) { + case DRW_TEX_RGBA_8: + case DRW_TEX_RGBA_16: + case DRW_TEX_RGBA_32: + *channels = 4; + break; + case DRW_TEX_RGB_8: + case DRW_TEX_RGB_16: + case DRW_TEX_RGB_32: + *channels = 3; + break; + case DRW_TEX_RG_8: + case DRW_TEX_RG_16: + case DRW_TEX_RG_32: + *channels = 2; + break; + default: + *channels = 1; + break; + } +} + +static void drw_texture_set_parameters(GPUTexture *tex, DRWTextureFlag flags) +{ + GPU_texture_bind(tex, 0); + GPU_texture_filter_mode(tex, flags & DRW_TEX_FILTER); + GPU_texture_wrap_mode(tex, flags & DRW_TEX_WRAP); + GPU_texture_compare_mode(tex, flags & DRW_TEX_COMPARE); + GPU_texture_unbind(tex); +} + +GPUTexture *DRW_texture_create_1D(int w, DRWTextureFormat format, DRWTextureFlag flags, const float *fpixels) +{ + GPUTexture *tex; + GPUTextureFormat data_type; + int channels; + + drw_texture_get_format(format, &data_type, &channels); + tex = GPU_texture_create_1D_custom(w, channels, data_type, fpixels, NULL); + drw_texture_set_parameters(tex, flags); + + return tex; +} + +GPUTexture *DRW_texture_create_2D(int w, int h, DRWTextureFormat format, DRWTextureFlag flags, const float *fpixels) +{ + GPUTexture *tex; + GPUTextureFormat data_type; + int channels; + + drw_texture_get_format(format, &data_type, &channels); + tex = GPU_texture_create_2D_custom(w, h, channels, data_type, fpixels, NULL); + drw_texture_set_parameters(tex, flags); + + return tex; +} + +/* TODO make use of format */ +GPUTexture *DRW_texture_create_2D_array(int w, int h, int d, DRWTextureFormat UNUSED(format), DRWTextureFlag flags, const float *fpixels) +{ + GPUTexture *tex; + + tex = GPU_texture_create_2D_array(w, h, d, fpixels, NULL); + drw_texture_set_parameters(tex, flags); + + return tex; +} + +void DRW_texture_free(GPUTexture *tex) +{ + GPU_texture_free(tex); +} + + +/* ************************************ UNIFORM BUFFER OBJECT **********************************/ + +GPUUniformBuffer *DRW_uniformbuffer_create(int size, const void *data) +{ + return GPU_uniformbuffer_create(size, data, NULL); +} + +void DRW_uniformbuffer_update(GPUUniformBuffer *ubo, const void *data) +{ + GPU_uniformbuffer_update(ubo, data); +} + +void DRW_uniformbuffer_free(GPUUniformBuffer *ubo) +{ + GPU_uniformbuffer_free(ubo); +} + +/* ****************************************** SHADERS ******************************************/ + +GPUShader *DRW_shader_create(const char *vert, const char *geom, const char *frag, const char *defines) +{ + return GPU_shader_create(vert, frag, geom, NULL, defines, 0, 0, 0); +} + +GPUShader *DRW_shader_create_2D(const char *frag, const char *defines) +{ + return GPU_shader_create(datatoc_gpu_shader_2D_vert_glsl, frag, NULL, NULL, defines, 0, 0, 0); +} + +GPUShader *DRW_shader_create_3D(const char *frag, const char *defines) +{ + return GPU_shader_create(datatoc_gpu_shader_3D_vert_glsl, frag, NULL, NULL, defines, 0, 0, 0); +} + +GPUShader *DRW_shader_create_3D_depth_only(void) +{ + return GPU_shader_get_builtin_shader(GPU_SHADER_3D_DEPTH_ONLY); +} + +void DRW_shader_free(GPUShader *shader) +{ + GPU_shader_free(shader); +} + +/* ***************************************** INTERFACE ******************************************/ + +static DRWInterface *DRW_interface_create(GPUShader *shader) +{ + DRWInterface *interface = MEM_mallocN(sizeof(DRWInterface), "DRWInterface"); + + interface->modelview = GPU_shader_get_uniform(shader, "ModelViewMatrix"); + interface->projection = GPU_shader_get_uniform(shader, "ProjectionMatrix"); + interface->viewprojection = GPU_shader_get_uniform(shader, "ViewProjectionMatrix"); + interface->modelviewprojection = GPU_shader_get_uniform(shader, "ModelViewProjectionMatrix"); + interface->normal = GPU_shader_get_uniform(shader, "NormalMatrix"); + interface->eye = GPU_shader_get_uniform(shader, "eye"); + + BLI_listbase_clear(&interface->uniforms); + + return interface; +} + +static void DRW_interface_uniform(DRWShadingGroup *shgroup, const char *name, + DRWUniformType type, const void *value, int length, int arraysize, int bindloc) +{ + DRWUniform *uni = MEM_mallocN(sizeof(DRWUniform), "DRWUniform"); + + if (type == DRW_UNIFORM_BLOCK) { + uni->location = GPU_shader_get_uniform_block(shgroup->shader, name); + } + else { + uni->location = GPU_shader_get_uniform(shgroup->shader, name); + } + + uni->type = type; + uni->value = value; + uni->length = length; + uni->arraysize = arraysize; + uni->bindloc = bindloc; /* for textures */ + + if (uni->location == -1) { + if (G.debug & G_DEBUG) + fprintf(stderr, "Uniform '%s' not found!\n", name); + + MEM_freeN(uni); + return; + } + + BLI_addtail(&shgroup->interface->uniforms, uni); +} + +void DRW_get_dfdy_factors(float dfdyfac[2]) +{ + GPU_get_dfdy_factors(dfdyfac); +} + +/* ***************************************** SHADING GROUP ******************************************/ + +DRWShadingGroup *DRW_shgroup_create(struct GPUShader *shader, DRWPass *pass) +{ + DRWShadingGroup *shgroup = MEM_callocN(sizeof(DRWShadingGroup), "DRWShadingGroup"); + + shgroup->shader = shader; + shgroup->interface = DRW_interface_create(shader); + shgroup->state = 0; + shgroup->dyntype = 0; + shgroup->dyngeom = NULL; + + BLI_addtail(&pass->shgroups, shgroup); + + return shgroup; +} + +void DRW_shgroup_free(struct DRWShadingGroup *shgroup) +{ + BLI_freelistN(&shgroup->calls); + BLI_freelistN(&shgroup->interface->uniforms); + MEM_freeN(shgroup->interface); + + if (shgroup->dyngeom) + Batch_discard_all(shgroup->dyngeom); +} + +/* Later use VBO */ +void DRW_shgroup_call_add(DRWShadingGroup *shgroup, Batch *geom, float (*obmat)[4]) +{ + if (geom) { + DRWCall *call = MEM_callocN(sizeof(DRWCall), "DRWCall"); + + call->obmat = obmat; + call->geometry = geom; + + BLI_addtail(&shgroup->calls, call); + } +} + +/* Make sure you know what you do when using this, + * State is not revert back at the end of the shgroup */ +void DRW_shgroup_state_set(DRWShadingGroup *shgroup, DRWState state) +{ + shgroup->state = state; +} + +void DRW_shgroup_dyntype_set(DRWShadingGroup *shgroup, int type) +{ + shgroup->dyntype = type; +} + +void DRW_shgroup_uniform_texture(DRWShadingGroup *shgroup, const char *name, const GPUTexture *tex, int loc) +{ + DRW_interface_uniform(shgroup, name, DRW_UNIFORM_TEXTURE, tex, 0, 0, loc); +} + +void DRW_shgroup_uniform_block(DRWShadingGroup *shgroup, const char *name, const GPUUniformBuffer *ubo, int loc) +{ + DRW_interface_uniform(shgroup, name, DRW_UNIFORM_BLOCK, ubo, 0, 0, loc); +} + +void DRW_shgroup_uniform_buffer(DRWShadingGroup *shgroup, const char *name, const int value, int loc) +{ + /* we abuse the lenght attrib to store the buffer index */ + DRW_interface_uniform(shgroup, name, DRW_UNIFORM_BUFFER, NULL, value, 0, loc); +} + +void DRW_shgroup_uniform_bool(DRWShadingGroup *shgroup, const char *name, const bool *value, int arraysize) +{ + DRW_interface_uniform(shgroup, name, DRW_UNIFORM_BOOL, value, 1, arraysize, 0); +} + +void DRW_shgroup_uniform_float(DRWShadingGroup *shgroup, const char *name, const float *value, int arraysize) +{ + DRW_interface_uniform(shgroup, name, DRW_UNIFORM_FLOAT, value, 1, arraysize, 0); +} + +void DRW_shgroup_uniform_vec2(DRWShadingGroup *shgroup, const char *name, const float *value, int arraysize) +{ + DRW_interface_uniform(shgroup, name, DRW_UNIFORM_FLOAT, value, 2, arraysize, 0); +} + +void DRW_shgroup_uniform_vec3(DRWShadingGroup *shgroup, const char *name, const float *value, int arraysize) +{ + DRW_interface_uniform(shgroup, name, DRW_UNIFORM_FLOAT, value, 3, arraysize, 0); +} + +void DRW_shgroup_uniform_vec4(DRWShadingGroup *shgroup, const char *name, const float *value, int arraysize) +{ + DRW_interface_uniform(shgroup, name, DRW_UNIFORM_FLOAT, value, 4, arraysize, 0); +} + +void DRW_shgroup_uniform_int(DRWShadingGroup *shgroup, const char *name, const int *value, int arraysize) +{ + DRW_interface_uniform(shgroup, name, DRW_UNIFORM_INT, value, 1, arraysize, 0); +} + +void DRW_shgroup_uniform_ivec2(DRWShadingGroup *shgroup, const char *name, const int *value, int arraysize) +{ + DRW_interface_uniform(shgroup, name, DRW_UNIFORM_INT, value, 2, arraysize, 0); +} + +void DRW_shgroup_uniform_ivec3(DRWShadingGroup *shgroup, const char *name, const int *value, int arraysize) +{ + DRW_interface_uniform(shgroup, name, DRW_UNIFORM_INT, value, 3, arraysize, 0); +} + +void DRW_shgroup_uniform_mat3(DRWShadingGroup *shgroup, const char *name, const float *value) +{ + DRW_interface_uniform(shgroup, name, DRW_UNIFORM_MAT3, value, 9, 1, 0); +} + +void DRW_shgroup_uniform_mat4(DRWShadingGroup *shgroup, const char *name, const float *value) +{ + DRW_interface_uniform(shgroup, name, DRW_UNIFORM_MAT4, value, 16, 1, 0); +} + +/* Creates OGL primitives based on DRWCall.obmat position list */ +static void shgroup_dynamic_batch_primitives(DRWShadingGroup *shgroup) +{ + int i = 0; + int nbr = BLI_listbase_count(&shgroup->calls); + GLenum type; + + if (nbr == 0) { + if (shgroup->dyngeom) { + Batch_discard(shgroup->dyngeom); + shgroup->dyngeom = NULL; + } + return; + } + + /* Gather Data */ + float *data = MEM_mallocN(sizeof(float) * 3 * nbr , "Object Center Batch data"); + + for (DRWCall *call = shgroup->calls.first; call; call = call->next, i++) { + copy_v3_v3(&data[i*3], call->obmat[3]); + } + + /* Upload Data */ + static VertexFormat format = { 0 }; + static unsigned pos_id; + if (format.attrib_ct == 0) { + pos_id = add_attrib(&format, "pos", GL_FLOAT, 3, KEEP_FLOAT); + } + + VertexBuffer *vbo = VertexBuffer_create_with_format(&format); + VertexBuffer_allocate_data(vbo, nbr); + + fillAttrib(vbo, pos_id, data); + + if (shgroup->dyntype == DRW_DYN_POINTS) + type = GL_POINTS; + else + type = GL_LINES; + + /* TODO make the batch dynamic instead of freeing it every times */ + if (shgroup->dyngeom) + Batch_discard_all(shgroup->dyngeom); + + shgroup->dyngeom = Batch_create(type, vbo, NULL); + + MEM_freeN(data); +} + +static void shgroup_dynamic_batch_instance(DRWShadingGroup *shgroup) +{ + int i = 0; + int nbr = BLI_listbase_count(&shgroup->calls); + + shgroup->instance_count = nbr; + + if (nbr == 0) { + if (shgroup->instance_vbo) { + glDeleteBuffers(1, &shgroup->instance_vbo); + shgroup->instance_vbo = 0; + } + return; + } + + /* Gather Data */ + float *data = MEM_mallocN(sizeof(float) * 4 * 4 * nbr , "Instance Model Matrix"); + + for (DRWCall *call = shgroup->calls.first; call; call = call->next, i++) { + copy_m4_m4((float (*)[4])&data[i*16], call->obmat); + } + + /* TODO poke mike to add this to gawain */ + if (shgroup->instance_vbo) { + glDeleteBuffers(1, &shgroup->instance_vbo); + shgroup->instance_vbo = 0; + } + + glGenBuffers(1, &shgroup->instance_vbo); + glBindBuffer(GL_ARRAY_BUFFER, shgroup->instance_vbo); + glBufferData(GL_ARRAY_BUFFER, sizeof(float) * 4 * 4 * nbr, data, GL_STATIC_DRAW); + + MEM_freeN(data); +} + +static void shgroup_dynamic_batch_from_calls(DRWShadingGroup *shgroup) +{ +#ifdef WITH_VIEWPORT_CACHE_TEST + if (shgroup->dyngeom) return; +#endif + if (shgroup->dyntype == DRW_DYN_INSTANCE) { + shgroup_dynamic_batch_instance(shgroup); + } + else { + shgroup_dynamic_batch_primitives(shgroup); + } +} + +/* ***************************************** PASSES ******************************************/ + +DRWPass *DRW_pass_create(const char *name, DRWState state) +{ + DRWPass *pass = MEM_callocN(sizeof(DRWPass), name); + pass->state = state; + + BLI_listbase_clear(&pass->shgroups); + + return pass; +} + +void DRW_pass_free(DRWPass *pass) +{ + for (DRWShadingGroup *shgroup = pass->shgroups.first; shgroup; shgroup = shgroup->next) { + DRW_shgroup_free(shgroup); + } + BLI_freelistN(&pass->shgroups); +} + +/* TODO this is slow we should not have to use this (better store shgroup pointer somewhere) */ +DRWShadingGroup *DRW_pass_nth_shgroup_get(DRWPass *pass, int n) +{ + int i = 0; + for (DRWShadingGroup *shgroup = pass->shgroups.first; shgroup; shgroup = shgroup->next) { + if (i == n) + return shgroup; + i++; + } + + return NULL; +} + +/* ****************************************** DRAW ******************************************/ + +void DRW_draw_background(void) +{ + /* Just to make sure */ + glDepthMask(GL_TRUE); + glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); + + if (UI_GetThemeValue(TH_SHOW_BACK_GRAD)) { + /* Gradient background Color */ + gpuMatrixBegin3D(); /* TODO: finish 2D API */ + + glClear(GL_DEPTH_BUFFER_BIT); + + VertexFormat *format = immVertexFormat(); + unsigned pos = add_attrib(format, "pos", COMP_F32, 2, KEEP_FLOAT); + unsigned color = add_attrib(format, "color", COMP_U8, 3, NORMALIZE_INT_TO_FLOAT); + unsigned char col_hi[3], col_lo[3]; + + immBindBuiltinProgram(GPU_SHADER_2D_SMOOTH_COLOR); + + UI_GetThemeColor3ubv(TH_LOW_GRAD, col_lo); + UI_GetThemeColor3ubv(TH_HIGH_GRAD, col_hi); + + immBegin(GL_QUADS, 4); + immAttrib3ubv(color, col_lo); + immVertex2f(pos, -1.0f, -1.0f); + immVertex2f(pos, 1.0f, -1.0f); + + immAttrib3ubv(color, col_hi); + immVertex2f(pos, 1.0f, 1.0f); + immVertex2f(pos, -1.0f, 1.0f); + immEnd(); + + immUnbindProgram(); + + gpuMatrixEnd(); + } + else { + /* Solid background Color */ + UI_ThemeClearColorAlpha(TH_HIGH_GRAD, 1.0f); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + } +} +#ifdef WITH_CLAY_ENGINE +/* Only alter the state (does not reset it like set_state() ) */ +static void shgroup_set_state(DRWShadingGroup *shgroup) +{ + if (shgroup->state) { + /* Blend */ + if (shgroup->state & DRW_STATE_BLEND) { + glEnable(GL_BLEND); + } + + /* Wire width */ + if (shgroup->state & DRW_STATE_WIRE) { + glLineWidth(1.0f); + } + else if (shgroup->state & DRW_STATE_WIRE_LARGE) { + glLineWidth(UI_GetThemeValuef(TH_OUTLINE_WIDTH) * 2.0f); + } + + /* Line Stipple */ + if (shgroup->state & DRW_STATE_STIPPLE_2) { + setlinestyle(2); + } + else if (shgroup->state & DRW_STATE_STIPPLE_3) { + setlinestyle(3); + } + else if (shgroup->state & DRW_STATE_STIPPLE_4) { + setlinestyle(4); + } + + if (shgroup->state & DRW_STATE_POINT) { + GPU_enable_program_point_size(); + glPointSize(5.0f); + } + } +} + +typedef struct DRWBoundTexture { + struct DRWBoundTexture *next, *prev; + GPUTexture *tex; +} DRWBoundTexture; + +static void draw_geometry(DRWShadingGroup *shgroup, DRWInterface *interface, Batch *geom, + unsigned int instance_vbo, int instance_count, const float (*obmat)[4]) +{ + RegionView3D *rv3d = CTX_wm_region_view3d(DST.context); + + float mvp[4][4], mv[4][4], n[3][3]; + float eye[3] = { 0.0f, 0.0f, 1.0f }; /* looking into the screen */ + + bool do_mvp = (interface->modelviewprojection != -1); + bool do_mv = (interface->modelview != -1); + bool do_n = (interface->normal != -1); + bool do_eye = (interface->eye != -1); + + if (do_mvp) { + mul_m4_m4m4(mvp, rv3d->persmat, obmat); + } + if (do_mv || do_n || do_eye) { + mul_m4_m4m4(mv, rv3d->viewmat, obmat); + } + if (do_n || do_eye) { + copy_m3_m4(n, mv); + invert_m3(n); + transpose_m3(n); + } + if (do_eye) { + /* Used by orthographic wires */ + float tmp[3][3]; + invert_m3_m3(tmp, n); + /* set eye vector, transformed to object coords */ + mul_m3_v3(tmp, eye); + } + + /* Should be really simple */ + /* step 1 : bind object dependent matrices */ + if (interface->modelviewprojection != -1) { + GPU_shader_uniform_vector(shgroup->shader, interface->modelviewprojection, 16, 1, (float *)mvp); + } + if (interface->viewprojection != -1) { + GPU_shader_uniform_vector(shgroup->shader, interface->viewprojection, 16, 1, (float *)rv3d->persmat); + } + if (interface->projection != -1) { + GPU_shader_uniform_vector(shgroup->shader, interface->projection, 16, 1, (float *)rv3d->winmat); + } + if (interface->modelview != -1) { + GPU_shader_uniform_vector(shgroup->shader, interface->modelview, 16, 1, (float *)mv); + } + if (interface->normal != -1) { + GPU_shader_uniform_vector(shgroup->shader, interface->normal, 9, 1, (float *)n); + } + if (interface->eye != -1) { + GPU_shader_uniform_vector(shgroup->shader, interface->eye, 3, 1, (float *)eye); + } + + /* step 2 : bind vertex array & draw */ + Batch_set_program(geom, GPU_shader_get_program(shgroup->shader)); + if (instance_vbo) { + Batch_draw_stupid_instanced(geom, instance_vbo, instance_count); + } + else { + Batch_draw_stupid(geom); + } +} + +static void draw_shgroup(DRWShadingGroup *shgroup) +{ + BLI_assert(shgroup->shader); + BLI_assert(shgroup->interface); + + DRWInterface *interface = shgroup->interface; + + if (DST.shader != shgroup->shader) { + if (DST.shader) GPU_shader_unbind(); + GPU_shader_bind(shgroup->shader); + DST.shader = shgroup->shader; + } + + if (shgroup->dyntype != 0) { + shgroup_dynamic_batch_from_calls(shgroup); + } + + shgroup_set_state(shgroup); + + /* Binding Uniform */ + /* Don't check anything, Interface should already contain the least uniform as possible */ + for (DRWUniform *uni = interface->uniforms.first; uni; uni = uni->next) { + DRWBoundTexture *bound_tex; + + switch (uni->type) { + case DRW_UNIFORM_BOOL: + case DRW_UNIFORM_INT: + GPU_shader_uniform_vector_int(shgroup->shader, uni->location, uni->length, uni->arraysize, (int *)uni->value); + break; + case DRW_UNIFORM_FLOAT: + case DRW_UNIFORM_MAT3: + case DRW_UNIFORM_MAT4: + GPU_shader_uniform_vector(shgroup->shader, uni->location, uni->length, uni->arraysize, (float *)uni->value); + break; + case DRW_UNIFORM_TEXTURE: + GPU_texture_bind((GPUTexture *)uni->value, uni->bindloc); + + bound_tex = MEM_callocN(sizeof(DRWBoundTexture), "DRWBoundTexture"); + bound_tex->tex = (GPUTexture *)uni->value; + BLI_addtail(&DST.bound_texs, bound_tex); + + GPU_shader_uniform_texture(shgroup->shader, uni->location, (GPUTexture *)uni->value); + break; + case DRW_UNIFORM_BUFFER: + /* restore index from lenght we abused */ + GPU_texture_bind(DST.current_txl->textures[uni->length], uni->bindloc); + GPU_texture_compare_mode(DST.current_txl->textures[uni->length], false); + GPU_texture_filter_mode(DST.current_txl->textures[uni->length], false); + + bound_tex = MEM_callocN(sizeof(DRWBoundTexture), "DRWBoundTexture"); + bound_tex->tex = DST.current_txl->textures[uni->length]; + BLI_addtail(&DST.bound_texs, bound_tex); + + GPU_shader_uniform_texture(shgroup->shader, uni->location, DST.current_txl->textures[uni->length]); + break; + case DRW_UNIFORM_BLOCK: + GPU_uniformbuffer_bind((GPUUniformBuffer *)uni->value, uni->bindloc); + GPU_shader_uniform_buffer(shgroup->shader, uni->location, (GPUUniformBuffer *)uni->value); + break; + } + } + + /* Rendering Calls */ + if (shgroup->dyntype != 0) { + /* Replacing multiple calls with only one */ + float obmat[4][4]; + unit_m4(obmat); + + if (shgroup->dyntype == DRW_DYN_INSTANCE && shgroup->instance_count > 0) { + DRWCall *call = shgroup->calls.first; + draw_geometry(shgroup, interface, call->geometry, shgroup->instance_vbo, shgroup->instance_count, obmat); + } + else { + /* Some dynamic batch can have no geom (no call to aggregate) */ + if (shgroup->dyngeom) { + draw_geometry(shgroup, interface, shgroup->dyngeom, 0, 1, obmat); + } + } + } + else { + for (DRWCall *call = shgroup->calls.first; call; call = call->next) { + draw_geometry(shgroup, interface, call->geometry, 0, 1, call->obmat); + } + } +} + +static void set_state(short flag) +{ + /* TODO Keep track of the state and only revert what is needed */ + + /* Depth Write */ + if (flag & DRW_STATE_WRITE_DEPTH) + glDepthMask(GL_TRUE); + else + glDepthMask(GL_FALSE); + + /* Color Write */ + if (flag & DRW_STATE_WRITE_COLOR) + glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); + else + glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); + + /* Backface Culling */ + if (flag & DRW_STATE_CULL_BACK || + flag & DRW_STATE_CULL_FRONT) { + + glEnable(GL_CULL_FACE); + + if (flag & DRW_STATE_CULL_BACK) + glCullFace(GL_BACK); + else if (flag & DRW_STATE_CULL_FRONT) + glCullFace(GL_FRONT); + } + else { + glDisable(GL_CULL_FACE); + } + + /* Depht Test */ + if (flag & DRW_STATE_DEPTH_LESS || + flag & DRW_STATE_DEPTH_EQUAL) { + + glEnable(GL_DEPTH_TEST); + + if (flag & DRW_STATE_DEPTH_LESS) + glDepthFunc(GL_LEQUAL); + else if (flag & DRW_STATE_DEPTH_EQUAL) + glDepthFunc(GL_EQUAL); + } + else { + glDisable(GL_DEPTH_TEST); + } + + /* Wire Width */ + if (flag & DRW_STATE_WIRE) { + glLineWidth(1.0f); + } + else if (flag & DRW_STATE_WIRE_LARGE) { + glLineWidth(UI_GetThemeValuef(TH_OUTLINE_WIDTH) * 2.0f); + } + + /* Points Size */ + if (flag & DRW_STATE_POINT) { + GPU_enable_program_point_size(); + glPointSize(5.0f); + } + else { + GPU_disable_program_point_size(); + } + + /* Blending (all buffer) */ + if (flag & DRW_STATE_BLEND) { + glEnable(GL_BLEND); + } + else { + glDisable(GL_BLEND); + } + + /* Line Stipple */ + if (flag & DRW_STATE_STIPPLE_2) { + setlinestyle(2); + } + else if (flag & DRW_STATE_STIPPLE_3) { + setlinestyle(3); + } + else if (flag & DRW_STATE_STIPPLE_4) { + setlinestyle(4); + } + else { + setlinestyle(0); + } +} + +void DRW_draw_pass(DRWPass *pass) +{ + /* Start fresh */ + DST.shader = NULL; + DST.tex_bind_id = 0; + + set_state(pass->state); + BLI_listbase_clear(&DST.bound_texs); + + for (DRWShadingGroup *shgroup = pass->shgroups.first; shgroup; shgroup = shgroup->next) { + draw_shgroup(shgroup); + } + + /* Clear Bound textures */ + for (DRWBoundTexture *bound_tex = DST.bound_texs.first; bound_tex; bound_tex = bound_tex->next) { + GPU_texture_unbind(bound_tex->tex); + } + DST.tex_bind_id = 0; + BLI_freelistN(&DST.bound_texs); + + if (DST.shader) { + GPU_shader_unbind(); + DST.shader = NULL; + } +} + +/* Reset state to not interfer with other UI drawcall */ +void DRW_state_reset(void) +{ + DRWState state = 0; + state |= DRW_STATE_WRITE_DEPTH; + state |= DRW_STATE_WRITE_COLOR; + state |= DRW_STATE_DEPTH_LESS; + set_state(state); +} +#endif +/* ****************************************** Settings ******************************************/ +void *DRW_material_settings_get(Material *ma, const char *engine_name) +{ + MaterialEngineSettings *ms = NULL; + + ms = BLI_findstring(&ma->engines_settings, engine_name, offsetof(MaterialEngineSettings, name)); + +#ifdef WITH_CLAY_ENGINE + /* If the settings does not exists yet, create it */ + if (ms == NULL) { + ms = MEM_callocN(sizeof(RenderEngineSettings), "RenderEngineSettings"); + + BLI_strncpy(ms->name, engine_name, 32); + + /* TODO make render_settings_create a polymorphic function */ + if (STREQ(engine_name, RE_engine_id_BLENDER_CLAY)) { + ms->data = CLAY_material_settings_create(); + } + else { + /* No engine matched */ + BLI_assert(false); + } + + BLI_addtail(&ma->engines_settings, ms); + } +#else + return NULL; +#endif + + return ms->data; +} + +/* If scene is NULL, use context scene */ +void *DRW_render_settings_get(Scene *scene, const char *engine_name) +{ + RenderEngineSettings *rs = NULL; + + if (scene == NULL) + scene = CTX_data_scene(DST.context); + + rs = BLI_findstring(&scene->engines_settings, engine_name, offsetof(RenderEngineSettings, name)); + +#ifdef WITH_CLAY_ENGINE + /* If the settings does not exists yet, create it */ + if (rs == NULL) { + rs = MEM_callocN(sizeof(RenderEngineSettings), "RenderEngineSettings"); + + BLI_strncpy(rs->name, engine_name, 32); + + /* TODO make render_settings_create a polymorphic function */ + if (STREQ(engine_name, RE_engine_id_BLENDER_CLAY)) { + rs->data = CLAY_render_settings_create(); + } + else { + /* No engine matched */ + BLI_assert(false); + } + + BLI_addtail(&scene->engines_settings, rs); + } +#else + return NULL; +#endif + + return rs->data; +} +/* ****************************************** Framebuffers ******************************************/ + +void DRW_framebuffer_init(struct GPUFrameBuffer **fb, int width, int height, DRWFboTexture textures[MAX_FBO_TEX], + int texnbr) +{ + if (!*fb) { + int color_attachment = -1; + *fb = GPU_framebuffer_create(); + + for (int i = 0; i < texnbr; ++i) + { + DRWFboTexture fbotex = textures[i]; + + if (!*fbotex.tex) { + /* TODO refine to opengl formats */ + if (fbotex.format == DRW_BUF_DEPTH_16 || + fbotex.format == DRW_BUF_DEPTH_24) { + *fbotex.tex = GPU_texture_create_depth(width, height, NULL); + GPU_texture_compare_mode(*fbotex.tex, false); + GPU_texture_filter_mode(*fbotex.tex, false); + } + else { + *fbotex.tex = GPU_texture_create_2D(width, height, NULL, NULL); + ++color_attachment; + } + } + + GPU_framebuffer_texture_attach(*fb, *fbotex.tex, color_attachment); + } + + if (!GPU_framebuffer_check_valid(*fb, NULL)) { + printf("Error invalid framebuffer\n"); + } + + GPU_framebuffer_bind(DST.default_framebuffer); + } +} + +void DRW_framebuffer_bind(struct GPUFrameBuffer *fb) +{ + GPU_framebuffer_bind(fb); +} + +void DRW_framebuffer_texture_attach(struct GPUFrameBuffer *fb, GPUTexture *tex, int slot) +{ + GPU_framebuffer_texture_attach(fb, tex, slot); +} + +void DRW_framebuffer_texture_detach(GPUTexture *tex) +{ + GPU_framebuffer_texture_detach(tex); +} + +/* ****************************************** Viewport ******************************************/ + +float *DRW_viewport_size_get(void) +{ + return &DST.size[0]; +} + +float *DRW_viewport_screenvecs_get(void) +{ + return &DST.screenvecs[0][0]; +} + +float *DRW_viewport_pixelsize_get(void) +{ + return &DST.pixsize; +} + +void DRW_viewport_init(const bContext *C, void **buffers, void **textures, void **passes) +{ + RegionView3D *rv3d = CTX_wm_region_view3d(C); + GPUViewport *viewport = rv3d->viewport; + + GPU_viewport_get_engine_data(viewport, buffers, textures, passes); + + /* Refresh DST.size */ + DefaultTextureList *txl = (DefaultTextureList *)*textures; + DST.size[0] = (float)GPU_texture_width(txl->color); + DST.size[1] = (float)GPU_texture_height(txl->color); + + DefaultFramebufferList *fbl = (DefaultFramebufferList *)*buffers; + DST.default_framebuffer = fbl->default_fb; + + DST.current_txl = (TextureList *)*textures; + DST.current_fbl = (FramebufferList *)*buffers; + DST.current_psl = (PassList *)*passes; + + /* Refresh DST.screenvecs */ + copy_v3_v3(DST.screenvecs[0], rv3d->viewinv[0]); + copy_v3_v3(DST.screenvecs[1], rv3d->viewinv[1]); + normalize_v3(DST.screenvecs[0]); + normalize_v3(DST.screenvecs[1]); + + /* Refresh DST.pixelsize */ + DST.pixsize = rv3d->pixsize; + + /* Save context for all later needs */ + DST.context = C; +} + +void DRW_viewport_matrix_get(float mat[4][4], DRWViewportMatrixType type) +{ + RegionView3D *rv3d = CTX_wm_region_view3d(DST.context); + + if (type == DRW_MAT_PERS) + copy_m4_m4(mat, rv3d->persmat); + else if (type == DRW_MAT_WIEW) + copy_m4_m4(mat, rv3d->viewmat); + else if (type == DRW_MAT_WIN) + copy_m4_m4(mat, rv3d->winmat); +} + +bool DRW_viewport_is_persp_get(void) +{ + RegionView3D *rv3d = CTX_wm_region_view3d(DST.context); + return rv3d->is_persp; +} + +bool DRW_viewport_cache_is_dirty(void) +{ + /* TODO Use a dirty flag */ + return (DST.current_psl->passes[0] == NULL); +} + +/* ****************************************** INIT ******************************************/ + +void DRW_engines_init(void) +{ +#ifdef WITH_CLAY_ENGINE + RE_engines_register(NULL, &viewport_clay_type); +#endif +} + +void DRW_engines_free(void) +{ +#ifdef WITH_CLAY_ENGINE + clay_engine_free(); + + DRW_shape_cache_free(); + + BLI_remlink(&R_engines, &viewport_clay_type); +#endif +}
\ No newline at end of file diff --git a/source/blender/draw/intern/draw_mode_pass.c b/source/blender/draw/intern/draw_mode_pass.c new file mode 100644 index 00000000000..507872a4fee --- /dev/null +++ b/source/blender/draw/intern/draw_mode_pass.c @@ -0,0 +1,787 @@ +/* + * 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 + * + */ + +/** \file blender/draw/draw_mode_pass.c + * \ingroup draw + */ + +#include "DNA_userdef_types.h" + +#include "GPU_shader.h" + +#include "UI_resources.h" + +#include "BKE_global.h" + +#include "draw_mode_pass.h" + +/* ************************** OBJECT MODE ******************************* */ + +/* Store list of shading group for easy access*/ + +/* Empties */ +static DRWShadingGroup *plain_axes_wire; +static DRWShadingGroup *plain_axes_active; +static DRWShadingGroup *plain_axes_select; +static DRWShadingGroup *plain_axes_transform; +static DRWShadingGroup *plain_axes_group; +static DRWShadingGroup *plain_axes_group_active; + +static DRWShadingGroup *cube_wire; +static DRWShadingGroup *cube_active; +static DRWShadingGroup *cube_select; +static DRWShadingGroup *cube_transform; +static DRWShadingGroup *cube_group; +static DRWShadingGroup *cube_group_active; + +static DRWShadingGroup *circle_wire; +static DRWShadingGroup *circle_active; +static DRWShadingGroup *circle_select; +static DRWShadingGroup *circle_transform; +static DRWShadingGroup *circle_group; +static DRWShadingGroup *circle_group_active; + +static DRWShadingGroup *sphere_wire; +static DRWShadingGroup *sphere_active; +static DRWShadingGroup *sphere_select; +static DRWShadingGroup *sphere_transform; +static DRWShadingGroup *sphere_group; +static DRWShadingGroup *sphere_group_active; + +static DRWShadingGroup *cone_wire; +static DRWShadingGroup *cone_active; +static DRWShadingGroup *cone_select; +static DRWShadingGroup *cone_transform; +static DRWShadingGroup *cone_group; +static DRWShadingGroup *cone_group_active; + +static DRWShadingGroup *single_arrow_wire; +static DRWShadingGroup *single_arrow_active; +static DRWShadingGroup *single_arrow_select; +static DRWShadingGroup *single_arrow_transform; +static DRWShadingGroup *single_arrow_group; +static DRWShadingGroup *single_arrow_group_active; + +static DRWShadingGroup *single_arrow_line_wire; +static DRWShadingGroup *single_arrow_line_active; +static DRWShadingGroup *single_arrow_line_select; +static DRWShadingGroup *single_arrow_line_transform; +static DRWShadingGroup *single_arrow_line_group; +static DRWShadingGroup *single_arrow_line_group_active; + +static DRWShadingGroup *arrows_wire; +static DRWShadingGroup *arrows_active; +static DRWShadingGroup *arrows_select; +static DRWShadingGroup *arrows_transform; +static DRWShadingGroup *arrows_group; +static DRWShadingGroup *arrows_group_active; + +/* Lamps */ +static DRWShadingGroup *lamp_center; +static DRWShadingGroup *lamp_center_group; +static DRWShadingGroup *lamp_groundpoint; +static DRWShadingGroup *lamp_groundline; +static DRWShadingGroup *lamp_circle; +static DRWShadingGroup *lamp_circle_active; +static DRWShadingGroup *lamp_circle_select; +static DRWShadingGroup *lamp_circle_transform; +static DRWShadingGroup *lamp_circle_group; +static DRWShadingGroup *lamp_circle_group_active; +static DRWShadingGroup *lamp_circle_shadow; +static DRWShadingGroup *lamp_circle_shadow_active; +static DRWShadingGroup *lamp_circle_shadow_select; +static DRWShadingGroup *lamp_circle_shadow_transform; +static DRWShadingGroup *lamp_circle_shadow_group; +static DRWShadingGroup *lamp_circle_shadow_group_active; +static DRWShadingGroup *lamp_sunrays; +static DRWShadingGroup *lamp_sunrays_active; +static DRWShadingGroup *lamp_sunrays_select; +static DRWShadingGroup *lamp_sunrays_transform; +static DRWShadingGroup *lamp_sunrays_group; +static DRWShadingGroup *lamp_sunrays_group_active; + +/* Helpers */ +static DRWShadingGroup *relationship_lines; + +/* Objects Centers */ +static DRWShadingGroup *center_active; +static DRWShadingGroup *center_selected; +static DRWShadingGroup *center_deselected; + +static DRWShadingGroup *shgroup_instance_uniform_color(DRWPass *pass, float color[4]) +{ + GPUShader *sh_inst = GPU_shader_get_builtin_shader(GPU_SHADER_3D_UNIFORM_COLOR_INSTANCE); + + DRWShadingGroup *grp = DRW_shgroup_create(sh_inst, pass); + DRW_shgroup_uniform_vec4(grp, "color", color, 1); + DRW_shgroup_dyntype_set(grp, DRW_DYN_INSTANCE); + + return grp; +} + +static DRWShadingGroup *shgroup_dynlines_uniform_color(DRWPass *pass, float color[4]) +{ + GPUShader *sh = GPU_shader_get_builtin_shader(GPU_SHADER_3D_UNIFORM_COLOR); + + DRWShadingGroup *grp = DRW_shgroup_create(sh, pass); + DRW_shgroup_uniform_vec4(grp, "color", color, 1); + DRW_shgroup_dyntype_set(grp, DRW_DYN_LINES); + + return grp; +} + +static DRWShadingGroup *shgroup_dynpoints_uniform_color(DRWPass *pass, float color[4], float *size) +{ + GPUShader *sh = GPU_shader_get_builtin_shader(GPU_SHADER_3D_POINT_UNIFORM_SIZE_UNIFORM_COLOR_SMOOTH); + + DRWShadingGroup *grp = DRW_shgroup_create(sh, pass); + DRW_shgroup_uniform_vec4(grp, "color", color, 1); + DRW_shgroup_uniform_float(grp, "size", size, 1); + DRW_shgroup_dyntype_set(grp, DRW_DYN_POINTS); + DRW_shgroup_state_set(grp, DRW_STATE_POINT); + + return grp; +} + +static DRWShadingGroup *shgroup_groundlines_uniform_color(DRWPass *pass, float color[4]) +{ + GPUShader *sh = GPU_shader_get_builtin_shader(GPU_SHADER_3D_GROUNDLINE); + + DRWShadingGroup *grp = DRW_shgroup_create(sh, pass); + DRW_shgroup_uniform_vec4(grp, "color", color, 1); + DRW_shgroup_dyntype_set(grp, DRW_DYN_POINTS); + + return grp; +} + +static DRWShadingGroup *shgroup_groundpoints_uniform_color(DRWPass *pass, float color[4]) +{ + GPUShader *sh = GPU_shader_get_builtin_shader(GPU_SHADER_3D_GROUNDPOINT); + + DRWShadingGroup *grp = DRW_shgroup_create(sh, pass); + DRW_shgroup_uniform_vec4(grp, "color", color, 1); + DRW_shgroup_dyntype_set(grp, DRW_DYN_POINTS); + DRW_shgroup_state_set(grp, DRW_STATE_POINT); + return grp; +} + +static DRWShadingGroup *shgroup_lamp(DRWPass *pass, float color[4], float *size) +{ + GPUShader *sh = GPU_shader_get_builtin_shader(GPU_SHADER_3D_LAMP_COMMON); + + DRWShadingGroup *grp = DRW_shgroup_create(sh, pass); + DRW_shgroup_uniform_vec4(grp, "color", color, 1); + DRW_shgroup_uniform_float(grp, "size", size, 1); + DRW_shgroup_uniform_float(grp, "pixel_size", DRW_viewport_pixelsize_get(), 1); + DRW_shgroup_uniform_vec3(grp, "screen_vecs", DRW_viewport_screenvecs_get(), 2); + DRW_shgroup_dyntype_set(grp, DRW_DYN_INSTANCE); + DRW_shgroup_state_set(grp, DRW_STATE_STIPPLE_3); + return grp; +} + +/* This Function setup the passes needed for the mode rendering. + * The passes are populated by the rendering engine using the DRW_shgroup_* functions. */ +void DRW_pass_setup_common(DRWPass **wire_overlay, DRWPass **wire_outline, DRWPass **non_meshes, DRWPass **ob_center) +{ + /* Theses are defined for the whole application so make sure they rely on global settings */ + static float colorWire[4], colorWireEdit[4]; + static float colorActive[4], colorSelect[4], colorTransform[4], colorGroup[4], colorGroupActive[4]; + static float colorEmpty[4], colorLamp[4], colorCamera[4], colorSpeaker[4]; + static float lampCenterSize, lampCircleRad, lampCircleShadowRad, colorLampNoAlpha[4]; + + UI_GetThemeColor4fv(TH_WIRE, colorWire); + UI_GetThemeColor4fv(TH_WIRE_EDIT, colorWireEdit); + UI_GetThemeColor4fv(TH_ACTIVE, colorActive); + UI_GetThemeColor4fv(TH_SELECT, colorSelect); + UI_GetThemeColor4fv(TH_TRANSFORM, colorTransform); + UI_GetThemeColor4fv(TH_GROUP_ACTIVE, colorGroupActive); + UI_GetThemeColor4fv(TH_GROUP, colorGroup); + UI_GetThemeColor4fv(TH_LAMP, colorLamp); + UI_GetThemeColor4fv(TH_LAMP, colorLampNoAlpha); + UI_GetThemeColor4fv(TH_SPEAKER, colorSpeaker); + UI_GetThemeColor4fv(TH_CAMERA, colorCamera); + UI_GetThemeColor4fv(TH_EMPTY, colorEmpty); + + colorLampNoAlpha[3] = 1.0f; + + if (wire_overlay) { + /* This pass can draw mesh edges top of Shaded Meshes without any Z fighting */ + DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_BLEND; + *wire_overlay = DRW_pass_create("Wire Overlays Pass", state); + } + + if (wire_outline) { + /* This pass can draw mesh outlines and/or fancy wireframe */ + /* Fancy wireframes are not meant to be occluded (without Z offset) */ + /* Outlines and Fancy Wires use the same VBO */ + DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS | DRW_STATE_BLEND; + *wire_outline = DRW_pass_create("Wire + Outlines Pass", state); + } + + if (non_meshes) { + /* Non Meshes Pass (Camera, empties, lamps ...) */ + DRWShadingGroup *grp; + + DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS | DRW_STATE_BLEND; + state |= DRW_STATE_WIRE; + *non_meshes = DRW_pass_create("Non Meshes Pass", state); + + GPUShader *sh = GPU_shader_get_builtin_shader(GPU_SHADER_3D_UNIFORM_COLOR); + + /* Empties */ + plain_axes_wire = shgroup_instance_uniform_color(*non_meshes, colorEmpty); + plain_axes_active = shgroup_instance_uniform_color(*non_meshes, colorActive); + plain_axes_select = shgroup_instance_uniform_color(*non_meshes, colorSelect); + plain_axes_transform = shgroup_instance_uniform_color(*non_meshes, colorTransform); + plain_axes_group = shgroup_instance_uniform_color(*non_meshes, colorGroup); + plain_axes_group_active = shgroup_instance_uniform_color(*non_meshes, colorGroupActive); + + cube_wire = shgroup_instance_uniform_color(*non_meshes, colorEmpty); + cube_active = shgroup_instance_uniform_color(*non_meshes, colorActive); + cube_select = shgroup_instance_uniform_color(*non_meshes, colorSelect); + cube_transform = shgroup_instance_uniform_color(*non_meshes, colorTransform); + cube_group = shgroup_instance_uniform_color(*non_meshes, colorGroup); + cube_group_active = shgroup_instance_uniform_color(*non_meshes, colorGroupActive); + + circle_wire = shgroup_instance_uniform_color(*non_meshes, colorEmpty); + circle_active = shgroup_instance_uniform_color(*non_meshes, colorActive); + circle_select = shgroup_instance_uniform_color(*non_meshes, colorSelect); + circle_transform = shgroup_instance_uniform_color(*non_meshes, colorTransform); + circle_group = shgroup_instance_uniform_color(*non_meshes, colorGroup); + circle_group_active = shgroup_instance_uniform_color(*non_meshes, colorGroupActive); + + sphere_wire = shgroup_instance_uniform_color(*non_meshes, colorEmpty); + sphere_active = shgroup_instance_uniform_color(*non_meshes, colorActive); + sphere_select = shgroup_instance_uniform_color(*non_meshes, colorSelect); + sphere_transform = shgroup_instance_uniform_color(*non_meshes, colorTransform); + sphere_group = shgroup_instance_uniform_color(*non_meshes, colorGroup); + sphere_group_active = shgroup_instance_uniform_color(*non_meshes, colorGroupActive); + + cone_wire = shgroup_instance_uniform_color(*non_meshes, colorEmpty); + cone_active = shgroup_instance_uniform_color(*non_meshes, colorActive); + cone_select = shgroup_instance_uniform_color(*non_meshes, colorSelect); + cone_transform = shgroup_instance_uniform_color(*non_meshes, colorTransform); + cone_group = shgroup_instance_uniform_color(*non_meshes, colorGroup); + cone_group_active = shgroup_instance_uniform_color(*non_meshes, colorGroupActive); + + single_arrow_wire = shgroup_instance_uniform_color(*non_meshes, colorEmpty); + single_arrow_active = shgroup_instance_uniform_color(*non_meshes, colorActive); + single_arrow_select = shgroup_instance_uniform_color(*non_meshes, colorSelect); + single_arrow_transform = shgroup_instance_uniform_color(*non_meshes, colorTransform); + single_arrow_group = shgroup_instance_uniform_color(*non_meshes, colorGroup); + single_arrow_group_active = shgroup_instance_uniform_color(*non_meshes, colorGroupActive); + + single_arrow_line_wire = shgroup_instance_uniform_color(*non_meshes, colorEmpty); + single_arrow_line_active = shgroup_instance_uniform_color(*non_meshes, colorActive); + single_arrow_line_select = shgroup_instance_uniform_color(*non_meshes, colorSelect); + single_arrow_line_transform = shgroup_instance_uniform_color(*non_meshes, colorTransform); + single_arrow_line_group = shgroup_instance_uniform_color(*non_meshes, colorGroup); + single_arrow_line_group_active = shgroup_instance_uniform_color(*non_meshes, colorGroupActive); + + arrows_wire = shgroup_instance_uniform_color(*non_meshes, colorEmpty); + arrows_active = shgroup_instance_uniform_color(*non_meshes, colorActive); + arrows_select = shgroup_instance_uniform_color(*non_meshes, colorSelect); + arrows_transform = shgroup_instance_uniform_color(*non_meshes, colorTransform); + arrows_group = shgroup_instance_uniform_color(*non_meshes, colorGroup); + arrows_group_active = shgroup_instance_uniform_color(*non_meshes, colorGroupActive); + + /* Lamps */ + lampCenterSize = (U.obcenter_dia + 1.5f) * U.pixelsize; + lampCircleRad = U.pixelsize * 9.0f; + lampCircleShadowRad = lampCircleRad + U.pixelsize * 3.0f; + /* TODO + * for now we create 3 times the same VBO with only lamp center coordinates + * but ideally we would only create it once */ + lamp_center = shgroup_dynpoints_uniform_color(*non_meshes, colorLampNoAlpha, &lampCenterSize); + lamp_center_group = shgroup_dynpoints_uniform_color(*non_meshes, colorGroup, &lampCenterSize); + lamp_circle = shgroup_lamp(*non_meshes, colorLampNoAlpha, &lampCircleRad); + lamp_circle_active = shgroup_lamp(*non_meshes, colorActive, &lampCircleRad); + lamp_circle_select = shgroup_lamp(*non_meshes, colorSelect, &lampCircleRad); + lamp_circle_transform = shgroup_lamp(*non_meshes, colorTransform, &lampCircleRad); + lamp_circle_group = shgroup_lamp(*non_meshes, colorGroup, &lampCircleRad); + lamp_circle_group_active = shgroup_lamp(*non_meshes, colorGroupActive, &lampCircleRad); + lamp_circle_shadow = shgroup_lamp(*non_meshes, colorLampNoAlpha, &lampCircleShadowRad); + lamp_circle_shadow_active = shgroup_lamp(*non_meshes, colorActive, &lampCircleShadowRad); + lamp_circle_shadow_select = shgroup_lamp(*non_meshes, colorSelect, &lampCircleShadowRad); + lamp_circle_shadow_transform = shgroup_lamp(*non_meshes, colorTransform, &lampCircleShadowRad); + lamp_circle_shadow_group = shgroup_lamp(*non_meshes, colorGroup, &lampCircleShadowRad); + lamp_circle_shadow_group_active = shgroup_lamp(*non_meshes, colorGroupActive, &lampCircleShadowRad); + lamp_sunrays = shgroup_lamp(*non_meshes, colorLampNoAlpha, &lampCircleRad); + lamp_sunrays_active = shgroup_lamp(*non_meshes, colorActive, &lampCircleRad); + lamp_sunrays_select = shgroup_lamp(*non_meshes, colorSelect, &lampCircleRad); + lamp_sunrays_transform = shgroup_lamp(*non_meshes, colorTransform, &lampCircleRad); + lamp_sunrays_group = shgroup_lamp(*non_meshes, colorGroup, &lampCircleRad); + lamp_sunrays_group_active = shgroup_lamp(*non_meshes, colorGroupActive, &lampCircleRad); + lamp_groundline = shgroup_groundlines_uniform_color(*non_meshes, colorLamp); + lamp_groundpoint = shgroup_groundpoints_uniform_color(*non_meshes, colorLamp); + + /* Stipple Wires */ + grp = DRW_shgroup_create(sh, *non_meshes); + DRW_shgroup_state_set(grp, DRW_STATE_STIPPLE_2); + + grp = DRW_shgroup_create(sh, *non_meshes); + DRW_shgroup_state_set(grp, DRW_STATE_STIPPLE_3); + + grp = DRW_shgroup_create(sh, *non_meshes); + DRW_shgroup_state_set(grp, DRW_STATE_STIPPLE_4); + + /* Relationship Lines */ + relationship_lines = shgroup_dynlines_uniform_color(*non_meshes, colorWire); + DRW_shgroup_state_set(relationship_lines, DRW_STATE_STIPPLE_3); + } + + if (ob_center) { + /* Object Center pass grouped by State */ + DRWShadingGroup *grp; + static float colorDeselect[4], outlineColor[4]; + static float outlineWidth, size; + + DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND | DRW_STATE_POINT; + *ob_center = DRW_pass_create("Obj Center Pass", state); + + outlineWidth = 1.0f * U.pixelsize; + size = U.obcenter_dia * U.pixelsize + outlineWidth; + //UI_GetThemeColorShadeAlpha4fv(TH_ACTIVE, 0, -80, colorActive); + //UI_GetThemeColorShadeAlpha4fv(TH_SELECT, 0, -80, colorSelect); + UI_GetThemeColorShadeAlpha4fv(TH_TRANSFORM, 0, -80, colorDeselect); + UI_GetThemeColorShadeAlpha4fv(TH_WIRE, 0, -30, outlineColor); + + GPUShader *sh = GPU_shader_get_builtin_shader(GPU_SHADER_3D_POINT_UNIFORM_SIZE_UNIFORM_COLOR_OUTLINE_SMOOTH); + + /* Active */ + grp = DRW_shgroup_create(sh, *ob_center); + DRW_shgroup_dyntype_set(grp, DRW_DYN_POINTS); + DRW_shgroup_uniform_float(grp, "size", &size, 1); + DRW_shgroup_uniform_float(grp, "outlineWidth", &outlineWidth, 1); + DRW_shgroup_uniform_vec4(grp, "color", colorActive, 1); + DRW_shgroup_uniform_vec4(grp, "outlineColor", outlineColor, 1); + center_active = grp; + + /* Select */ + grp = DRW_shgroup_create(sh, *ob_center); + DRW_shgroup_dyntype_set(grp, DRW_DYN_POINTS); + DRW_shgroup_uniform_vec4(grp, "color", colorSelect, 1); + center_selected = grp; + + /* Deselect */ + grp = DRW_shgroup_create(sh, *ob_center); + DRW_shgroup_dyntype_set(grp, DRW_DYN_POINTS); + DRW_shgroup_uniform_vec4(grp, "color", colorDeselect, 1); + center_deselected = grp; + } +} + +/* ******************************************** WIRES *********************************************** */ + +/* TODO FINISH */ +static int draw_object_wire_theme(Object *ob) +{ + const bool is_edit = (ob->mode & OB_MODE_EDIT) != 0; + /* confusing logic here, there are 2 methods of setting the color + * 'colortab[colindex]' and 'theme_id', colindex overrides theme_id. + * + * note: no theme yet for 'colindex' */ + int theme_id = is_edit ? TH_WIRE_EDIT : TH_WIRE; + + if (//(scene->obedit == NULL) && + ((G.moving & G_TRANSFORM_OBJ) != 0) && + ((ob->base_flag & BASE_SELECTED) != 0)) + { + theme_id = TH_TRANSFORM; + } + else { + /* Sets the 'theme_id' or fallback to wire */ + if ((ob->flag & OB_FROMGROUP) != 0) { + if ((ob->base_flag & BASE_SELECTED) != 0) { + /* uses darker active color for non-active + selected */ + theme_id = TH_GROUP_ACTIVE; + + // if (scene->basact != base) { + // theme_shade = -16; + // } + } + else { + theme_id = TH_GROUP; + } + } + else { + if ((ob->base_flag & BASE_SELECTED) != 0) { + theme_id = //scene->basact == base ? TH_ACTIVE : + TH_SELECT; + } + else { + if (ob->type == OB_LAMP) theme_id = TH_LAMP; + else if (ob->type == OB_SPEAKER) theme_id = TH_SPEAKER; + else if (ob->type == OB_CAMERA) theme_id = TH_CAMERA; + else if (ob->type == OB_EMPTY) theme_id = TH_EMPTY; + /* fallback to TH_WIRE */ + } + } + } + + return theme_id; +} + +void DRW_shgroup_wire_overlay(DRWPass *wire_overlay, Object *ob) +{ +#if 1 + struct Batch *geom = DRW_cache_wire_overlay_get(ob); + GPUShader *sh = GPU_shader_get_builtin_shader(GPU_SHADER_EDGES_OVERLAY); + + DRWShadingGroup *grp = DRW_shgroup_create(sh, wire_overlay); + DRW_shgroup_uniform_vec2(grp, "viewportSize", DRW_viewport_size_get(), 1); + + DRW_shgroup_call_add(grp, geom, ob->obmat); +#else + static float col[4] = {0.0f, 0.0f, 0.0f, 1.0f}; + struct Batch *geom = DRW_cache_wire_overlay_get(ob); + GPUShader *sh = GPU_shader_get_builtin_shader(GPU_SHADER_3D_UNIFORM_COLOR); + + DRWShadingGroup *grp = DRW_shgroup_create(sh, wire_overlay); + DRW_shgroup_uniform_vec4(grp, "color", col, 1); + + DRW_shgroup_call_add(grp, geom, ob->obmat); +#endif +} + +void DRW_shgroup_wire_outline(DRWPass *wire_outline, Object *ob, + const bool do_front, const bool do_back, const bool do_outline) +{ + GPUShader *sh; + struct Batch *geom = DRW_cache_wire_outline_get(ob); + + /* Get color */ + /* TODO get the right color depending on ob state (Groups, overides etc..) */ + static float frontcol[4], backcol[4], color[4]; + UI_GetThemeColor4fv(TH_ACTIVE, color); + copy_v4_v4(frontcol, color); + copy_v4_v4(backcol, color); + backcol[3] = 0.333f; + frontcol[3] = 0.667f; + +#if 1 /* New wire */ + + bool is_perps = DRW_viewport_is_persp_get(); + static bool bTrue = true; + static bool bFalse = false; + + /* Note (TODO) : this requires cache to be discarded on ortho/perp switch + * It may be preferable (or not depending on performance implication) + * to introduce a shader uniform switch */ + if (is_perps) { + sh = GPU_shader_get_builtin_shader(GPU_SHADER_EDGES_FRONT_BACK_PERSP); + } + else { + sh = GPU_shader_get_builtin_shader(GPU_SHADER_EDGES_FRONT_BACK_ORTHO); + } + + if (do_front || do_back) { + bool *bFront = (do_front) ? &bTrue : &bFalse; + bool *bBack = (do_back) ? &bTrue : &bFalse; + + DRWShadingGroup *grp = DRW_shgroup_create(sh, wire_outline); + DRW_shgroup_state_set(grp, DRW_STATE_WIRE); + DRW_shgroup_uniform_vec4(grp, "frontColor", frontcol, 1); + DRW_shgroup_uniform_vec4(grp, "backColor", backcol, 1); + DRW_shgroup_uniform_bool(grp, "drawFront", bFront, 1); + DRW_shgroup_uniform_bool(grp, "drawBack", bBack, 1); + DRW_shgroup_uniform_bool(grp, "drawSilhouette", &bFalse, 1); + DRW_shgroup_call_add(grp, geom, ob->obmat); + } + + if (do_outline) { + DRWShadingGroup *grp = DRW_shgroup_create(sh, wire_outline); + DRW_shgroup_state_set(grp, DRW_STATE_WIRE_LARGE); + DRW_shgroup_uniform_vec4(grp, "silhouetteColor", color, 1); + DRW_shgroup_uniform_bool(grp, "drawFront", &bFalse, 1); + DRW_shgroup_uniform_bool(grp, "drawBack", &bFalse, 1); + DRW_shgroup_uniform_bool(grp, "drawSilhouette", &bTrue, 1); + + DRW_shgroup_call_add(grp, geom, ob->obmat); + } + +#else /* Old (flat) wire */ + + sh = GPU_shader_get_builtin_shader(GPU_SHADER_3D_UNIFORM_COLOR); + DRWShadingGroup *grp = DRW_shgroup_create(sh, wire_outline); + DRW_shgroup_state_set(grp, DRW_STATE_WIRE_LARGE); + DRW_shgroup_uniform_vec4(grp, "color", frontcol, 1); + + DRW_shgroup_call_add(grp, geom, ob->obmat); +#endif + +} + +/* ***************************** NON MESHES ********************** */ + +static void DRW_draw_lamp(Object *ob) +{ + struct Batch *center = DRW_cache_single_vert_get(); + struct Batch *lamp = DRW_cache_lamp_get(); + struct Batch *sunrays = DRW_cache_lamp_sunrays_get(); + Lamp *la = ob->data; + int theme_id = draw_object_wire_theme(ob); + + /* Don't draw the center if it's selected or active */ + if (theme_id == TH_GROUP) + DRW_shgroup_call_add(lamp_center_group, center, ob->obmat); + else if (theme_id == TH_LAMP) + DRW_shgroup_call_add(lamp_center, center, ob->obmat); + + /* First circle */ + if (theme_id == TH_ACTIVE) + DRW_shgroup_call_add(lamp_circle_active, lamp, ob->obmat); + else if (theme_id == TH_SELECT) + DRW_shgroup_call_add(lamp_circle_select, lamp, ob->obmat); + else if (theme_id == TH_GROUP) + DRW_shgroup_call_add(lamp_circle_group, lamp, ob->obmat); + else if (theme_id == TH_GROUP_ACTIVE) + DRW_shgroup_call_add(lamp_circle_group_active, lamp, ob->obmat); + else if (theme_id == TH_TRANSFORM) + DRW_shgroup_call_add(lamp_circle_transform, lamp, ob->obmat); + else + DRW_shgroup_call_add(lamp_circle, lamp, ob->obmat); + + /* draw dashed outer circle if shadow is on. remember some lamps can't have certain shadows! */ + if (la->type != LA_HEMI) { + if ((la->mode & LA_SHAD_RAY) || ((la->mode & LA_SHAD_BUF) && (la->type == LA_SPOT))) { + if (theme_id == TH_ACTIVE) + DRW_shgroup_call_add(lamp_circle_shadow_active, lamp, ob->obmat); + else if (theme_id == TH_SELECT) + DRW_shgroup_call_add(lamp_circle_shadow_select, lamp, ob->obmat); + else if (theme_id == TH_GROUP) + DRW_shgroup_call_add(lamp_circle_shadow_group, lamp, ob->obmat); + else if (theme_id == TH_GROUP_ACTIVE) + DRW_shgroup_call_add(lamp_circle_shadow_group_active, lamp, ob->obmat); + else if (theme_id == TH_TRANSFORM) + DRW_shgroup_call_add(lamp_circle_shadow_transform, lamp, ob->obmat); + else + DRW_shgroup_call_add(lamp_circle_shadow, lamp, ob->obmat); + } + } + + /* Sunrays */ + if (la->type == LA_SUN) { + if (theme_id == TH_ACTIVE) + DRW_shgroup_call_add(lamp_sunrays_active, sunrays, ob->obmat); + else if (theme_id == TH_SELECT) + DRW_shgroup_call_add(lamp_sunrays_select, sunrays, ob->obmat); + else if (theme_id == TH_GROUP) + DRW_shgroup_call_add(lamp_sunrays_group, sunrays, ob->obmat); + else if (theme_id == TH_GROUP_ACTIVE) + DRW_shgroup_call_add(lamp_sunrays_group_active, sunrays, ob->obmat); + else if (theme_id == TH_TRANSFORM) + DRW_shgroup_call_add(lamp_sunrays_transform, sunrays, ob->obmat); + else + DRW_shgroup_call_add(lamp_sunrays, sunrays, ob->obmat); + } + + /* Line and point going to the ground */ + DRW_shgroup_call_add(lamp_groundline, center, ob->obmat); + DRW_shgroup_call_add(lamp_groundpoint, center, ob->obmat); +} + +static void DRW_draw_empty(Object *ob) +{ + struct Batch *geom, *geom2; + DRWShadingGroup *grp, *grp2; + int theme_id = draw_object_wire_theme(ob); + + switch (ob->empty_drawtype) { + case OB_PLAINAXES: + if (theme_id == TH_ACTIVE) + grp = plain_axes_active; + else if (theme_id == TH_SELECT) + grp = plain_axes_select; + else if (theme_id == TH_GROUP_ACTIVE) + grp = plain_axes_group_active; + else if (theme_id == TH_GROUP) + grp = plain_axes_group; + else if (theme_id == TH_TRANSFORM) + grp = plain_axes_transform; + else + grp = plain_axes_wire; + + geom = DRW_cache_plain_axes_get(); + DRW_shgroup_call_add(grp, geom, ob->obmat); + break; + + case OB_SINGLE_ARROW: + if (theme_id == TH_ACTIVE) { + grp = single_arrow_active; + grp2 = single_arrow_line_active; + } + else if (theme_id == TH_SELECT) { + grp = single_arrow_select; + grp2 = single_arrow_line_select; + } + else if (theme_id == TH_GROUP_ACTIVE) { + grp = single_arrow_group_active; + grp2 = single_arrow_line_group_active; + } + else if (theme_id == TH_GROUP) { + grp = single_arrow_group; + grp2 = single_arrow_line_group; + } + else if (theme_id == TH_TRANSFORM) { + grp = single_arrow_transform; + grp2 = single_arrow_line_transform; + } + else { + grp = single_arrow_wire; + grp2 = single_arrow_line_wire; + } + + geom = DRW_cache_single_arrow_get(&geom2); + DRW_shgroup_call_add(grp, geom, ob->obmat); + DRW_shgroup_call_add(grp2, geom2, ob->obmat); + break; + + case OB_CUBE: + if (theme_id == TH_ACTIVE) + grp = cube_active; + else if (theme_id == TH_SELECT) + grp = cube_select; + else if (theme_id == TH_GROUP_ACTIVE) + grp = cube_group_active; + else if (theme_id == TH_GROUP) + grp = cube_group; + else if (theme_id == TH_TRANSFORM) + grp = cube_transform; + else + grp = cube_wire; + + geom = DRW_cache_cube_get(); + DRW_shgroup_call_add(grp, geom, ob->obmat); + break; + + case OB_CIRCLE: + if (theme_id == TH_ACTIVE) + grp = circle_active; + else if (theme_id == TH_SELECT) + grp = circle_select; + else if (theme_id == TH_GROUP_ACTIVE) + grp = circle_group_active; + else if (theme_id == TH_GROUP) + grp = circle_group; + else if (theme_id == TH_TRANSFORM) + grp = circle_transform; + else + grp = circle_wire; + + geom = DRW_cache_circle_get(); + DRW_shgroup_call_add(grp, geom, ob->obmat); + break; + + case OB_EMPTY_SPHERE: + if (theme_id == TH_ACTIVE) + grp = sphere_active; + else if (theme_id == TH_SELECT) + grp = sphere_select; + else if (theme_id == TH_GROUP_ACTIVE) + grp = sphere_group_active; + else if (theme_id == TH_GROUP) + grp = sphere_group; + else if (theme_id == TH_TRANSFORM) + grp = sphere_transform; + else + grp = sphere_wire; + + geom = DRW_cache_empty_sphere_get(); + DRW_shgroup_call_add(grp, geom, ob->obmat); + break; + + case OB_EMPTY_CONE: + if (theme_id == TH_ACTIVE) + grp = cone_active; + else if (theme_id == TH_SELECT) + grp = cone_select; + else if (theme_id == TH_GROUP_ACTIVE) + grp = cone_group_active; + else if (theme_id == TH_GROUP) + grp = cone_group; + else if (theme_id == TH_TRANSFORM) + grp = cone_transform; + else + grp = cone_wire; + + geom = DRW_cache_empty_cone_get(); + DRW_shgroup_call_add(grp, geom, ob->obmat); + break; + + case OB_ARROWS: + default: + if (theme_id == TH_ACTIVE) + grp = arrows_active; + else if (theme_id == TH_SELECT) + grp = arrows_select; + else if (theme_id == TH_GROUP_ACTIVE) + grp = arrows_group_active; + else if (theme_id == TH_GROUP) + grp = arrows_group; + else if (theme_id == TH_TRANSFORM) + grp = arrows_transform; + else + grp = arrows_wire; + + geom = DRW_cache_arrows_get(); + DRW_shgroup_call_add(grp, geom, ob->obmat); + /* TODO Missing axes names */ + break; + } +} + +void DRW_shgroup_non_meshes(DRWPass *UNUSED(non_meshes), Object *ob) +{ + switch (ob->type) { + case OB_LAMP: + DRW_draw_lamp(ob); + break; + case OB_CAMERA: + case OB_EMPTY: + DRW_draw_empty(ob); + default: + break; + } +} + +void DRW_shgroup_relationship_lines(DRWPass *UNUSED(non_meshes), Object *ob) +{ + if (ob->parent) { + struct Batch *geom = DRW_cache_single_vert_get(); + DRW_shgroup_call_add(relationship_lines, geom, ob->obmat); + DRW_shgroup_call_add(relationship_lines, geom, ob->parent->obmat); + } +} + +/* ***************************** COMMON **************************** */ + +void DRW_shgroup_object_center(DRWPass *UNUSED(ob_center), Object *ob) +{ + struct Batch *geom = DRW_cache_single_vert_get(); + + if ((ob->base_flag & BASE_SELECTED) != 0) { + DRW_shgroup_call_add(center_selected, geom, ob->obmat); + } + else if (0) { + DRW_shgroup_call_add(center_deselected, geom, ob->obmat); + } +} diff --git a/source/blender/draw/intern/draw_mode_pass.h b/source/blender/draw/intern/draw_mode_pass.h new file mode 100644 index 00000000000..d11213ec8a2 --- /dev/null +++ b/source/blender/draw/intern/draw_mode_pass.h @@ -0,0 +1,45 @@ +/* + * 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 + * + */ + +/** \file draw_mode_pass.h + * \ingroup draw + */ + +#ifndef __DRAW_MODE_PASS_H__ +#define __DRAW_MODE_PASS_H__ + +#include "DRW_render.h" + +struct DRWPass; +struct Batch; +struct Object; + +void DRW_pass_setup_common(struct DRWPass **wire_overlay, struct DRWPass **wire_outline, struct DRWPass **non_meshes, struct DRWPass **ob_center); + +void DRW_shgroup_wire_overlay(struct DRWPass *wire_overlay, struct Object *ob); +void DRW_shgroup_wire_outline( + struct DRWPass *wire_outline, struct Object *ob, const bool do_front, const bool do_back, const bool do_outline); + +void DRW_shgroup_non_meshes(struct DRWPass *non_meshes, struct Object *ob); +void DRW_shgroup_relationship_lines(struct DRWPass *non_meshes, struct Object *ob); +void DRW_shgroup_object_center(struct DRWPass *ob_center, struct Object *ob); + +#endif /* __DRAW_MODE_PASS_H__ */
\ No newline at end of file |