From 83adc544382689217e19564fd5f2dd62160956cb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Foucault?= Date: Tue, 7 Feb 2017 11:20:15 +0100 Subject: Clay-Engine (merge clay-engine) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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) --- CMakeLists.txt | 2 + build_files/cmake/macros.cmake | 1 + .../scripts/startup/bl_ui/properties_collection.py | 49 + release/scripts/startup/bl_ui/properties_render.py | 19 + .../startup/bl_ui/properties_render_layer.py | 2 +- source/blender/CMakeLists.txt | 1 + source/blender/blenkernel/BKE_layer.h | 32 +- source/blender/blenkernel/intern/layer.c | 240 ++++ source/blender/blenkernel/intern/material.c | 11 + source/blender/blenkernel/intern/mesh_render.c | 2 +- source/blender/blenkernel/intern/scene.c | 8 + source/blender/blenloader/intern/readfile.c | 23 + source/blender/blenloader/intern/versioning_280.c | 1 + source/blender/blenloader/intern/writefile.c | 58 + source/blender/draw/CMakeLists.txt | 40 +- source/blender/draw/DRW_defines.h | 25 - source/blender/draw/DRW_engine.h | 45 + source/blender/draw/DRW_engines.h | 0 source/blender/draw/engines/clay/clay.c | 722 ++++++++++++ source/blender/draw/engines/clay/clay.h | 36 + .../draw/engines/clay/shaders/clay_frag.glsl | 207 ++++ .../draw/engines/clay/shaders/clay_vert.glsl | 20 + .../draw/engines/clay/shaders/ssao_alchemy.glsl | 73 ++ .../engines/clay/shaders/ssao_groundtruth.glsl | 120 ++ source/blender/draw/intern/DRW_render.h | 221 ++++ source/blender/draw/intern/draw_cache.c | 543 +++++++++ source/blender/draw/intern/draw_cache.h | 56 + source/blender/draw/intern/draw_manager.c | 1148 ++++++++++++++++++++ source/blender/draw/intern/draw_mode_pass.c | 787 ++++++++++++++ source/blender/draw/intern/draw_mode_pass.h | 45 + source/blender/editors/space_view3d/space_view3d.c | 2 + source/blender/editors/space_view3d/view3d_draw.c | 42 +- .../blender/editors/space_view3d/view3d_intern.h | 1 + source/blender/gpu/CMakeLists.txt | 9 + source/blender/gpu/GPU_extensions.h | 2 + source/blender/gpu/GPU_framebuffer.h | 1 + source/blender/gpu/GPU_shader.h | 9 + source/blender/gpu/GPU_uniformbuffer.h | 44 + source/blender/gpu/GPU_viewport.h | 42 +- source/blender/gpu/gawain/batch.c | 86 ++ source/blender/gpu/gawain/batch.h | 2 + source/blender/gpu/intern/gpu_extensions.c | 15 + source/blender/gpu/intern/gpu_framebuffer.c | 38 +- source/blender/gpu/intern/gpu_shader.c | 40 + source/blender/gpu/intern/gpu_texture.c | 1 + source/blender/gpu/intern/gpu_uniformbuffer.c | 105 ++ source/blender/gpu/intern/gpu_viewport.c | 196 +++- .../gpu/shaders/gpu_shader_3D_groundline_geom.glsl | 16 + .../gpu/shaders/gpu_shader_3D_groundline_vert.glsl | 8 + .../shaders/gpu_shader_3D_groundpoint_vert.glsl | 11 + .../gpu/shaders/gpu_shader_3D_instance_vert.glsl | 10 + .../gpu/shaders/gpu_shader_3D_lamp_vert.glsl | 24 + source/blender/makesdna/DNA_layer_types.h | 47 + source/blender/makesdna/DNA_material_types.h | 40 + source/blender/makesdna/DNA_object_types.h | 3 + source/blender/makesdna/DNA_scene_types.h | 49 + source/blender/makesrna/RNA_access.h | 5 + source/blender/makesrna/intern/CMakeLists.txt | 5 + source/blender/makesrna/intern/rna_material.c | 143 +++ source/blender/makesrna/intern/rna_render.c | 30 +- source/blender/makesrna/intern/rna_scene.c | 436 +++++++- source/blender/render/CMakeLists.txt | 1 + source/blender/render/extern/include/RE_engine.h | 6 + .../blender/render/intern/source/external_engine.c | 24 +- source/blenderplayer/bad_level_call_stubs/stubs.c | 5 + 65 files changed, 5980 insertions(+), 55 deletions(-) delete mode 100644 source/blender/draw/DRW_defines.h create mode 100644 source/blender/draw/DRW_engine.h delete mode 100644 source/blender/draw/DRW_engines.h create mode 100644 source/blender/draw/engines/clay/clay.c create mode 100644 source/blender/draw/engines/clay/clay.h create mode 100644 source/blender/draw/engines/clay/shaders/clay_frag.glsl create mode 100644 source/blender/draw/engines/clay/shaders/clay_vert.glsl create mode 100644 source/blender/draw/engines/clay/shaders/ssao_alchemy.glsl create mode 100644 source/blender/draw/engines/clay/shaders/ssao_groundtruth.glsl create mode 100644 source/blender/draw/intern/DRW_render.h create mode 100644 source/blender/draw/intern/draw_cache.c create mode 100644 source/blender/draw/intern/draw_cache.h create mode 100644 source/blender/draw/intern/draw_manager.c create mode 100644 source/blender/draw/intern/draw_mode_pass.c create mode 100644 source/blender/draw/intern/draw_mode_pass.h create mode 100644 source/blender/gpu/GPU_uniformbuffer.h create mode 100644 source/blender/gpu/intern/gpu_uniformbuffer.c create mode 100644 source/blender/gpu/shaders/gpu_shader_3D_groundline_geom.glsl create mode 100644 source/blender/gpu/shaders/gpu_shader_3D_groundline_vert.glsl create mode 100644 source/blender/gpu/shaders/gpu_shader_3D_groundpoint_vert.glsl create mode 100644 source/blender/gpu/shaders/gpu_shader_3D_instance_vert.glsl create mode 100644 source/blender/gpu/shaders/gpu_shader_3D_lamp_vert.glsl diff --git a/CMakeLists.txt b/CMakeLists.txt index d52f0c83511..a107dd78fbb 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -242,6 +242,8 @@ endif() option(WITH_PLAYER "Build Player" OFF) option(WITH_OPENCOLORIO "Enable OpenColorIO color management" ${_init_OPENCOLORIO}) +option(WITH_CLAY_ENGINE "Enable New Clay engine (Breaks Mac and Intel compatibility)" ON) + # Compositor option(WITH_COMPOSITOR "Enable the tile based nodal compositor" ON) diff --git a/build_files/cmake/macros.cmake b/build_files/cmake/macros.cmake index 83ae56636b0..fa9c2a28cb5 100644 --- a/build_files/cmake/macros.cmake +++ b/build_files/cmake/macros.cmake @@ -598,6 +598,7 @@ function(SETUP_BLENDER_SORTED_LIBS) bf_modifiers bf_bmesh bf_gpu + bf_draw bf_blenloader bf_blenkernel bf_physics diff --git a/release/scripts/startup/bl_ui/properties_collection.py b/release/scripts/startup/bl_ui/properties_collection.py index d67d694aec9..88d78f98ef2 100644 --- a/release/scripts/startup/bl_ui/properties_collection.py +++ b/release/scripts/startup/bl_ui/properties_collection.py @@ -75,5 +75,54 @@ class COLLECTION_PT_objects(CollectionButtonsPanel, Panel): row.operator("collections.objects_deselect", text="Deselect") +def template_engine_settings(col, settings, name, use_icon_view=False): + icons = { + False: 'ZOOMIN', + True: 'X', + } + + use_name = "{0}_use".format(name) + use = getattr(settings, use_name) + + row = col.row() + col = row.column() + col.active = use + + if use_icon_view: + col.template_icon_view(settings, name) + else: + col.prop(settings, name) + + row.prop(settings, "{}_use".format(name), text="", icon=icons[use], emboss=False) + + +class COLLECTION_PT_clay_settings(CollectionButtonsPanel, Panel): + bl_label = "Render Settings" + COMPAT_ENGINES = {'BLENDER_CLAY'} + + @classmethod + def poll(cls, context): + scene = context.scene + return scene and (scene.render.engine in cls.COMPAT_ENGINES) + + def draw(self, context): + layout = self.layout + + collection = context.layer_collection + settings = collection.get_engine_settings() + + col = layout.column() + template_engine_settings(col, settings, "type") + template_engine_settings(col, settings, "matcap_icon", use_icon_view=True) + template_engine_settings(col, settings, "matcap_rotation") + template_engine_settings(col, settings, "matcap_hue") + template_engine_settings(col, settings, "matcap_saturation") + template_engine_settings(col, settings, "matcap_value") + template_engine_settings(col, settings, "ssao_factor_cavity") + template_engine_settings(col, settings, "ssao_factor_edge") + template_engine_settings(col, settings, "ssao_distance") + template_engine_settings(col, settings, "ssao_attenuation") + + if __name__ == "__main__": # only for live edit. bpy.utils.register_module(__name__) diff --git a/release/scripts/startup/bl_ui/properties_render.py b/release/scripts/startup/bl_ui/properties_render.py index 6d23c07152e..90d46a6ee47 100644 --- a/release/scripts/startup/bl_ui/properties_render.py +++ b/release/scripts/startup/bl_ui/properties_render.py @@ -584,5 +584,24 @@ class RENDER_PT_bake(RenderButtonsPanel, Panel): sub.prop(rd, "bake_user_scale", text="User Scale") +class RENDER_PT_clay(RenderButtonsPanel, Panel): + bl_label = "Default Clay" + COMPAT_ENGINES = {'BLENDER_CLAY'} + + def draw(self, context): + layout = self.layout; + settings = context.scene.active_engine_settings + layout.template_icon_view(settings, "matcap_icon") + layout.prop(settings, "matcap_rotation") + layout.prop(settings, "matcap_hue") + layout.prop(settings, "matcap_saturation") + layout.prop(settings, "matcap_value") + layout.prop(settings, "ssao_factor_cavity") + layout.prop(settings, "ssao_factor_edge") + layout.prop(settings, "ssao_distance") + layout.prop(settings, "ssao_attenuation") + layout.prop(settings, "ssao_samples") + + if __name__ == "__main__": # only for live edit. bpy.utils.register_module(__name__) diff --git a/release/scripts/startup/bl_ui/properties_render_layer.py b/release/scripts/startup/bl_ui/properties_render_layer.py index 45c93dd9335..2545eadc792 100644 --- a/release/scripts/startup/bl_ui/properties_render_layer.py +++ b/release/scripts/startup/bl_ui/properties_render_layer.py @@ -48,7 +48,7 @@ class RENDERLAYER_UL_renderlayers(UIList): class RENDERLAYER_PT_layers(RenderLayerButtonsPanel, Panel): bl_label = "Layer List" bl_options = {'HIDE_HEADER'} - COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'} + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME', 'BLENDER_CLAY'} def draw(self, context): layout = self.layout diff --git a/source/blender/CMakeLists.txt b/source/blender/CMakeLists.txt index 6f2b78e0845..47ebed8f791 100644 --- a/source/blender/CMakeLists.txt +++ b/source/blender/CMakeLists.txt @@ -100,6 +100,7 @@ add_subdirectory(windowmanager) add_subdirectory(blenkernel) add_subdirectory(blenlib) add_subdirectory(bmesh) +add_subdirectory(draw) add_subdirectory(render) add_subdirectory(blenfont) add_subdirectory(blentranslation) diff --git a/source/blender/blenkernel/BKE_layer.h b/source/blender/blenkernel/BKE_layer.h index 850c63f535f..de8a577d272 100644 --- a/source/blender/blenkernel/BKE_layer.h +++ b/source/blender/blenkernel/BKE_layer.h @@ -39,13 +39,17 @@ extern "C" { #define TODO_LAYER_CONTEXT /* get/set current (context) SceneLayer */ #define TODO_LAYER_BASE /* BaseLegacy to Base related TODO */ #define TODO_LAYER_OPERATORS /* collection mamanger and property panel operators */ +#define TODO_LAYER_DEPSGRAPH /* placeholder for real Depsgraph fix */ #define TODO_LAYER /* generic todo */ -struct Base; -struct ID; +struct CollectionEngineSettings; struct LayerCollection; +struct ID; +struct ListBase; struct Main; struct Object; +struct Base; +struct RenderEngine; struct Scene; struct SceneCollection; struct SceneLayer; @@ -66,6 +70,9 @@ void BKE_scene_layer_base_deselect_all(struct SceneLayer *sl); void BKE_scene_layer_base_select(struct SceneLayer *sl, struct Base *selbase); void BKE_scene_layer_base_flag_recalculate(struct SceneLayer *sl); +void BKE_scene_layer_engine_settings_recalculate(struct SceneLayer *sl); +void BKE_scene_layer_engine_settings_update(struct SceneLayer *sl); + void BKE_layer_collection_free(struct SceneLayer *sl, struct LayerCollection *lc); struct LayerCollection *BKE_layer_collection_active(struct SceneLayer *sl); @@ -91,6 +98,24 @@ void BKE_layer_sync_object_unlink(struct Scene *scene, struct SceneCollection *s void BKE_collection_override_datablock_add(struct LayerCollection *lc, const char *data_path, struct ID *id); +/* engine settings */ +typedef void (*CollectionEngineSettingsCB)(struct RenderEngine *engine, struct CollectionEngineSettings *ces); +struct CollectionEngineSettings *BKE_layer_collection_engine_get(struct LayerCollection *lc, const char *engine_name); +void BKE_layer_collection_engine_settings_callback_register(struct Main *bmain, const char *engine_name, CollectionEngineSettingsCB func); +void BKE_layer_collection_engine_settings_callback_free(void); +void BKE_layer_collection_engine_settings_create(struct ListBase *lb, const char *engine_name); +void BKE_layer_collection_engine_settings_free(struct ListBase *lb); + +void BKE_collection_engine_property_add_float(struct CollectionEngineSettings *ces, const char *name, float value); +void BKE_collection_engine_property_add_int(struct CollectionEngineSettings *ces, const char *name, int value); +struct CollectionEngineProperty *BKE_collection_engine_property_get(struct CollectionEngineSettings *ces, const char *name); +int BKE_collection_engine_property_value_get_int(struct CollectionEngineSettings *ces, const char *name); +float BKE_collection_engine_property_value_get_float(struct CollectionEngineSettings *ces, const char *name); +void BKE_collection_engine_property_value_set_int(struct CollectionEngineSettings *ces, const char *name, int value); +void BKE_collection_engine_property_value_set_float(struct CollectionEngineSettings *ces, const char *name, float value); +bool BKE_collection_engine_property_use_get(struct CollectionEngineSettings *ces, const char *name); +void BKE_collection_engine_property_use_set(struct CollectionEngineSettings *ces, const char *name, bool value); + /* iterators */ void BKE_selected_objects_Iterator_begin(Iterator *iter, void *data_in); @@ -172,6 +197,9 @@ void BKE_visible_bases_Iterator_end(Iterator *iter); /* temporary hacky solution waiting for final depsgraph evaluation */ #define DEG_OBJECT_ITER(sl_, ob_) \ { \ + /* temporary solution, waiting for depsgraph update */ \ + BKE_scene_layer_engine_settings_update(sl); \ + \ /* flush all the data to objects*/ \ Base *base_; \ for (base_ = sl->object_bases.first; base_; base_ = base_->next) { \ diff --git a/source/blender/blenkernel/intern/layer.c b/source/blender/blenkernel/intern/layer.c index cec1d70463f..28c5e9aff5d 100644 --- a/source/blender/blenkernel/intern/layer.c +++ b/source/blender/blenkernel/intern/layer.c @@ -45,9 +45,12 @@ #include "MEM_guardedalloc.h" /* prototype */ +struct CollectionEngineSettingsCB_Type; static void layer_collection_free(SceneLayer *sl, LayerCollection *lc); static LayerCollection *layer_collection_add(SceneLayer *sl, ListBase *lb, SceneCollection *sc); static LayerCollection *find_layer_collection_by_scene_collection(LayerCollection *lc, const SceneCollection *sc); +static void collection_engine_settings_create(ListBase *lb, struct CollectionEngineSettingsCB_Type *ces_type); +static void layer_collection_create_engine_settings(LayerCollection *lc); static void object_bases_Iterator_next(Iterator *iter, const int flag); /* RenderLayer */ @@ -254,6 +257,35 @@ void BKE_scene_layer_base_flag_recalculate(SceneLayer *sl) base->flag &= ~BASE_SELECTED; } } + + BKE_scene_layer_engine_settings_recalculate(sl); +} + +/** + * Tag Scene Layer to recalculation + * + * Temporary function, waiting for real depsgraph + */ +void BKE_scene_layer_engine_settings_recalculate(struct SceneLayer *sl) +{ + sl->flag |= SCENE_LAYER_ENGINE_DIRTY; +} + +/** + * Re-calculate the engine settings for all the objects in SceneLayer + * + * Temporary function, waiting for real depsgraph + */ +void BKE_scene_layer_engine_settings_update(struct SceneLayer *sl) +{ + if ((sl->flag & SCENE_LAYER_ENGINE_DIRTY) == 0) { + return; + } + + /* do the complete settings update */ + TODO_LAYER_DEPSGRAPH; + + sl->flag &= ~SCENE_LAYER_ENGINE_DIRTY; } /** @@ -292,10 +324,12 @@ static void layer_collection_free(SceneLayer *sl, LayerCollection *lc) BLI_freelistN(&lc->object_bases); BLI_freelistN(&lc->overrides); + BKE_layer_collection_engine_settings_free(&lc->engine_settings); for (LayerCollection *nlc = lc->layer_collections.first; nlc; nlc = nlc->next) { layer_collection_free(sl, nlc); } + BLI_freelistN(&lc->layer_collections); } @@ -467,6 +501,7 @@ static LayerCollection *layer_collection_add(SceneLayer *sl, ListBase *lb, Scene lc->scene_collection = sc; lc->flag = COLLECTION_VISIBLE + COLLECTION_SELECTABLE + COLLECTION_FOLDED; + layer_collection_create_engine_settings(lc); layer_collection_populate(sl, lc, sc); return lc; } @@ -578,6 +613,211 @@ void BKE_collection_override_datablock_add(LayerCollection *UNUSED(lc), const ch TODO_LAYER_OVERRIDE; } +/* ---------------------------------------------------------------------- */ +/* Engine Settings */ + +ListBase R_engines_settings_callbacks = {NULL, NULL}; + +typedef struct CollectionEngineSettingsCB_Type { + struct CollectionEngineSettingsCB_Type *next, *prev; + + char name[MAX_NAME]; /* engine name */ + + CollectionEngineSettingsCB callback; + +} CollectionEngineSettingsCB_Type; + +static void create_engine_settings_layer_collection(LayerCollection *lc, CollectionEngineSettingsCB_Type *ces_type) +{ + if (BKE_layer_collection_engine_get(lc, ces_type->name)) { + return; + } + + collection_engine_settings_create(&lc->engine_settings, ces_type); + + for (LayerCollection *lcn = lc->layer_collections.first; lcn; lcn = lcn->next) { + create_engine_settings_layer_collection(lcn, ces_type); + } +} + +static void create_engines_settings_scene(Scene *scene, CollectionEngineSettingsCB_Type *ces_type) +{ + for (SceneLayer *sl = scene->render_layers.first; sl; sl = sl->next) { + for (LayerCollection *lc = sl->layer_collections.first; lc; lc = lc->next) { + create_engine_settings_layer_collection(lc, ces_type); + } + } +} + +void BKE_layer_collection_engine_settings_callback_register( + Main *bmain, const char *engine_name, CollectionEngineSettingsCB func) +{ + CollectionEngineSettingsCB_Type *ces_type; + + /* cleanup in case it existed */ + ces_type = BLI_findstring(&R_engines_settings_callbacks, engine_name, offsetof(CollectionEngineSettingsCB_Type, name)); + + if (ces_type) { + BLI_remlink(&R_engines_settings_callbacks, ces_type); + MEM_freeN(ces_type); + } + + ces_type = MEM_callocN(sizeof(CollectionEngineSettingsCB_Type), "collection_engine_type"); + BLI_strncpy_utf8(ces_type->name, engine_name, sizeof(ces_type->name)); + ces_type->callback = func; + BLI_addtail(&R_engines_settings_callbacks, ces_type); + + if (bmain) { + /* populate all of the collections of the scene with those settings */ + for (Scene *scene = bmain->scene.first; scene; scene = scene->id.next) { + create_engines_settings_scene(scene, ces_type); + } + } +} + +void BKE_layer_collection_engine_settings_callback_free(void) +{ + BLI_freelistN(&R_engines_settings_callbacks); +} + +static void collection_engine_settings_create(ListBase *lb, CollectionEngineSettingsCB_Type *ces_type) +{ + /* create callback data */ + CollectionEngineSettings *ces = MEM_callocN(sizeof(CollectionEngineSettings), "Collection Engine Settings"); + BLI_strncpy_utf8(ces->name, ces_type->name, sizeof(ces->name)); + BLI_addtail(lb, ces); + + /* call callback */ + ces_type->callback(NULL, ces); +} + +/** + * Initialize a CollectionEngineSettings + * + * Usually we would pass LayerCollection->engine_settings + * But depsgraph uses this for Object->collection_settings + */ +void BKE_layer_collection_engine_settings_create(ListBase *lb, const char *engine_name) +{ + CollectionEngineSettingsCB_Type *ces_type; + ces_type = BLI_findstring(&R_engines_settings_callbacks, engine_name, offsetof(CollectionEngineSettingsCB_Type, name)); + BLI_assert(ces_type); + collection_engine_settings_create(lb, ces_type); +} + +/** + * Free the CollectionEngineSettings ListBase + * + * Usually we would pass LayerCollection->engine_settings + * But depsgraph uses this for Object->collection_settings + */ +void BKE_layer_collection_engine_settings_free(ListBase *lb) +{ + for (CollectionEngineSettings *cse = lb->first; cse; cse = cse->next) { + BLI_freelistN(&cse->properties); + } + BLI_freelistN(lb); +} + +/** + * Initialize the render settings for a single LayerCollection + */ +static void layer_collection_create_engine_settings(LayerCollection *lc) +{ + CollectionEngineSettingsCB_Type *ces_type; + for (ces_type = R_engines_settings_callbacks.first; ces_type; ces_type = ces_type->next) { + create_engine_settings_layer_collection(lc, ces_type); + } +} + +/** + * Return layer collection engine settings for specified engine + */ +CollectionEngineSettings *BKE_layer_collection_engine_get(LayerCollection *lc, const char *engine_name) +{ + CollectionEngineSettings *ces; + ces = BLI_findstring(&lc->engine_settings, engine_name, offsetof(CollectionEngineSettings, name)); + return ces; +} + +/* ---------------------------------------------------------------------- */ +/* Engine Settings Properties */ + +void BKE_collection_engine_property_add_float(CollectionEngineSettings *ces, const char *name, float value) +{ + CollectionEnginePropertyFloat *prop; + prop = MEM_callocN(sizeof(CollectionEnginePropertyFloat), "collection engine settings float"); + prop->data.type = COLLECTION_PROP_TYPE_FLOAT; + BLI_strncpy_utf8(prop->data.name, name, sizeof(prop->data.name)); + prop->value = value; + BLI_addtail(&ces->properties, prop); +} + +void BKE_collection_engine_property_add_int(CollectionEngineSettings *ces, const char *name, int value) +{ + CollectionEnginePropertyInt *prop; + prop = MEM_callocN(sizeof(CollectionEnginePropertyInt), "collection engine settings int"); + prop->data.type = COLLECTION_PROP_TYPE_INT; + BLI_strncpy_utf8(prop->data.name, name, sizeof(prop->data.name)); + prop->value = value; + BLI_addtail(&ces->properties, prop); +} + +CollectionEngineProperty *BKE_collection_engine_property_get(CollectionEngineSettings *ces, const char *name) +{ + return BLI_findstring(&ces->properties, name, offsetof(CollectionEngineProperty, name)); +} + +int BKE_collection_engine_property_value_get_int(CollectionEngineSettings *ces, const char *name) +{ + CollectionEnginePropertyInt *prop; + prop = (CollectionEnginePropertyInt *)BLI_findstring(&ces->properties, name, offsetof(CollectionEngineProperty, name)); + return prop->value; +} + +float BKE_collection_engine_property_value_get_float(CollectionEngineSettings *ces, const char *name) +{ + CollectionEnginePropertyFloat *prop; + prop = (CollectionEnginePropertyFloat *)BLI_findstring(&ces->properties, name, offsetof(CollectionEngineProperty, name)); + return prop->value; +} + +void BKE_collection_engine_property_value_set_int(CollectionEngineSettings *ces, const char *name, int value) +{ + CollectionEnginePropertyInt *prop; + prop = (CollectionEnginePropertyInt *)BLI_findstring(&ces->properties, name, offsetof(CollectionEngineProperty, name)); + prop->value = value; + prop->data.flag |= COLLECTION_PROP_USE; +} + +void BKE_collection_engine_property_value_set_float(CollectionEngineSettings *ces, const char *name, float value) +{ + CollectionEnginePropertyFloat *prop; + prop = (CollectionEnginePropertyFloat *)BLI_findstring(&ces->properties, name, offsetof(CollectionEngineProperty, name)); + prop->value = value; + prop->data.flag |= COLLECTION_PROP_USE; +} + +bool BKE_collection_engine_property_use_get(CollectionEngineSettings *ces, const char *name) +{ + CollectionEngineProperty *prop; + prop = (CollectionEngineProperty *)BLI_findstring(&ces->properties, name, offsetof(CollectionEngineProperty, name)); + return ((prop->flag & COLLECTION_PROP_USE) != 0); +} + +void BKE_collection_engine_property_use_set(CollectionEngineSettings *ces, const char *name, bool value) +{ + CollectionEngineProperty *prop; + prop = (CollectionEngineProperty *)BLI_findstring(&ces->properties, name, offsetof(CollectionEngineProperty, name)); + + if (value) { + prop->flag |= COLLECTION_PROP_USE; + } + else { + prop->flag &= ~COLLECTION_PROP_USE; + } +} + /* ---------------------------------------------------------------------- */ /* Iterators */ diff --git a/source/blender/blenkernel/intern/material.c b/source/blender/blenkernel/intern/material.c index 54945242fe4..435504859a4 100644 --- a/source/blender/blenkernel/intern/material.c +++ b/source/blender/blenkernel/intern/material.c @@ -111,6 +111,12 @@ void BKE_material_free(Material *ma) BKE_icon_id_delete((ID *)ma); BKE_previewimg_free(&ma->preview); + + for (MaterialEngineSettings *mes = ma->engines_settings.first; mes; mes = mes->next) { + if (mes->data) + MEM_SAFE_FREE(mes->data); + } + BLI_freelistN(&ma->engines_settings); } void BKE_material_init(Material *ma) @@ -248,6 +254,8 @@ Material *BKE_material_copy(Main *bmain, Material *ma) BLI_listbase_clear(&man->gpumaterial); + /* TODO Duplicate Engine Settings and set runtime to NULL */ + BKE_id_copy_ensure_local(bmain, &ma->id, &man->id); return man; @@ -279,6 +287,8 @@ Material *localize_material(Material *ma) man->nodetree = ntreeLocalize(ma->nodetree); BLI_listbase_clear(&man->gpumaterial); + + /* TODO Duplicate Engine Settings and set runtime to NULL */ return man; } @@ -1698,6 +1708,7 @@ void copy_matcopybuf(Material *ma) matcopybuf.nodetree = ntreeCopyTree_ex(ma->nodetree, G.main, false); matcopybuf.preview = NULL; BLI_listbase_clear(&matcopybuf.gpumaterial); + /* TODO Duplicate Engine Settings and set runtime to NULL */ matcopied = 1; } diff --git a/source/blender/blenkernel/intern/mesh_render.c b/source/blender/blenkernel/intern/mesh_render.c index 4118208d32f..fd0f49810fb 100644 --- a/source/blender/blenkernel/intern/mesh_render.c +++ b/source/blender/blenkernel/intern/mesh_render.c @@ -47,7 +47,7 @@ /* Mesh Interface */ #define MESH_RENDER_FUNCTION(func_name) \ - if (me->edit_btmesh) { \ + if (me->edit_btmesh && me->edit_btmesh->derivedFinal) { \ return mesh_bmesh_##func_name(me); \ } \ else { \ diff --git a/source/blender/blenkernel/intern/scene.c b/source/blender/blenkernel/intern/scene.c index d47982f96eb..1ce4bf8f9eb 100644 --- a/source/blender/blenkernel/intern/scene.c +++ b/source/blender/blenkernel/intern/scene.c @@ -109,6 +109,7 @@ const char *RE_engine_id_BLENDER_RENDER = "BLENDER_RENDER"; const char *RE_engine_id_BLENDER_GAME = "BLENDER_GAME"; +const char *RE_engine_id_BLENDER_CLAY = "BLENDER_CLAY"; const char *RE_engine_id_CYCLES = "CYCLES"; void free_avicodecdata(AviCodecData *acd) @@ -566,6 +567,13 @@ void BKE_scene_free(Scene *sce) BKE_collection_master_free(sce); MEM_freeN(sce->collection); sce->collection = NULL; + + /* Runtime Engine Data */ + for (RenderEngineSettings *res = sce->engines_settings.first; res; res = res->next) { + if (res->data) + MEM_freeN(res->data); + } + BLI_freelistN(&sce->engines_settings); } void BKE_scene_init(Scene *sce) diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c index e669bf3b4a6..da0650d02f5 100644 --- a/source/blender/blenloader/intern/readfile.c +++ b/source/blender/blenloader/intern/readfile.c @@ -3970,6 +3970,7 @@ static void lib_link_material(FileData *fd, Main *main) static void direct_link_material(FileData *fd, Material *ma) { int a; + MaterialEngineSettings *mes; ma->adt = newdataadr(fd, ma->adt); direct_link_animdata(fd, ma->adt); @@ -3990,6 +3991,11 @@ static void direct_link_material(FileData *fd, Material *ma) ma->preview = direct_link_preview_image(fd, ma->preview); BLI_listbase_clear(&ma->gpumaterial); + + link_list(fd, &ma->engines_settings); + for (mes = ma->engines_settings.first; mes; mes = mes->next) { + mes->data = newdataadr(fd, mes->data); + } } /* ************ READ PARTICLE SETTINGS ***************** */ @@ -5552,6 +5558,7 @@ static void direct_link_object(FileData *fd, Object *ob) ob->bb = NULL; ob->derivedDeform = NULL; ob->derivedFinal = NULL; + ob->collection_settings = NULL; BLI_listbase_clear(&ob->gpulamp); link_list(fd, &ob->pc_ids); @@ -5924,6 +5931,14 @@ static void direct_link_scene_collection(FileData *fd, SceneCollection *sc) } } +static void direct_link_engine_settings(FileData *fd, ListBase *lb) +{ + link_list(fd, lb); + for (CollectionEngineSettings *ces = lb->first; ces; ces = ces->next) { + link_list(fd, &ces->properties); + } +} + static void direct_link_layer_collections(FileData *fd, ListBase *lb) { link_list(fd, lb); @@ -5938,6 +5953,8 @@ static void direct_link_layer_collections(FileData *fd, ListBase *lb) link_list(fd, &lc->overrides); + direct_link_engine_settings(fd, &lc->engine_settings); + direct_link_layer_collections(fd, &lc->layer_collections); } } @@ -5950,6 +5967,7 @@ static void direct_link_scene(FileData *fd, Scene *sce) RigidBodyWorld *rbw; SceneLayer *sl; SceneRenderLayer *srl; + RenderEngineSettings *res; sce->theDag = NULL; sce->depsgraph = NULL; @@ -6212,6 +6230,11 @@ static void direct_link_scene(FileData *fd, Scene *sce) sl->basact = newdataadr(fd, sl->basact); direct_link_layer_collections(fd, &sl->layer_collections); } + + link_list(fd, &sce->engines_settings); + for (res = sce->engines_settings.first; res; res = res->next) { + res->data = newdataadr(fd, res->data); + } } /* ************ READ WM ***************** */ diff --git a/source/blender/blenloader/intern/versioning_280.c b/source/blender/blenloader/intern/versioning_280.c index a4e69c9d514..89ee05ee3e7 100644 --- a/source/blender/blenloader/intern/versioning_280.c +++ b/source/blender/blenloader/intern/versioning_280.c @@ -30,6 +30,7 @@ #include "DNA_object_types.h" #include "DNA_layer_types.h" +#include "DNA_material_types.h" #include "DNA_scene_types.h" #include "DNA_genfile.h" diff --git a/source/blender/blenloader/intern/writefile.c b/source/blender/blenloader/intern/writefile.c index 4ddf83d306b..0ad879b9aa6 100644 --- a/source/blender/blenloader/intern/writefile.c +++ b/source/blender/blenloader/intern/writefile.c @@ -1894,6 +1894,8 @@ static void write_objects(WriteData *wd, ListBase *idbase) writelist(wd, DATA, LinkData, &ob->pc_ids); writelist(wd, DATA, LodLevel, &ob->lodlevels); + + ob->collection_settings = NULL; } write_previews(wd, ob->preview); @@ -2469,6 +2471,21 @@ static void write_textures(WriteData *wd, ListBase *idbase) mywrite_flush(wd); } +static void write_material_engines_settings(WriteData *wd, ListBase *lb) +{ + for (MaterialEngineSettings *res = lb->first; res; res = res->next) { + writestruct(wd, DATA, MaterialEngineSettings, 1, res); + + if (STREQ(res->name, RE_engine_id_BLENDER_CLAY)) { + writestruct(wd, DATA, MaterialEngineSettingsClay, 1, res->data); + } + else { + /* No engine matched */ + /* error: don't know how to write this file */ + } + } +} + static void write_materials(WriteData *wd, ListBase *idbase) { Material *ma; @@ -2505,6 +2522,8 @@ static void write_materials(WriteData *wd, ListBase *idbase) } write_previews(wd, ma->preview); + + write_material_engines_settings(wd, &ma->engines_settings); } ma = ma->id.next; } @@ -2639,6 +2658,26 @@ static void write_scene_collection(WriteData *wd, SceneCollection *sc) } } +static void write_collection_engine_settings(WriteData *wd, ListBase *lb) +{ + for (CollectionEngineSettings *ces = lb->first; ces; ces = ces->next) { + writestruct(wd, DATA, CollectionEngineSettings, 1, ces); + + for (CollectionEngineProperty *prop = ces->properties.first; prop; prop = prop->next) { + switch (prop->type) { + case COLLECTION_PROP_TYPE_FLOAT: + writestruct(wd, DATA, CollectionEnginePropertyFloat, 1, prop); + break; + case COLLECTION_PROP_TYPE_INT: + writestruct(wd, DATA, CollectionEnginePropertyInt, 1, prop); + break; + default: + ; /* error: don't know how to write this file */ + } + } + } +} + static void write_layer_collections(WriteData *wd, ListBase *lb) { for (LayerCollection *lc = lb->first; lc; lc = lc->next) { @@ -2647,10 +2686,27 @@ static void write_layer_collections(WriteData *wd, ListBase *lb) writelist(wd, DATA, LinkData, &lc->object_bases); writelist(wd, DATA, CollectionOverride, &lc->overrides); + write_collection_engine_settings(wd, &lc->engine_settings); + write_layer_collections(wd, &lc->layer_collections); } } +static void write_render_engines_settings(WriteData *wd, ListBase *lb) +{ + for (RenderEngineSettings *res = lb->first; res; res = res->next) { + writestruct(wd, DATA, RenderEngineSettings, 1, res); + + if (STREQ(res->name, RE_engine_id_BLENDER_CLAY)) { + writestruct(wd, DATA, RenderEngineSettingsClay, 1, res->data); + } + else { + /* No engine matched */ + /* error: don't know how to write this file */ + } + } +} + static void write_scenes(WriteData *wd, ListBase *scebase) { Scene *sce; @@ -2880,6 +2936,8 @@ static void write_scenes(WriteData *wd, ListBase *scebase) write_layer_collections(wd, &sl->layer_collections); } + write_render_engines_settings(wd, &sce->engines_settings); + sce = sce->id.next; } 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_defines.h b/source/blender/draw/DRW_defines.h deleted file mode 100644 index 212c39e203b..00000000000 --- a/source/blender/draw/DRW_defines.h +++ /dev/null @@ -1,25 +0,0 @@ -/* - * 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 - * - */ - -#ifndef __DRW_DEFINES_H__ -#define __DRW_DEFINES_H__ - -#endif /* __DRW_DEFINES_H__ */ 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 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/engines/clay/clay.h b/source/blender/draw/engines/clay/clay.h new file mode 100644 index 00000000000..404924be2a1 --- /dev/null +++ b/source/blender/draw/engines/clay/clay.h @@ -0,0 +1,36 @@ +/* + * 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 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 /* __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 + +#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 diff --git a/source/blender/editors/space_view3d/space_view3d.c b/source/blender/editors/space_view3d/space_view3d.c index a3d4f6ef031..a48208b55f7 100644 --- a/source/blender/editors/space_view3d/space_view3d.c +++ b/source/blender/editors/space_view3d/space_view3d.c @@ -586,6 +586,7 @@ static void view3d_main_region_exit(wmWindowManager *wm, ARegion *ar) if (rv3d->viewport) { GPU_viewport_free(rv3d->viewport); + MEM_freeN(rv3d->viewport); rv3d->viewport = NULL; } } @@ -747,6 +748,7 @@ static void view3d_main_region_free(ARegion *ar) } if (rv3d->viewport) { GPU_viewport_free(rv3d->viewport); + MEM_freeN(rv3d->viewport); } MEM_freeN(rv3d); diff --git a/source/blender/editors/space_view3d/view3d_draw.c b/source/blender/editors/space_view3d/view3d_draw.c index b0faffcab3b..65966a67da8 100644 --- a/source/blender/editors/space_view3d/view3d_draw.c +++ b/source/blender/editors/space_view3d/view3d_draw.c @@ -2098,12 +2098,42 @@ static void view3d_draw_view(const bContext *C, ARegion *ar, DrawData *draw_data #endif } +static void view3d_render_pass(const bContext *C, ARegion *ar) +{ + Scene *scene = CTX_data_scene(C); + RenderEngineType *type = RE_engines_find(scene->r.engine); /* In the future we should get that from Layers */ + + if (type->flag & RE_USE_OGL_PIPELINE) { + type->view_draw(NULL, C); + } + else { + // Offline Render engine + } +} + +static void view3d_draw_view_new(const bContext *C, ARegion *ar, DrawData *UNUSED(draw_data)) +{ + + view3d_draw_setup_view(C, ar); + + /* Only 100% compliant on new spec goes bellow */ + view3d_render_pass(C, ar); + + view3d_draw_grid(C, ar); + view3d_draw_manipulator(C); + view3d_draw_region_info(C, ar); +} + + void view3d_main_region_draw(const bContext *C, ARegion *ar) { + Scene *scene = CTX_data_scene(C); View3D *v3d = CTX_wm_view3d(C); RegionView3D *rv3d = ar->regiondata; + /* TODO layers - In the future we should get RE from Layers */ + RenderEngineType *type = RE_engines_find(scene->r.engine); - if (IS_VIEWPORT_LEGACY(v3d)) { + if (IS_VIEWPORT_LEGACY(v3d) && ((type->flag & RE_USE_OGL_PIPELINE) == 0)) { view3d_main_region_draw_legacy(C, ar); return; } @@ -2111,12 +2141,20 @@ void view3d_main_region_draw(const bContext *C, ARegion *ar) if (!rv3d->viewport) rv3d->viewport = GPU_viewport_create(); + GPU_viewport_bind(rv3d->viewport, &ar->winrct); + /* TODO viewport - there is so much to be done, in fact a lot will need to happen in the space_view3d.c * before we even call the drawing routine, but let's move on for now (dfelinto) * but this is a provisory way to start seeing things in the viewport */ DrawData draw_data; view3d_draw_data_init(C, ar, rv3d, &draw_data); - view3d_draw_view(C, ar, &draw_data); + + if (type->flag & RE_USE_OGL_PIPELINE) + view3d_draw_view_new(C, ar, &draw_data); + else + view3d_draw_view(C, ar, &draw_data); + + GPU_viewport_unbind(rv3d->viewport); v3d->flag |= V3D_INVALID_BACKBUF; } diff --git a/source/blender/editors/space_view3d/view3d_intern.h b/source/blender/editors/space_view3d/view3d_intern.h index bed47354d89..f7346a378dc 100644 --- a/source/blender/editors/space_view3d/view3d_intern.h +++ b/source/blender/editors/space_view3d/view3d_intern.h @@ -38,6 +38,7 @@ struct ARegion; struct ARegionType; struct BoundBox; +struct Batch; struct DerivedMesh; struct Object; struct SmokeDomainSettings; diff --git a/source/blender/gpu/CMakeLists.txt b/source/blender/gpu/CMakeLists.txt index c5531b8542e..364e77123d9 100644 --- a/source/blender/gpu/CMakeLists.txt +++ b/source/blender/gpu/CMakeLists.txt @@ -31,6 +31,7 @@ set(INC ../imbuf ../makesdna ../makesrna + ../draw ../editors/include @@ -64,6 +65,7 @@ set(SRC intern/gpu_select.c intern/gpu_shader.c intern/gpu_texture.c + intern/gpu_uniformbuffer.c intern/gpu_viewport.c gawain/attrib_binding.c @@ -122,6 +124,7 @@ set(SRC GPU_select.h GPU_shader.h GPU_texture.h + GPU_uniformbuffer.h GPU_viewport.h intern/gpu_codegen.h @@ -145,10 +148,16 @@ data_to_c_simple(shaders/gpu_shader_image_depth_linear_frag.glsl SRC) data_to_c_simple(shaders/gpu_shader_image_interlace_frag.glsl SRC) data_to_c_simple(shaders/gpu_shader_3D_image_vert.glsl SRC) data_to_c_simple(shaders/gpu_shader_3D_vert.glsl SRC) +data_to_c_simple(shaders/gpu_shader_3D_instance_vert.glsl SRC) data_to_c_simple(shaders/gpu_shader_3D_flat_color_vert.glsl SRC) data_to_c_simple(shaders/gpu_shader_3D_smooth_color_vert.glsl SRC) data_to_c_simple(shaders/gpu_shader_3D_smooth_color_frag.glsl SRC) +data_to_c_simple(shaders/gpu_shader_3D_groundpoint_vert.glsl SRC) +data_to_c_simple(shaders/gpu_shader_3D_groundline_vert.glsl SRC) +data_to_c_simple(shaders/gpu_shader_3D_groundline_geom.glsl SRC) +data_to_c_simple(shaders/gpu_shader_3D_lamp_vert.glsl SRC) + data_to_c_simple(shaders/gpu_shader_point_uniform_color_frag.glsl SRC) data_to_c_simple(shaders/gpu_shader_point_uniform_color_smooth_frag.glsl SRC) data_to_c_simple(shaders/gpu_shader_point_uniform_color_outline_smooth_frag.glsl SRC) diff --git a/source/blender/gpu/GPU_extensions.h b/source/blender/gpu/GPU_extensions.h index 31ad8243c4b..ff00a83d00b 100644 --- a/source/blender/gpu/GPU_extensions.h +++ b/source/blender/gpu/GPU_extensions.h @@ -53,6 +53,8 @@ int GPU_max_textures(void); float GPU_max_texture_anisotropy(void); int GPU_max_color_texture_samples(void); int GPU_max_cube_map_size(void); +int GPU_max_ubo_binds(void); +int GPU_max_ubo_size(void); int GPU_color_depth(void); void GPU_get_dfdy_factors(float fac[2]); diff --git a/source/blender/gpu/GPU_framebuffer.h b/source/blender/gpu/GPU_framebuffer.h index 989b874fd38..9611a6f0577 100644 --- a/source/blender/gpu/GPU_framebuffer.h +++ b/source/blender/gpu/GPU_framebuffer.h @@ -52,6 +52,7 @@ void GPU_texture_bind_as_framebuffer(struct GPUTexture *tex); GPUFrameBuffer *GPU_framebuffer_create(void); bool GPU_framebuffer_texture_attach(GPUFrameBuffer *fb, struct GPUTexture *tex, int slot); void GPU_framebuffer_texture_detach(struct GPUTexture *tex); +void GPU_framebuffer_bind(GPUFrameBuffer *fb); void GPU_framebuffer_slots_bind(GPUFrameBuffer *fb, int slot); void GPU_framebuffer_texture_unbind(GPUFrameBuffer *fb, struct GPUTexture *tex); void GPU_framebuffer_free(GPUFrameBuffer *fb); diff --git a/source/blender/gpu/GPU_shader.h b/source/blender/gpu/GPU_shader.h index 394e751ed9b..b36954dd010 100644 --- a/source/blender/gpu/GPU_shader.h +++ b/source/blender/gpu/GPU_shader.h @@ -38,6 +38,7 @@ extern "C" { typedef struct GPUShader GPUShader; struct GPUTexture; +struct GPUUniformBuffer; /* GPU Shader * - only for fragment shaders now @@ -69,14 +70,17 @@ void GPU_shader_free(GPUShader *shader); void GPU_shader_bind(GPUShader *shader); void GPU_shader_unbind(void); +int GPU_shader_get_program(GPUShader *shader); void *GPU_shader_get_interface(GPUShader *shader); void GPU_shader_set_interface(GPUShader *shader, void *interface); int GPU_shader_get_uniform(GPUShader *shader, const char *name); +int GPU_shader_get_uniform_block(GPUShader *shader, const char *name); void GPU_shader_uniform_vector(GPUShader *shader, int location, int length, int arraysize, const float *value); void GPU_shader_uniform_vector_int(GPUShader *shader, int location, int length, int arraysize, const int *value); +void GPU_shader_uniform_buffer(GPUShader *shader, int location, struct GPUUniformBuffer *ubo); void GPU_shader_uniform_texture(GPUShader *shader, int location, struct GPUTexture *tex); void GPU_shader_uniform_int(GPUShader *shader, int location, int value); void GPU_shader_geometry_stage_primitive_io(GPUShader *shader, int input, int output, int number); @@ -104,6 +108,7 @@ typedef enum GPUBuiltinShader { GPU_SHADER_2D_IMAGE_COLOR, /* for simple 3D drawing */ GPU_SHADER_3D_UNIFORM_COLOR, + GPU_SHADER_3D_UNIFORM_COLOR_INSTANCE, GPU_SHADER_3D_FLAT_COLOR, GPU_SHADER_3D_SMOOTH_COLOR, GPU_SHADER_3D_DEPTH_ONLY, @@ -126,6 +131,10 @@ typedef enum GPUBuiltinShader { GPU_SHADER_3D_POINT_UNIFORM_SIZE_UNIFORM_COLOR_OUTLINE_SMOOTH, GPU_SHADER_3D_POINT_VARYING_SIZE_UNIFORM_COLOR, GPU_SHADER_3D_POINT_VARYING_SIZE_VARYING_COLOR, + /* lamp drawing */ + GPU_SHADER_3D_GROUNDPOINT, + GPU_SHADER_3D_GROUNDLINE, + GPU_SHADER_3D_LAMP_COMMON, GPU_NUM_BUILTIN_SHADERS /* (not an actual shader) */ } GPUBuiltinShader; diff --git a/source/blender/gpu/GPU_uniformbuffer.h b/source/blender/gpu/GPU_uniformbuffer.h new file mode 100644 index 00000000000..bcb6e1077b7 --- /dev/null +++ b/source/blender/gpu/GPU_uniformbuffer.h @@ -0,0 +1,44 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * 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. + * + * The Original Code is Copyright (C) 2005 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): Clement Foucault. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file GPU_uniformbuffer.h + * \ingroup gpu + */ + +typedef struct GPUUniformBuffer GPUUniformBuffer; + +GPUUniformBuffer *GPU_uniformbuffer_create(int size, const void *data, char err_out[256]); +void GPU_uniformbuffer_free(GPUUniformBuffer *ubo); + +void GPU_uniformbuffer_update(GPUUniformBuffer *ubo, const void *data); + +void GPU_uniformbuffer_bind(GPUUniformBuffer *ubo, int number); +#if 0 +void GPU_uniformbuffer_unbind(GPUUniformBuffer *ubo); +#endif + +int GPU_uniformbuffer_bindpoint(GPUUniformBuffer *ubo); diff --git a/source/blender/gpu/GPU_viewport.h b/source/blender/gpu/GPU_viewport.h index fce509377ab..e44657a4647 100644 --- a/source/blender/gpu/GPU_viewport.h +++ b/source/blender/gpu/GPU_viewport.h @@ -34,12 +34,52 @@ #include +#include "DNA_vec_types.h" + +#include "GPU_framebuffer.h" +#include "GPU_texture.h" + typedef struct GPUViewport GPUViewport; -GPUViewport *GPU_viewport_create(void); +#define MAX_BUFFERS 8 +#define MAX_TEXTURES 16 +#define MAX_PASSES 16 + +/* All FramebufferLists are just the same pointers with different names */ +typedef struct FramebufferList { + struct GPUFrameBuffer *framebuffers[MAX_BUFFERS]; +} FramebufferList; + +typedef struct TextureList { + struct GPUTexture *textures[MAX_TEXTURES]; +} TextureList; + +typedef struct PassList { + struct DRWPass *passes[MAX_TEXTURES]; +} PassList; +/* Buffer and textures used by the viewport by default */ +typedef struct DefaultFramebufferList { + struct GPUFrameBuffer *default_fb; +} DefaultFramebufferList; + +typedef struct DefaultTextureList { + struct GPUTexture *color; + struct GPUTexture *depth; +} DefaultTextureList; + +typedef struct DefaultPassList { + struct DRWPass *non_meshes_pass; + struct DRWPass *ob_center_pass; +} DefaultPassList; + +GPUViewport *GPU_viewport_create(void); +void GPU_viewport_bind(GPUViewport *viewport, const rcti *rect); +void GPU_viewport_unbind(GPUViewport *viewport); void GPU_viewport_free(GPUViewport *viewport); +void GPU_viewport_get_engine_data(GPUViewport *viewport, void **fbs, void **txs, void **pss); + /* debug */ bool GPU_viewport_debug_depth_create(GPUViewport *viewport, int width, int height, char err_out[256]); void GPU_viewport_debug_depth_free(GPUViewport *viewport); diff --git a/source/blender/gpu/gawain/batch.c b/source/blender/gpu/gawain/batch.c index a60865d41d2..99c13301177 100644 --- a/source/blender/gpu/gawain/batch.c +++ b/source/blender/gpu/gawain/batch.c @@ -247,3 +247,89 @@ void Batch_draw(Batch* batch) Batch_done_using_program(batch); glBindVertexArray(0); } + +/* clement : temp stuff */ +void Batch_draw_stupid(Batch* batch) +{ + if (batch->vao_id) + glBindVertexArray(batch->vao_id); + else + Batch_prime(batch); + + if (batch->program_dirty) + Batch_update_program_bindings(batch); + + // Batch_use_program(batch); + + //gpuBindMatrices(batch->program); + + if (batch->elem) + { + const ElementList* el = batch->elem; + +#if TRACK_INDEX_RANGE + if (el->base_index) + glDrawRangeElementsBaseVertex(batch->prim_type, el->min_index, el->max_index, el->index_ct, el->index_type, 0, el->base_index); + else + glDrawRangeElements(batch->prim_type, el->min_index, el->max_index, el->index_ct, el->index_type, 0); +#else + glDrawElements(batch->prim_type, el->index_ct, GL_UNSIGNED_INT, 0); +#endif + } + else + glDrawArrays(batch->prim_type, 0, batch->verts->vertex_ct); + + // Batch_done_using_program(batch); + glBindVertexArray(0); +} + +/* clement : temp stuff */ +void Batch_draw_stupid_instanced(Batch* batch, unsigned int instance_vbo, int instance_count) +{ + if (batch->vao_id) + glBindVertexArray(batch->vao_id); + else + Batch_prime(batch); + + if (batch->program_dirty) + Batch_update_program_bindings(batch); + + const GLint loc = glGetAttribLocation(batch->program, "InstanceModelMatrix"); + +#if TRUST_NO_ONE + assert(loc != -1); +#endif + + glBindBuffer(GL_ARRAY_BUFFER, instance_vbo); + glEnableVertexAttribArray(loc); + glVertexAttribPointer(loc + 0, 4, GL_FLOAT, GL_FALSE, sizeof(float)*4*4, (GLvoid*)0); + glEnableVertexAttribArray(loc + 1); + glVertexAttribPointer(loc + 1, 4, GL_FLOAT, GL_FALSE, sizeof(float)*4*4, (GLvoid*)(sizeof(float)*4)); + glEnableVertexAttribArray(loc + 2); + glVertexAttribPointer(loc + 2, 4, GL_FLOAT, GL_FALSE, sizeof(float)*4*4, (GLvoid*)(2 * sizeof(float)*4)); + glEnableVertexAttribArray(loc + 3); + glVertexAttribPointer(loc + 3, 4, GL_FLOAT, GL_FALSE, sizeof(float)*4*4, (GLvoid*)(3 * sizeof(float)*4)); + glBindBuffer(GL_ARRAY_BUFFER, 0); + + glVertexAttribDivisor(loc + 0, 1); + glVertexAttribDivisor(loc + 1, 1); + glVertexAttribDivisor(loc + 2, 1); + glVertexAttribDivisor(loc + 3, 1); + + // Batch_use_program(batch); + + //gpuBindMatrices(batch->program); + + if (batch->elem) + { + const ElementList* el = batch->elem; + + glDrawElementsInstanced(batch->prim_type, el->index_ct, GL_UNSIGNED_INT, 0, instance_count); + } + else + glDrawArraysInstanced(batch->prim_type, 0, batch->verts->vertex_ct, instance_count); + + // Batch_done_using_program(batch); + glBindVertexArray(0); +} + diff --git a/source/blender/gpu/gawain/batch.h b/source/blender/gpu/gawain/batch.h index 932ee182703..8b5c48cca79 100644 --- a/source/blender/gpu/gawain/batch.h +++ b/source/blender/gpu/gawain/batch.h @@ -57,6 +57,8 @@ void Batch_Uniform3fv(Batch*, const char* name, const float data[3]); void Batch_Uniform4fv(Batch*, const char* name, const float data[4]); void Batch_draw(Batch*); +void Batch_draw_stupid(Batch* batch); +void Batch_draw_stupid_instanced(Batch* batch, unsigned int instance_vbo, int instance_count); diff --git a/source/blender/gpu/intern/gpu_extensions.c b/source/blender/gpu/intern/gpu_extensions.c index e8fd4b8b8b1..d7ed65e853e 100644 --- a/source/blender/gpu/intern/gpu_extensions.c +++ b/source/blender/gpu/intern/gpu_extensions.c @@ -69,6 +69,8 @@ static struct GPUGlobal { GLint maxtexsize; GLint maxcubemapsize; GLint maxtextures; + GLint maxubosize; + GLint maxubobinds; bool extdisabled; int colordepth; int samples_color_texture_max; @@ -121,6 +123,16 @@ int GPU_max_cube_map_size(void) return GG.maxcubemapsize; } +int GPU_max_ubo_binds(void) +{ + return GG.maxubobinds; +} + +int GPU_max_ubo_size(void) +{ + return GG.maxubosize; +} + void GPU_get_dfdy_factors(float fac[2]) { copy_v2_v2(fac, GG.dfdyfactors); @@ -154,6 +166,9 @@ void gpu_extensions_init(void) else GG.max_anisotropy = 1.0f; + glGetIntegerv(GL_MAX_UNIFORM_BUFFER_BINDINGS, &GG.maxubobinds); + glGetIntegerv(GL_MAX_UNIFORM_BLOCK_SIZE, &GG.maxubosize); + GLint r, g, b; glGetIntegerv(GL_RED_BITS, &r); glGetIntegerv(GL_GREEN_BITS, &g); diff --git a/source/blender/gpu/intern/gpu_framebuffer.c b/source/blender/gpu/intern/gpu_framebuffer.c index 2ef8018e5e9..1efc451f4a8 100644 --- a/source/blender/gpu/intern/gpu_framebuffer.c +++ b/source/blender/gpu/intern/gpu_framebuffer.c @@ -260,6 +260,43 @@ void GPU_framebuffer_slots_bind(GPUFrameBuffer *fb, int slot) glPushMatrix(); } +void GPU_framebuffer_bind(GPUFrameBuffer *fb) +{ + int numslots = 0, i; + GLenum attachments[4]; + GLenum readattachement = 0; + GPUTexture *tex; + + for (i = 0; i < 4; i++) { + if (fb->colortex[i]) { + attachments[numslots] = GL_COLOR_ATTACHMENT0 + i; + tex = fb->colortex[i]; + + if (!readattachement) + readattachement = GL_COLOR_ATTACHMENT0 + i; + + numslots++; + } + } + + /* bind framebuffer */ + glBindFramebuffer(GL_FRAMEBUFFER, fb->object); + + if (numslots == 0) { + glDrawBuffer(GL_NONE); + glReadBuffer(GL_NONE); + tex = fb->depthtex; + } + else { + /* last bound prevails here, better allow explicit control here too */ + glDrawBuffers(numslots, attachments); + glReadBuffer(readattachement); + } + + glViewport(0, 0, GPU_texture_width(tex), GPU_texture_height(tex)); + GG.currentfb = fb->object; +} + void GPU_framebuffer_texture_unbind(GPUFrameBuffer *UNUSED(fb), GPUTexture *UNUSED(tex)) { @@ -283,7 +320,6 @@ void GPU_framebuffer_bind_no_save(GPUFrameBuffer *fb, int slot) /* push matrices and set default viewport and matrix */ glViewport(0, 0, GPU_texture_width(fb->colortex[slot]), GPU_texture_height(fb->colortex[slot])); GG.currentfb = fb->object; - GG.currentfb = fb->object; } bool GPU_framebuffer_bound(GPUFrameBuffer *fb) diff --git a/source/blender/gpu/intern/gpu_shader.c b/source/blender/gpu/intern/gpu_shader.c index b81c19d5c70..0d6fd5f7b99 100644 --- a/source/blender/gpu/intern/gpu_shader.c +++ b/source/blender/gpu/intern/gpu_shader.c @@ -37,6 +37,7 @@ #include "GPU_debug.h" #include "GPU_extensions.h" #include "GPU_shader.h" +#include "GPU_uniformbuffer.h" #include "GPU_texture.h" #include "gpu_shader_private.h" @@ -64,10 +65,16 @@ extern char datatoc_gpu_shader_image_modulate_alpha_frag_glsl[]; extern char datatoc_gpu_shader_image_rect_modulate_alpha_frag_glsl[]; extern char datatoc_gpu_shader_image_depth_linear_frag_glsl[]; extern char datatoc_gpu_shader_3D_vert_glsl[]; +extern char datatoc_gpu_shader_3D_instance_vert_glsl[]; extern char datatoc_gpu_shader_3D_flat_color_vert_glsl[]; extern char datatoc_gpu_shader_3D_smooth_color_vert_glsl[]; extern char datatoc_gpu_shader_3D_smooth_color_frag_glsl[]; +extern char datatoc_gpu_shader_3D_groundpoint_vert_glsl[]; +extern char datatoc_gpu_shader_3D_groundline_vert_glsl[]; +extern char datatoc_gpu_shader_3D_groundline_geom_glsl[]; +extern char datatoc_gpu_shader_3D_lamp_vert_glsl[]; + extern char datatoc_gpu_shader_point_uniform_color_frag_glsl[]; extern char datatoc_gpu_shader_point_uniform_color_smooth_frag_glsl[]; extern char datatoc_gpu_shader_point_uniform_color_outline_smooth_frag_glsl[]; @@ -511,11 +518,24 @@ int GPU_shader_get_uniform(GPUShader *shader, const char *name) return glGetUniformLocation(shader->program, name); } +int GPU_shader_get_uniform_block(GPUShader *shader, const char *name) +{ + BLI_assert(shader && shader->program); + + return glGetUniformBlockIndex(shader->program, name); +} + void *GPU_shader_get_interface(GPUShader *shader) { return shader->uniform_interface; } +/* Clement : Temp */ +int GPU_shader_get_program(GPUShader *shader) +{ + return (int)shader->program; +} + void GPU_shader_set_interface(GPUShader *shader, void *interface) { shader->uniform_interface = interface; @@ -563,6 +583,17 @@ void GPU_shader_geometry_stage_primitive_io(GPUShader *shader, int input, int ou } } +void GPU_shader_uniform_buffer(GPUShader *shader, int location, GPUUniformBuffer *ubo) +{ + int bindpoint = GPU_uniformbuffer_bindpoint(ubo); + + if (location == -1) { + return; + } + + glUniformBlockBinding(shader->program, location, bindpoint); +} + void GPU_shader_uniform_texture(GPUShader *UNUSED(shader), int location, GPUTexture *tex) { int number = GPU_texture_bound_number(tex); @@ -645,12 +676,21 @@ GPUShader *GPU_shader_get_builtin_shader(GPUBuiltinShader shader) [GPU_SHADER_2D_IMAGE_COLOR] = { datatoc_gpu_shader_2D_image_vert_glsl, datatoc_gpu_shader_image_color_frag_glsl }, [GPU_SHADER_3D_UNIFORM_COLOR] = { datatoc_gpu_shader_3D_vert_glsl, datatoc_gpu_shader_uniform_color_frag_glsl }, + [GPU_SHADER_3D_UNIFORM_COLOR_INSTANCE] = { datatoc_gpu_shader_3D_instance_vert_glsl, datatoc_gpu_shader_uniform_color_frag_glsl }, [GPU_SHADER_3D_FLAT_COLOR] = { datatoc_gpu_shader_3D_flat_color_vert_glsl, datatoc_gpu_shader_flat_color_frag_glsl }, [GPU_SHADER_3D_SMOOTH_COLOR] = { datatoc_gpu_shader_3D_smooth_color_vert_glsl, datatoc_gpu_shader_3D_smooth_color_frag_glsl }, [GPU_SHADER_3D_DEPTH_ONLY] = { datatoc_gpu_shader_3D_vert_glsl, datatoc_gpu_shader_depth_only_frag_glsl }, + [GPU_SHADER_3D_GROUNDPOINT] = { datatoc_gpu_shader_3D_groundpoint_vert_glsl, datatoc_gpu_shader_point_uniform_color_frag_glsl }, + [GPU_SHADER_3D_GROUNDLINE] = { datatoc_gpu_shader_3D_groundline_vert_glsl, + datatoc_gpu_shader_uniform_color_frag_glsl, + datatoc_gpu_shader_3D_groundline_geom_glsl }, + + [GPU_SHADER_3D_LAMP_COMMON] = { datatoc_gpu_shader_3D_lamp_vert_glsl, + datatoc_gpu_shader_uniform_color_frag_glsl}, + [GPU_SHADER_2D_POINT_FIXED_SIZE_UNIFORM_COLOR] = { datatoc_gpu_shader_2D_vert_glsl, datatoc_gpu_shader_point_uniform_color_frag_glsl }, [GPU_SHADER_2D_POINT_VARYING_SIZE_VARYING_COLOR] = diff --git a/source/blender/gpu/intern/gpu_texture.c b/source/blender/gpu/intern/gpu_texture.c index 6fb658e20eb..3513250993e 100644 --- a/source/blender/gpu/intern/gpu_texture.c +++ b/source/blender/gpu/intern/gpu_texture.c @@ -91,6 +91,7 @@ static GLenum GPU_texture_get_format(int components, GPUTextureFormat data_type, /* Formats texture & renderbuffer */ case GPU_RGBA16F: return GL_RGBA16F; case GPU_RG32F: return GL_RG32F; + case GPU_RG16F: return GL_RG16F; case GPU_RGBA8: return GL_RGBA8; case GPU_R8: return GL_R8; /* Special formats texture & renderbuffer */ diff --git a/source/blender/gpu/intern/gpu_uniformbuffer.c b/source/blender/gpu/intern/gpu_uniformbuffer.c new file mode 100644 index 00000000000..76aa1a8226f --- /dev/null +++ b/source/blender/gpu/intern/gpu_uniformbuffer.c @@ -0,0 +1,105 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * 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. + * + * The Original Code is Copyright (C) 2005 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): Clement Foucault. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file gpu_uniformbuffer.c + * \ingroup gpu + */ + +#include "MEM_guardedalloc.h" + +#include "BLI_blenlib.h" + +#include "GPU_extensions.h" +#include "GPU_glew.h" +#include "GPU_uniformbuffer.h" + +struct GPUUniformBuffer { + int size; /* in bytes */ + GLuint bindcode; /* opengl identifier for UBO */ + int bindpoint; /* current binding point */ +}; + +GPUUniformBuffer *GPU_uniformbuffer_create(int size, const void *data, char err_out[256]) +{ + GPUUniformBuffer *ubo = MEM_callocN(sizeof(GPUUniformBuffer), "GPUUniformBuffer"); + ubo->size = size; + + /* Generate Buffer object */ + glGenBuffers(1, &ubo->bindcode); + + if (!ubo->bindcode) { + if (err_out) + BLI_snprintf(err_out, 256, "GPUUniformBuffer: UBO create failed"); + GPU_uniformbuffer_free(ubo); + return NULL; + } + + if (ubo->size > GPU_max_ubo_size()) { + if (err_out) + BLI_snprintf(err_out, 256, "GPUUniformBuffer: UBO too big"); + GPU_uniformbuffer_free(ubo); + return NULL; + } + + glBindBuffer(GL_UNIFORM_BUFFER, ubo->bindcode); + glBufferData(GL_UNIFORM_BUFFER, ubo->size, data, GL_DYNAMIC_DRAW); + glBindBuffer(GL_UNIFORM_BUFFER, 0); + + return ubo; +} + +void GPU_uniformbuffer_free(GPUUniformBuffer *ubo) +{ + glDeleteBuffers(1, &ubo->bindcode); + MEM_freeN(ubo); +} + +void GPU_uniformbuffer_update(GPUUniformBuffer *ubo, const void *data) +{ + glBindBuffer(GL_UNIFORM_BUFFER, ubo->bindcode); + glBufferSubData(GL_UNIFORM_BUFFER, 0, ubo->size, data); + glBindBuffer(GL_UNIFORM_BUFFER, 0); +} + +void GPU_uniformbuffer_bind(GPUUniformBuffer *ubo, int number) +{ + if (number >= GPU_max_ubo_binds()) { + fprintf(stderr, "Not enough UBO slots.\n"); + return; + } + + if (ubo->bindcode != 0) { + glBindBufferBase(GL_UNIFORM_BUFFER, number, ubo->bindcode); + } + + ubo->bindpoint = number; +} + +int GPU_uniformbuffer_bindpoint(GPUUniformBuffer *ubo) +{ + return ubo->bindpoint; +} \ No newline at end of file diff --git a/source/blender/gpu/intern/gpu_viewport.c b/source/blender/gpu/intern/gpu_viewport.c index a4fb3494639..b1964857ab1 100644 --- a/source/blender/gpu/intern/gpu_viewport.c +++ b/source/blender/gpu/intern/gpu_viewport.c @@ -31,10 +31,19 @@ * System that manages viewport drawing. */ +#include + +#include "BLI_rect.h" + +#include "DNA_vec_types.h" + +#include "GPU_framebuffer.h" #include "GPU_glew.h" #include "GPU_immediate.h" -#include "GPU_viewport.h" #include "GPU_texture.h" +#include "GPU_viewport.h" + +#include "DRW_engine.h" #include "MEM_guardedalloc.h" @@ -43,19 +52,200 @@ struct GPUViewport { /* debug */ GPUTexture *debug_depth; - int debug_width, debug_height; + int size[2]; + + /* Viewport Buffer Storage */ + /* TODO indentify to what engine conf are theses buffers */ + DefaultFramebufferList *fbl; + DefaultTextureList *txl; + DefaultPassList *psl; }; +static void GPU_viewport_buffers_free(GPUViewport *viewport); +static void GPU_viewport_passes_free(GPUViewport *viewport); + GPUViewport *GPU_viewport_create(void) { GPUViewport *viewport = MEM_callocN(sizeof(GPUViewport), "GPUViewport"); + viewport->fbl = MEM_callocN(sizeof(FramebufferList), "FramebufferList"); + viewport->txl = MEM_callocN(sizeof(TextureList), "TextureList"); + viewport->psl = MEM_callocN(sizeof(PassList), "PassList"); + viewport->size[0] = viewport->size[1] = -1; + return viewport; } +void GPU_viewport_get_engine_data(GPUViewport *viewport, void **fbs, void **txs, void **pss) +{ + *fbs = viewport->fbl; + *txs = viewport->txl; + *pss = viewport->psl; +} + +void GPU_viewport_bind(GPUViewport *viewport, const rcti *rect) +{ + /* add one pixel because of scissor test */ + int rect_w = BLI_rcti_size_x(rect) + 1, rect_h = BLI_rcti_size_y(rect) + 1; + +#ifndef WITH_VIEWPORT_CACHE_TEST + /* TODO for testing only, we need proper cache invalidation */ + GPU_viewport_passes_free(viewport); +#endif + + if (viewport->fbl->default_fb) { + if (rect_w != viewport->size[0] || rect_h != viewport->size[1]) { + GPU_viewport_buffers_free(viewport); + } + } + + if (!viewport->fbl->default_fb) { + bool ok = true; + viewport->size[0] = rect_w; + viewport->size[1] = rect_h; + + viewport->fbl->default_fb = GPU_framebuffer_create(); + if (!viewport->fbl->default_fb) { + ok = false; + goto cleanup; + } + + /* Color */ + /* No multi samples for now */ + viewport->txl->color = GPU_texture_create_2D(rect_w, rect_h, NULL, NULL); + if (!viewport->txl->color) { + ok = false; + goto cleanup; + } + + if (!GPU_framebuffer_texture_attach(viewport->fbl->default_fb, viewport->txl->color, 0)) { + ok = false; + goto cleanup; + } + + /* Depth */ + viewport->txl->depth = GPU_texture_create_depth(rect_w, rect_h, NULL); + if (!viewport->txl->depth) { + ok = false; + goto cleanup; + } + else if (!GPU_framebuffer_texture_attach(viewport->fbl->default_fb, viewport->txl->depth, 0)) { + ok = false; + goto cleanup; + } + else if (!GPU_framebuffer_check_valid(viewport->fbl->default_fb, NULL)) { + ok = false; + goto cleanup; + } + +cleanup: + if (!ok) { + GPU_viewport_free(viewport); + MEM_freeN(viewport); + return; + } + + GPU_framebuffer_restore(); + } + + GPU_framebuffer_slots_bind(viewport->fbl->default_fb, 0); +} + +static void draw_ofs_to_screen(GPUViewport *viewport) +{ + GPUTexture *color = viewport->txl->color; + + const float w = (float)GPU_texture_width(color); + const float h = (float)GPU_texture_height(color); + + VertexFormat *format = immVertexFormat(); + unsigned texcoord = add_attrib(format, "texCoord", GL_FLOAT, 2, KEEP_FLOAT); + unsigned pos = add_attrib(format, "pos", GL_FLOAT, 2, KEEP_FLOAT); + + immBindBuiltinProgram(GPU_SHADER_3D_IMAGE_MODULATE_ALPHA); + + GPU_texture_bind(color, 0); + + immUniform1i("image", 0); /* default GL_TEXTURE0 unit */ + + immBegin(GL_QUADS, 4); + + immAttrib2f(texcoord, 0.0f, 0.0f); + immVertex2f(pos, 0.0f, 0.0f); + + immAttrib2f(texcoord, 1.0f, 0.0f); + immVertex2f(pos, w, 0.0f); + + immAttrib2f(texcoord, 1.0f, 1.0f); + immVertex2f(pos, w, h); + + immAttrib2f(texcoord, 0.0f, 1.0f); + immVertex2f(pos, 0.0f, h); + + immEnd(); + + GPU_texture_unbind(color); + + immUnbindProgram(); +} + +void GPU_viewport_unbind(GPUViewport *viewport) +{ + if (viewport->fbl->default_fb) { + GPU_framebuffer_texture_unbind(NULL, NULL); + GPU_framebuffer_restore(); + + glEnable(GL_SCISSOR_TEST); + + /* This might be bandwidth limiting */ + draw_ofs_to_screen(viewport); + } +} + +static void GPU_viewport_buffers_free(GPUViewport *viewport) +{ + FramebufferList *fbl = (FramebufferList *)viewport->fbl; + TextureList *txl = (TextureList *)viewport->txl; + int i; + for (i = MAX_BUFFERS - 1; i > -1; --i) { + GPUFrameBuffer *fb = fbl->framebuffers[i]; + if (fb) { + GPU_framebuffer_free(fb); + fbl->framebuffers[i] = NULL; + } + } + for (i = MAX_TEXTURES - 1; i > -1; --i) { + GPUTexture *tex = txl->textures[i]; + if (tex) { + GPU_texture_free(tex); + txl->textures[i] = NULL; + } + } +} + +static void GPU_viewport_passes_free(GPUViewport *viewport) +{ + PassList *psl = (PassList *)viewport->psl; + int i; + + for (i = MAX_PASSES - 1; i > -1; --i) { + struct DRWPass *pass = psl->passes[i]; + if (pass) { + DRW_pass_free(pass); + MEM_freeN(pass); + psl->passes[i] = NULL; + } + } +} + void GPU_viewport_free(GPUViewport *viewport) { GPU_viewport_debug_depth_free(viewport); - MEM_freeN(viewport); + GPU_viewport_buffers_free(viewport); + GPU_viewport_passes_free(viewport); + + MEM_freeN(viewport->fbl); + MEM_freeN(viewport->txl); + MEM_freeN(viewport->psl); } /****************** debug ********************/ diff --git a/source/blender/gpu/shaders/gpu_shader_3D_groundline_geom.glsl b/source/blender/gpu/shaders/gpu_shader_3D_groundline_geom.glsl new file mode 100644 index 00000000000..f16fa21b342 --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_3D_groundline_geom.glsl @@ -0,0 +1,16 @@ + +/* Make to be used with dynamic batching so no Model Matrix needed */ +uniform mat4 ViewProjectionMatrix; + +layout(points) in; +layout(line_strip, max_vertices = 2) out; + +void main() +{ + vec3 vert = gl_in[0].gl_Position.xyz; + gl_Position = ViewProjectionMatrix * vec4(vert.xyz, 1.0); + EmitVertex(); + gl_Position = ViewProjectionMatrix * vec4(vert.xy, 0.0, 1.0); + EmitVertex(); + EndPrimitive(); +} diff --git a/source/blender/gpu/shaders/gpu_shader_3D_groundline_vert.glsl b/source/blender/gpu/shaders/gpu_shader_3D_groundline_vert.glsl new file mode 100644 index 00000000000..60793bf56b6 --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_3D_groundline_vert.glsl @@ -0,0 +1,8 @@ + +/* Does Nothing */ +in vec3 pos; + +void main() +{ + gl_Position = vec4(pos, 1.0); +} diff --git a/source/blender/gpu/shaders/gpu_shader_3D_groundpoint_vert.glsl b/source/blender/gpu/shaders/gpu_shader_3D_groundpoint_vert.glsl new file mode 100644 index 00000000000..be6b6014a19 --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_3D_groundpoint_vert.glsl @@ -0,0 +1,11 @@ + +/* Make to be used with dynamic batching so no Model Matrix needed */ +uniform mat4 ViewProjectionMatrix; + +in vec3 pos; + +void main() +{ + gl_Position = ViewProjectionMatrix * vec4(pos.xy, 0.0, 1.0); + gl_PointSize = 2.0; +} diff --git a/source/blender/gpu/shaders/gpu_shader_3D_instance_vert.glsl b/source/blender/gpu/shaders/gpu_shader_3D_instance_vert.glsl new file mode 100644 index 00000000000..7eb321f2996 --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_3D_instance_vert.glsl @@ -0,0 +1,10 @@ + +uniform mat4 ViewProjectionMatrix; + +in vec3 pos; +in mat4 InstanceModelMatrix; + +void main() +{ + gl_Position = ViewProjectionMatrix * InstanceModelMatrix * vec4(pos, 1.0); +} diff --git a/source/blender/gpu/shaders/gpu_shader_3D_lamp_vert.glsl b/source/blender/gpu/shaders/gpu_shader_3D_lamp_vert.glsl new file mode 100644 index 00000000000..dbc683ef42b --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_3D_lamp_vert.glsl @@ -0,0 +1,24 @@ + +uniform mat4 ViewProjectionMatrix; +uniform vec3 screen_vecs[2]; +uniform float size; +uniform float pixel_size; + +in vec2 pos; +in mat4 InstanceModelMatrix; + +#define lamp_pos InstanceModelMatrix[3].xyz + +float mul_project_m4_v3_zfac(in vec3 co) +{ + return (ViewProjectionMatrix[0][3] * co.x) + + (ViewProjectionMatrix[1][3] * co.y) + + (ViewProjectionMatrix[2][3] * co.z) + ViewProjectionMatrix[3][3]; +} + +void main() +{ + float pix_size = mul_project_m4_v3_zfac(lamp_pos) * pixel_size; + vec3 screen_pos = screen_vecs[0].xyz * pos.x + screen_vecs[1].xyz * pos.y; + gl_Position = ViewProjectionMatrix * vec4(lamp_pos + screen_pos * size * pix_size, 1.0); +} diff --git a/source/blender/makesdna/DNA_layer_types.h b/source/blender/makesdna/DNA_layer_types.h index 6f6c6d7d145..3a4293c8ad8 100644 --- a/source/blender/makesdna/DNA_layer_types.h +++ b/source/blender/makesdna/DNA_layer_types.h @@ -59,6 +59,7 @@ typedef struct LayerCollection { ListBase object_bases; /* (ObjectBase *)LinkData->data - synced with collection->objects and collection->filter_objects */ ListBase overrides; ListBase layer_collections; /* synced with collection->collections */ + ListBase engine_settings; /* CollectionEngineSettings */ } LayerCollection; typedef struct SceneLayer { @@ -102,8 +103,54 @@ enum { /* SceneLayer->flag */ enum { SCENE_LAYER_RENDER = (1 << 0), + SCENE_LAYER_ENGINE_DIRTY = (1 << 1), }; + +/* *************************************************************** */ +/* Engine Settings */ + +typedef struct CollectionEngineProperty { + struct CollectionEngineProperty *next, *prev; + char name[64]; /* MAX_NAME */ + short type; + short pad; + char flag; + char pad2[3]; +} CollectionEngineProperty; + +typedef struct CollectionEnginePropertyInt { + struct CollectionEngineProperty data; + int value; + int pad; +} CollectionEnginePropertyInt; + +typedef struct CollectionEnginePropertyFloat { + struct CollectionEngineProperty data; + float value; + float pad; +} CollectionEnginePropertyFloat; + +typedef struct CollectionEngineSettings { + struct CollectionEngineSettings *next, *prev; + char name[32]; /* engine name - MAX_NAME */ + ListBase properties; /* CollectionProperty */ +} CollectionEngineSettings; + +/* CollectionEngineProperty->flag */ +enum { + COLLECTION_PROP_USE = (1 << 0), +}; + +/* CollectionEntineProperty.type */ +typedef enum CollectionEnginePropertyType { + COLLECTION_PROP_TYPE_FLOAT = 0, + COLLECTION_PROP_TYPE_INT = 1, +} CollectionEnginePropertyType; + +/* *************************************************************** */ + + #ifdef __cplusplus } #endif diff --git a/source/blender/makesdna/DNA_material_types.h b/source/blender/makesdna/DNA_material_types.h index 0c500e366a7..bd8278f897a 100644 --- a/source/blender/makesdna/DNA_material_types.h +++ b/source/blender/makesdna/DNA_material_types.h @@ -90,6 +90,43 @@ typedef struct TexPaintSlot { int pad; } TexPaintSlot; +/* Material Engine Settings */ +typedef struct MaterialEngineSettings { + struct MaterialEngineSettings *next, *prev; + char name[32]; /* engine name - MAX_NAME */ + void *data; +} MaterialEngineSettings; + +/* Clay engine */ + +/* MaterialRuntimeClay.flag */ +#define CLAY_OUTDATED 1 + +typedef struct MaterialEngineSettingsClay { + short type; + short matcap_icon; /* Icon ID */ + + float matcap_rot; + float matcap_hue; + float matcap_sat; + float matcap_val; + + float ssao_distance; + float ssao_attenuation; + float ssao_factor_cavity; + float ssao_factor_edge; + + /* Runtime */ + short flag; + short pad; + int ubo_index; +} MaterialEngineSettingsClay; + +/* MaterialEngineSettingsClay.type */ +#define CLAY_MATCAP_NONE 0 +#define CLAY_MATCAP_SIMPLE 1 +#define CLAY_MATCAP_COMPLETE 2 + typedef struct Material { ID id; struct AnimData *adt; /* animation data (must be immediately after id for utilities to use it) */ @@ -203,6 +240,9 @@ typedef struct Material { struct TexPaintSlot *texpaintslot; /* cached slot for painting. Make sure to recalculate before use * with refresh_texpaint_image_cache */ + /* Engine Settings */ + ListBase engines_settings; /* MaterialEngineSettings */ + ListBase gpumaterial; /* runtime */ } Material; diff --git a/source/blender/makesdna/DNA_object_types.h b/source/blender/makesdna/DNA_object_types.h index 60aaa4ace20..080ade57c0d 100644 --- a/source/blender/makesdna/DNA_object_types.h +++ b/source/blender/makesdna/DNA_object_types.h @@ -46,6 +46,7 @@ struct Object; struct AnimData; struct Ipo; struct BoundBox; +struct CollectionSettings; struct Path; struct Material; struct PartDeflect; @@ -302,6 +303,8 @@ typedef struct Object { LodLevel *currentlod; struct PreviewImage *preview; + + struct ListBase *collection_settings; /* used by depsgraph, flushed from collection-tree */ } Object; /* Warning, this is not used anymore because hooks are now modifiers */ diff --git a/source/blender/makesdna/DNA_scene_types.h b/source/blender/makesdna/DNA_scene_types.h index ba5e50ec441..6e56824b176 100644 --- a/source/blender/makesdna/DNA_scene_types.h +++ b/source/blender/makesdna/DNA_scene_types.h @@ -48,6 +48,7 @@ extern "C" { #include "DNA_freestyle_types.h" #include "DNA_gpu_types.h" #include "DNA_layer_types.h" +#include "DNA_material_types.h" #include "DNA_userdef_types.h" struct CurveMapping; @@ -538,6 +539,50 @@ typedef enum BakePassFilter { #define R_BAKE_PASS_FILTER_ALL (~0) +/* *************************************************************** */ +/* Engine Settings */ + +typedef struct RenderEngineSettings { + struct RenderEngineSettings *next, *prev; + char name[32]; /* engine name */ + void *data; +} RenderEngineSettings; + +/* Render Data */ +typedef struct RenderEngineSettingsClay { + /* Use same layout as MaterialEngineSettingsClay so this struct + * can be used as Material Settings. */ + short type; + short matcap_icon; /* Icon ID */ + + float matcap_rot; + float matcap_hue; + float matcap_sat; + float matcap_val; + + float ssao_distance; + float ssao_attenuation; + float ssao_factor_cavity; + float ssao_factor_edge; + + short flag; + short pad; + int ubo_index; + /* end of MaterialEngineSettingsClay */ + + /* Global Settings */ + short options; + short pad1; + int ssao_samples; + int pad2[2]; +} RenderEngineSettingsClay; + +/* RenderEngineSettingsClay.options */ +typedef enum ClayFlagSettings { + CLAY_USE_AO = (1 << 0), + CLAY_USE_HSV = (1 << 1), +} ClayFlagSettings; + /* *************************************************************** */ /* Render Data */ @@ -1707,6 +1752,9 @@ typedef struct Scene { struct SceneCollection *collection; int active_layer; int pad4; + + ListBase engines_settings; /* RenderEngineSettings */ + int pad5[2]; } Scene; /* **************** RENDERDATA ********************* */ @@ -1895,6 +1943,7 @@ enum { /* scene->r.engine (scene.c) */ extern const char *RE_engine_id_BLENDER_RENDER; extern const char *RE_engine_id_BLENDER_GAME; +extern const char *RE_engine_id_BLENDER_CLAY; extern const char *RE_engine_id_CYCLES; /* **************** SCENE ********************* */ diff --git a/source/blender/makesrna/RNA_access.h b/source/blender/makesrna/RNA_access.h index 9c45e34f211..2221526fa8b 100644 --- a/source/blender/makesrna/RNA_access.h +++ b/source/blender/makesrna/RNA_access.h @@ -106,6 +106,7 @@ extern StructRNA RNA_ClothCollisionSettings; extern StructRNA RNA_ClothModifier; extern StructRNA RNA_ClothSettings; extern StructRNA RNA_CloudsTexture; +extern StructRNA RNA_CollectionEngineSettings; extern StructRNA RNA_CollectionProperty; extern StructRNA RNA_CollisionModifier; extern StructRNA RNA_CollisionSensor; @@ -385,6 +386,8 @@ extern StructRNA RNA_MaterialStrand; extern StructRNA RNA_MaterialSubsurfaceScattering; extern StructRNA RNA_MaterialTextureSlot; extern StructRNA RNA_MaterialVolume; +extern StructRNA RNA_MaterialEngineSettings; +extern StructRNA RNA_MaterialEngineSettingsClay; extern StructRNA RNA_Mask; extern StructRNA RNA_MaskLayer; extern StructRNA RNA_Menu; @@ -500,6 +503,8 @@ extern StructRNA RNA_RenderLayer; extern StructRNA RNA_RenderPass; extern StructRNA RNA_RenderResult; extern StructRNA RNA_RenderSettings; +extern StructRNA RNA_RenderEngineSettings; +extern StructRNA RNA_RenderEngineSettingsClay; extern StructRNA RNA_RigidBodyWorld; extern StructRNA RNA_RigidBodyObject; extern StructRNA RNA_RigidBodyJointConstraint; diff --git a/source/blender/makesrna/intern/CMakeLists.txt b/source/blender/makesrna/intern/CMakeLists.txt index 0f3ea27a7f9..0bf2bbb6109 100644 --- a/source/blender/makesrna/intern/CMakeLists.txt +++ b/source/blender/makesrna/intern/CMakeLists.txt @@ -192,6 +192,10 @@ if(WITH_GAMEENGINE) add_definitions(-DWITH_GAMEENGINE) endif() +if(WITH_CLAY_ENGINE) + add_definitions(-DWITH_CLAY_ENGINE) +endif() + if(WITH_IMAGE_OPENEXR) add_definitions(-DWITH_OPENEXR) endif() @@ -341,6 +345,7 @@ blender_include_dirs( ../../bmesh ../../blentranslation ../../depsgraph + ../../draw ../../gpu ../../imbuf ../../ikplugin diff --git a/source/blender/makesrna/intern/rna_material.c b/source/blender/makesrna/intern/rna_material.c index b293f20dd95..4d3e3ffca26 100644 --- a/source/blender/makesrna/intern/rna_material.c +++ b/source/blender/makesrna/intern/rna_material.c @@ -313,6 +313,31 @@ static void rna_MaterialTextureSlot_use_set(PointerRNA *ptr, int value) } } +static StructRNA *rna_MaterialEngineSettings_refine(PointerRNA *ptr) +{ +#ifdef WITH_CLAY_ENGINE + MaterialEngineSettings *mes = (MaterialEngineSettings *)ptr->data; + if (STREQ(mes->name, RE_engine_id_BLENDER_CLAY)) { + return &RNA_MaterialEngineSettingsClay; + } +#endif + return &RNA_MaterialEngineSettings; +} + +static void rna_Material_update_engine_data(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *UNUSED(ptr)) +{ +#if 0 + Material *ma = (Material *)ptr->data; + RenderEngineSettings *ed = DRW_material_settings_get(ma, sce->r.engine, NULL); + + if (ed->runtime) { + MEM_freeN(ed->runtime); + ed->runtime = NULL; + } +#endif + WM_main_add_notifier(NC_SPACE | ND_SPACE_VIEW3D, NULL); +} + static void rna_Material_use_diffuse_ramp_set(PointerRNA *ptr, int value) { Material *ma = (Material *)ptr->data; @@ -824,6 +849,118 @@ static void rna_def_material_mtex(BlenderRNA *brna) RNA_def_property_update(prop, 0, "rna_Material_update"); } +static void rna_def_material_settings_clay(BlenderRNA *brna) +{ + StructRNA *srna; + PropertyRNA *prop; + + static EnumPropertyItem clay_matcap_items[] = { + {ICON_MATCAP_01, "01", ICON_MATCAP_01, "", ""}, + {ICON_MATCAP_02, "02", ICON_MATCAP_02, "", ""}, + {ICON_MATCAP_03, "03", ICON_MATCAP_03, "", ""}, + {ICON_MATCAP_04, "04", ICON_MATCAP_04, "", ""}, + {ICON_MATCAP_05, "05", ICON_MATCAP_05, "", ""}, + {ICON_MATCAP_06, "06", ICON_MATCAP_06, "", ""}, + {ICON_MATCAP_07, "07", ICON_MATCAP_07, "", ""}, + {ICON_MATCAP_08, "08", ICON_MATCAP_08, "", ""}, + {ICON_MATCAP_09, "09", ICON_MATCAP_09, "", ""}, + {ICON_MATCAP_10, "10", ICON_MATCAP_10, "", ""}, + {ICON_MATCAP_11, "11", ICON_MATCAP_11, "", ""}, + {ICON_MATCAP_12, "12", ICON_MATCAP_12, "", ""}, + {ICON_MATCAP_13, "13", ICON_MATCAP_13, "", ""}, + {ICON_MATCAP_14, "14", ICON_MATCAP_14, "", ""}, + {ICON_MATCAP_15, "15", ICON_MATCAP_15, "", ""}, + {ICON_MATCAP_16, "16", ICON_MATCAP_16, "", ""}, + {ICON_MATCAP_17, "17", ICON_MATCAP_17, "", ""}, + {ICON_MATCAP_18, "18", ICON_MATCAP_18, "", ""}, + {ICON_MATCAP_19, "19", ICON_MATCAP_19, "", ""}, + {ICON_MATCAP_20, "20", ICON_MATCAP_20, "", ""}, + {ICON_MATCAP_21, "21", ICON_MATCAP_21, "", ""}, + {ICON_MATCAP_22, "22", ICON_MATCAP_22, "", ""}, + {ICON_MATCAP_23, "23", ICON_MATCAP_23, "", ""}, + {ICON_MATCAP_24, "24", ICON_MATCAP_24, "", ""}, + {0, NULL, 0, NULL, NULL} + }; + + static EnumPropertyItem clay_matcap_type[] = { + {CLAY_MATCAP_NONE, "NONE", 0, "Scene", "Use default scene matcap"}, + {CLAY_MATCAP_SIMPLE, "SIMPLE", 0, "Simple", "Let you choose the texture to use with the default settings"}, + {CLAY_MATCAP_COMPLETE, "COMPLETE", 0, "Complete", "Expose all settings"}, + {0, NULL, 0, NULL, NULL} + }; + + srna = RNA_def_struct(brna, "MaterialEngineSettingsClay", "MaterialEngineSettings"); + RNA_def_struct_ui_text(srna, "Material Clay Settings", "Clay Engine settings for a Material data-block"); + RNA_def_struct_sdna_from(srna, "MaterialEngineSettingsClay", "data"); + + prop = RNA_def_property(srna, "type", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_items(prop, clay_matcap_type); + RNA_def_property_ui_text(prop, "Settings Type", "What settings to use for this material"); + RNA_def_property_update(prop, 0, "rna_Material_update_engine_data"); + + prop = RNA_def_property(srna, "matcap_icon", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_items(prop, clay_matcap_items); + RNA_def_property_ui_text(prop, "Matcap", "Image to use for Material Capture by this material"); + RNA_def_property_update(prop, 0, "rna_Material_update_engine_data"); + + prop = RNA_def_property(srna, "matcap_rotation", PROP_FLOAT, PROP_FACTOR); + RNA_def_property_float_sdna(prop, NULL, "matcap_rot"); + RNA_def_property_range(prop, 0.0f, 1.0f); + RNA_def_property_ui_text(prop, "Matcap Rotation", "Orientation of the matcap on the model"); + RNA_def_property_update(prop, 0, "rna_Material_update_engine_data"); + + prop = RNA_def_property(srna, "matcap_hue", PROP_FLOAT, PROP_FACTOR); + RNA_def_property_range(prop, 0.0f, 1.0f); + RNA_def_property_ui_text(prop, "Matcap Hue shift", "Hue correction of the matcap"); + RNA_def_property_update(prop, 0, "rna_Material_update_engine_data"); + + prop = RNA_def_property(srna, "matcap_saturation", PROP_FLOAT, PROP_FACTOR); + RNA_def_property_float_sdna(prop, NULL, "matcap_sat"); + RNA_def_property_range(prop, 0.0f, 1.0f); + RNA_def_property_ui_text(prop, "Matcap Saturation", "Saturation correction of the matcap"); + RNA_def_property_update(prop, 0, "rna_Material_update_engine_data"); + + prop = RNA_def_property(srna, "matcap_value", PROP_FLOAT, PROP_FACTOR); + RNA_def_property_float_sdna(prop, NULL, "matcap_val"); + RNA_def_property_range(prop, 0.0f, 1.0f); + RNA_def_property_ui_text(prop, "Matcap Value", "Value correction of the matcap"); + RNA_def_property_update(prop, 0, "rna_Material_update_engine_data"); + + prop = RNA_def_property(srna, "ssao_factor_cavity", PROP_FLOAT, PROP_NONE); + RNA_def_property_ui_text(prop, "Cavity Strength", "Strength of the Cavity effect"); + RNA_def_property_range(prop, 0.0f, 250.0f); + RNA_def_property_update(prop, 0, "rna_Material_update_engine_data"); + + prop = RNA_def_property(srna, "ssao_factor_edge", PROP_FLOAT, PROP_NONE); + RNA_def_property_ui_text(prop, "Edge Strength", "Strength of the Edge effect"); + RNA_def_property_range(prop, 0.0f, 250.0f); + RNA_def_property_update(prop, 0, "rna_Material_update_engine_data"); + + prop = RNA_def_property(srna, "ssao_distance", PROP_FLOAT, PROP_NONE); + RNA_def_property_ui_text(prop, "Distance", "Distance of object that contribute to the Cavity/Edge effect"); + RNA_def_property_range(prop, 0.0f, 100000.0f); + RNA_def_property_ui_range(prop, 0.0f, 100.0f, 1, 3); + RNA_def_property_update(prop, 0, "rna_Material_update_engine_data"); + + prop = RNA_def_property(srna, "ssao_attenuation", PROP_FLOAT, PROP_NONE); + RNA_def_property_ui_text(prop, "Attenuation", "Attenuation constant"); + RNA_def_property_range(prop, 1.0f, 100000.0f); + RNA_def_property_ui_range(prop, 1.0f, 100.0f, 1, 3); + RNA_def_property_update(prop, 0, "rna_Material_update_engine_data"); +} + +static void rna_def_material_engine_settings(BlenderRNA *brna) +{ + StructRNA *srna; + + srna = RNA_def_struct(brna, "MaterialEngineSettings", NULL); + RNA_def_struct_ui_text(srna, "Engine Settings", "Engine specific settings"); + RNA_def_struct_sdna(srna, "MaterialEngineSettings"); + RNA_def_struct_refine_func(srna, "rna_MaterialEngineSettings_refine"); + + rna_def_material_settings_clay(brna); +} + static void rna_def_material_gamesettings(BlenderRNA *brna) { StructRNA *srna; @@ -2087,6 +2224,11 @@ void RNA_def_material(BlenderRNA *brna) RNA_def_property_struct_type(prop, "MaterialGameSettings"); RNA_def_property_ui_text(prop, "Game Settings", "Game material settings"); + /* Engine settings */ + prop = RNA_def_property(srna, "engines_settings", PROP_COLLECTION, PROP_NONE); + RNA_def_property_struct_type(prop, "MaterialEngineSettings"); + RNA_def_property_ui_text(prop, "Material Engine Settings", "Engine specific settings"); + /* nodetree */ prop = RNA_def_property(srna, "node_tree", PROP_POINTER, PROP_NONE); RNA_def_property_pointer_sdna(prop, NULL, "nodetree"); @@ -2136,6 +2278,7 @@ void RNA_def_material(BlenderRNA *brna) rna_def_material_strand(brna); rna_def_material_physics(brna); rna_def_material_gamesettings(brna); + rna_def_material_engine_settings(brna); RNA_api_material(srna); } diff --git a/source/blender/makesrna/intern/rna_render.c b/source/blender/makesrna/intern/rna_render.c index 518c7efd915..5f796261c73 100644 --- a/source/blender/makesrna/intern/rna_render.c +++ b/source/blender/makesrna/intern/rna_render.c @@ -261,6 +261,24 @@ static void engine_update_script_node(RenderEngine *engine, struct bNodeTree *nt RNA_parameter_list_free(&list); } +static void engine_collection_settings_create(RenderEngine *engine, struct CollectionEngineSettings *ces) +{ + extern FunctionRNA rna_RenderEngine_collection_settings_create_func; + PointerRNA ptr,cesptr; + ParameterList list; + FunctionRNA *func; + + RNA_pointer_create(NULL, engine->type->ext.srna, engine, &ptr); + RNA_pointer_create(NULL, &RNA_CollectionEngineSettings, ces, &cesptr); + func = &rna_RenderEngine_collection_settings_create_func; + + RNA_parameter_list_create(&list, &ptr, func); + RNA_parameter_set_lookup(&list, "collection_settings", &cesptr); + engine->type->ext.call(NULL, &ptr, func, &list); + + RNA_parameter_list_free(&list); +} + /* RenderEngine registration */ static void rna_RenderEngine_unregister(Main *UNUSED(bmain), StructRNA *type) @@ -281,7 +299,7 @@ static StructRNA *rna_RenderEngine_register(Main *bmain, ReportList *reports, vo RenderEngineType *et, dummyet = {NULL}; RenderEngine dummyengine = {NULL}; PointerRNA dummyptr; - int have_function[6]; + int have_function[7]; /* setup dummy engine & engine type to store static properties in */ dummyengine.type = &dummyet; @@ -323,8 +341,9 @@ static StructRNA *rna_RenderEngine_register(Main *bmain, ReportList *reports, vo et->view_update = (have_function[3]) ? engine_view_update : NULL; et->view_draw = (have_function[4]) ? engine_view_draw : NULL; et->update_script_node = (have_function[5]) ? engine_update_script_node : NULL; + et->collection_settings_create = (have_function[6]) ? engine_collection_settings_create : NULL; - BLI_addtail(&R_engines, et); + RE_engines_register(bmain, et); return et->ext.srna; } @@ -489,6 +508,13 @@ static void rna_def_render_engine(BlenderRNA *brna) parm = RNA_def_pointer(func, "node", "Node", "", ""); RNA_def_parameter_flags(parm, 0, PARM_RNAPTR); + /* per-collection engine settings initialization */ + func = RNA_def_function(srna, "collection_settings_create", NULL); + RNA_def_function_ui_description(func, "Create the per collection settings for the engine"); + RNA_def_function_flag(func, FUNC_REGISTER_OPTIONAL | FUNC_ALLOW_WRITE); + parm = RNA_def_pointer(func, "collection_settings", "CollectionEngineSettings", "", ""); + RNA_def_parameter_flags(parm, 0, PARM_RNAPTR); + /* tag for redraw */ func = RNA_def_function(srna, "tag_redraw", "engine_tag_redraw"); RNA_def_function_ui_description(func, "Request redraw for viewport rendering"); diff --git a/source/blender/makesrna/intern/rna_scene.c b/source/blender/makesrna/intern/rna_scene.c index 8f36af96cf4..ec9a08af287 100644 --- a/source/blender/makesrna/intern/rna_scene.c +++ b/source/blender/makesrna/intern/rna_scene.c @@ -52,6 +52,8 @@ #include "GPU_extensions.h" +#include "DRW_engine.h" + #include "RNA_define.h" #include "RNA_enum_types.h" @@ -80,6 +82,8 @@ #include "BLI_threads.h" +#define NO_ENGINE "NO_ENGINE" + #ifdef WITH_OPENEXR EnumPropertyItem rna_enum_exr_codec_items[] = { {R_IMF_EXR_CODEC_NONE, "NONE", 0, "None", ""}, @@ -1872,6 +1876,43 @@ static void rna_GameSettings_exit_key_set(PointerRNA *ptr, int value) gm->exitkey = value; } +static StructRNA *rna_RenderEngineSettings_refine(PointerRNA *ptr) +{ +#ifdef WITH_CLAY_ENGINE + RenderEngineSettings *res = (RenderEngineSettings *)ptr->data; + + if (STREQ(res->name, RE_engine_id_BLENDER_CLAY)) { + return &RNA_RenderEngineSettingsClay; + } +#endif + return &RNA_RenderEngineSettings; +} + +static PointerRNA rna_RenderEngineSettings_active_get(PointerRNA *ptr) +{ + Scene *scene = (Scene *)ptr->data; + RenderEngineSettings *res; + + /* Ensure settings exists */ + DRW_render_settings_get(scene, scene->r.engine); + + res = BLI_findstring(&scene->engines_settings, scene->r.engine, offsetof(RenderEngineSettings, name)); + + return rna_pointer_inherit_refine(ptr, &RNA_RenderEngineSettings, res); +} + +static void rna_RenderEngineSettings_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr) +{ + Scene *sce = (Scene *)ptr->id.data; + MaterialEngineSettingsClay *res; + + res = (MaterialEngineSettingsClay *)DRW_render_settings_get(sce, sce->r.engine); + + res->flag = CLAY_OUTDATED; + + WM_main_add_notifier(NC_SPACE | ND_SPACE_VIEW3D, NULL); +} + static TimeMarker *rna_TimeLine_add(Scene *scene, const char name[], int frame) { TimeMarker *marker = MEM_callocN(sizeof(TimeMarker), "TimeMarker"); @@ -2311,6 +2352,83 @@ static void rna_SceneCollection_object_unlink( WM_main_add_notifier(NC_SCENE | ND_LAYER | ND_OB_ACTIVE, scene); } +/****** layer collection engine settings *******/ + +static StructRNA *rna_CollectionEngineSettings_refine(struct PointerRNA *ptr) +{ + CollectionEngineSettings *ces = (CollectionEngineSettings *)ptr->data; + + if (STREQ(ces->name, "BLENDER_CLAY")) { + return &RNA_CollectionEngineSettingsClay; + } + + /* TODO - handle other engines */ + TODO_LAYER; + (void) ces; + + return &RNA_CollectionEngineSettings; +} + +/****** clay engine settings *******/ + +#define RNA_LAYER_ENGINE_USE_GET_SET(_NAME_) \ + static int rna_LayerEngineSettings_##_NAME_##_use_get(PointerRNA *ptr) \ + { \ + CollectionEngineSettings *ces = (CollectionEngineSettings *)ptr->data; \ + return BKE_collection_engine_property_use_get(ces, #_NAME_) ? 1 : 0; \ + } \ + \ + static void rna_LayerEngineSettings_##_NAME_##_use_set(PointerRNA *ptr, int value) \ + { \ + CollectionEngineSettings *ces = (CollectionEngineSettings *)ptr->data; \ + BKE_collection_engine_property_use_set(ces, #_NAME_, value? true : false); \ + } + +#define RNA_LAYER_ENGINE_GET_SET(_TYPE_, _NAME_) \ +static _TYPE_ rna_LayerEngineSettings_##_NAME_##_get(PointerRNA *ptr) \ +{ \ + CollectionEngineSettings *ces = (CollectionEngineSettings *)ptr->data; \ + return BKE_collection_engine_property_value_get_##_TYPE_(ces, #_NAME_); \ +} \ + \ +static void rna_LayerEngineSettings_##_NAME_##_set(PointerRNA *ptr, _TYPE_ value) \ +{ \ + CollectionEngineSettings *ces = (CollectionEngineSettings *)ptr->data; \ + BKE_collection_engine_property_value_set_##_TYPE_(ces, #_NAME_, value); \ +} \ + RNA_LAYER_ENGINE_USE_GET_SET(_NAME_) + +#define RNA_LAYER_ENGINE_GET_SET_FLOAT(_NAME_) \ + RNA_LAYER_ENGINE_GET_SET(float, _NAME_) + +#define RNA_LAYER_ENGINE_GET_SET_INT(_NAME_) \ + RNA_LAYER_ENGINE_GET_SET(int, _NAME_) + + +RNA_LAYER_ENGINE_GET_SET_INT(type) +RNA_LAYER_ENGINE_GET_SET_INT(matcap_icon) +RNA_LAYER_ENGINE_GET_SET_FLOAT(matcap_rotation) +RNA_LAYER_ENGINE_GET_SET_FLOAT(matcap_hue) +RNA_LAYER_ENGINE_GET_SET_FLOAT(matcap_saturation) +RNA_LAYER_ENGINE_GET_SET_FLOAT(matcap_value) +RNA_LAYER_ENGINE_GET_SET_FLOAT(ssao_factor_cavity) +RNA_LAYER_ENGINE_GET_SET_FLOAT(ssao_factor_edge) +RNA_LAYER_ENGINE_GET_SET_FLOAT(ssao_distance) +RNA_LAYER_ENGINE_GET_SET_FLOAT(ssao_attenuation) + +#undef RNA_LAYER_ENGINE_GET_SET_INT +#undef RNA_LAYER_ENGINE_GET_SET_FLOAT +#undef RNA_LAYER_ENGINE_GET_SET +#undef RNA_LAYER_ENGINE_USE_GET_SET + +static void rna_CollectionEngineSettings_update(bContext *C, PointerRNA *UNUSED(ptr)) +{ + SceneLayer *sl = CTX_data_scene_layer(C); + BKE_scene_layer_engine_settings_recalculate(sl); +} + +/***********************************/ + static void rna_LayerCollection_name_get(PointerRNA *ptr, char *value) { SceneCollection *sc = ((LayerCollection *)ptr->data)->scene_collection; @@ -2340,6 +2458,25 @@ static PointerRNA rna_LayerCollection_objects_get(CollectionPropertyIterator *it return rna_pointer_inherit_refine(&iter->parent, &RNA_Object, base->object); } +static PointerRNA rna_LayerCollection_engine_settings_get(ID *UNUSED(id), LayerCollection *lc, bContext *C, const char *engine) +{ + Scene *scene = CTX_data_scene(C); + const char *engine_name; + + if (STREQ(engine, NO_ENGINE)) { + RenderData *rd = &scene->r; + engine_name = rd->engine; + } + else { + engine_name = engine; + } + + PointerRNA ptr; + CollectionEngineSettings *ces = BKE_layer_collection_engine_get(lc, engine_name); + RNA_pointer_create(NULL, &RNA_CollectionEngineSettings, ces, &ptr); + return rna_pointer_inherit_refine(&ptr, &RNA_CollectionEngineSettings, ces); +} + static void rna_LayerCollection_hide_update(bContext *C, PointerRNA *ptr) { Scene *scene = CTX_data_scene(C); @@ -5602,11 +5739,176 @@ static void rna_def_layer_collection_override(BlenderRNA *brna) RNA_def_property_update(prop, NC_SCENE | ND_LAYER_CONTENT, NULL); } +#define RNA_LAYER_ENGINE_USE(_NAME_) \ + prop = RNA_def_property(srna, #_NAME_"_use", PROP_BOOLEAN, PROP_NONE); \ + RNA_def_property_boolean_funcs(prop, \ + "rna_LayerEngineSettings_"#_NAME_"_use_get", \ + "rna_LayerEngineSettings_"#_NAME_"_use_set"); \ + RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE); \ + RNA_def_property_update(prop, NC_SCENE | ND_LAYER_CONTENT, "rna_CollectionEngineSettings_update"); + +static void rna_def_layer_collection_engine_settings_clay(BlenderRNA *brna) +{ + StructRNA *srna; + PropertyRNA *prop; + + static EnumPropertyItem clay_matcap_items[] = { + {ICON_MATCAP_01, "01", ICON_MATCAP_01, "", ""}, + {ICON_MATCAP_02, "02", ICON_MATCAP_02, "", ""}, + {ICON_MATCAP_03, "03", ICON_MATCAP_03, "", ""}, + {ICON_MATCAP_04, "04", ICON_MATCAP_04, "", ""}, + {ICON_MATCAP_05, "05", ICON_MATCAP_05, "", ""}, + {ICON_MATCAP_06, "06", ICON_MATCAP_06, "", ""}, + {ICON_MATCAP_07, "07", ICON_MATCAP_07, "", ""}, + {ICON_MATCAP_08, "08", ICON_MATCAP_08, "", ""}, + {ICON_MATCAP_09, "09", ICON_MATCAP_09, "", ""}, + {ICON_MATCAP_10, "10", ICON_MATCAP_10, "", ""}, + {ICON_MATCAP_11, "11", ICON_MATCAP_11, "", ""}, + {ICON_MATCAP_12, "12", ICON_MATCAP_12, "", ""}, + {ICON_MATCAP_13, "13", ICON_MATCAP_13, "", ""}, + {ICON_MATCAP_14, "14", ICON_MATCAP_14, "", ""}, + {ICON_MATCAP_15, "15", ICON_MATCAP_15, "", ""}, + {ICON_MATCAP_16, "16", ICON_MATCAP_16, "", ""}, + {ICON_MATCAP_17, "17", ICON_MATCAP_17, "", ""}, + {ICON_MATCAP_18, "18", ICON_MATCAP_18, "", ""}, + {ICON_MATCAP_19, "19", ICON_MATCAP_19, "", ""}, + {ICON_MATCAP_20, "20", ICON_MATCAP_20, "", ""}, + {ICON_MATCAP_21, "21", ICON_MATCAP_21, "", ""}, + {ICON_MATCAP_22, "22", ICON_MATCAP_22, "", ""}, + {ICON_MATCAP_23, "23", ICON_MATCAP_23, "", ""}, + {ICON_MATCAP_24, "24", ICON_MATCAP_24, "", ""}, + {0, NULL, 0, NULL, NULL} + }; + + static EnumPropertyItem clay_matcap_type[] = { + {CLAY_MATCAP_NONE, "NONE", 0, "Scene", "Use default scene matcap"}, + {CLAY_MATCAP_SIMPLE, "SIMPLE", 0, "Simple", "Let you choose the texture to use with the default settings"}, + {CLAY_MATCAP_COMPLETE, "COMPLETE", 0, "Complete", "Expose all settings"}, + {0, NULL, 0, NULL, NULL} + }; + + srna = RNA_def_struct(brna, "CollectionEngineSettingsClay", NULL); + RNA_def_struct_sdna(srna, "CollectionEngineSettings"); + RNA_def_struct_ui_text(srna, "Collections Clay Engine Settings", "Engine specific settings for this collection"); + + prop = RNA_def_property(srna, "name", PROP_STRING, PROP_NONE); + RNA_def_property_ui_text(prop, "Name", "Engine name"); + RNA_def_property_clear_flag(prop, PROP_EDITABLE); + RNA_def_struct_name_property(srna, prop); + + /* see RNA_LAYER_ENGINE_GET_SET macro */ + + prop = RNA_def_property(srna, "type", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_funcs(prop, "rna_LayerEngineSettings_type_get", "rna_LayerEngineSettings_type_set", NULL); + RNA_def_property_enum_items(prop, clay_matcap_type); + RNA_def_property_ui_text(prop, "Settings Type", "What settings to use for this material"); + RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE); + RNA_def_property_update(prop, NC_SCENE | ND_LAYER_CONTENT, "rna_CollectionEngineSettings_update"); + RNA_LAYER_ENGINE_USE(type) + + prop = RNA_def_property(srna, "matcap_icon", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_funcs(prop, "rna_LayerEngineSettings_matcap_icon_get", "rna_LayerEngineSettings_matcap_icon_set", NULL); + RNA_def_property_enum_items(prop, clay_matcap_items); + RNA_def_property_ui_text(prop, "Matcap", "Image to use for Material Capture by this material"); + RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE); + RNA_def_property_update(prop, NC_SCENE | ND_LAYER_CONTENT, "rna_CollectionEngineSettings_update"); + RNA_LAYER_ENGINE_USE(matcap_icon) + + prop = RNA_def_property(srna, "matcap_rotation", PROP_FLOAT, PROP_FACTOR); + RNA_def_property_float_funcs(prop, "rna_LayerEngineSettings_matcap_rotation_get", "rna_LayerEngineSettings_matcap_rotation_set", NULL); + RNA_def_property_range(prop, 0.0f, 1.0f); + RNA_def_property_ui_text(prop, "Matcap Rotation", "Orientation of the matcap on the model"); + RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE); + RNA_def_property_update(prop, NC_SCENE | ND_LAYER_CONTENT, "rna_CollectionEngineSettings_update"); + RNA_LAYER_ENGINE_USE(matcap_rotation) + + prop = RNA_def_property(srna, "matcap_hue", PROP_FLOAT, PROP_FACTOR); + RNA_def_property_float_funcs(prop, "rna_LayerEngineSettings_matcap_hue_get", "rna_LayerEngineSettings_matcap_hue_set", NULL); + RNA_def_property_range(prop, 0.0f, 1.0f); + RNA_def_property_ui_text(prop, "Matcap Hue shift", "Hue correction of the matcap"); + RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE); + RNA_def_property_update(prop, NC_SCENE | ND_LAYER_CONTENT, "rna_CollectionEngineSettings_update"); + RNA_LAYER_ENGINE_USE(matcap_hue) + + prop = RNA_def_property(srna, "matcap_saturation", PROP_FLOAT, PROP_FACTOR); + RNA_def_property_float_funcs(prop, "rna_LayerEngineSettings_matcap_saturation_get", "rna_LayerEngineSettings_matcap_saturation_set", NULL); + RNA_def_property_range(prop, 0.0f, 1.0f); + RNA_def_property_ui_text(prop, "Matcap Saturation", "Saturation correction of the matcap"); + RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE); + RNA_def_property_update(prop, NC_SCENE | ND_LAYER_CONTENT, "rna_CollectionEngineSettings_update"); + RNA_LAYER_ENGINE_USE(matcap_saturation) + + prop = RNA_def_property(srna, "matcap_value", PROP_FLOAT, PROP_FACTOR); + RNA_def_property_float_funcs(prop, "rna_LayerEngineSettings_matcap_value_get", "rna_LayerEngineSettings_matcap_value_set", NULL); + RNA_def_property_range(prop, 0.0f, 1.0f); + RNA_def_property_ui_text(prop, "Matcap Value", "Value correction of the matcap"); + RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE); + RNA_def_property_update(prop, NC_SCENE | ND_LAYER_CONTENT, "rna_CollectionEngineSettings_update"); + RNA_LAYER_ENGINE_USE(matcap_value) + + prop = RNA_def_property(srna, "ssao_factor_cavity", PROP_FLOAT, PROP_NONE); + RNA_def_property_float_funcs(prop, "rna_LayerEngineSettings_ssao_factor_cavity_get", "rna_LayerEngineSettings_ssao_factor_cavity_set", NULL); + RNA_def_property_ui_text(prop, "Cavity Strength", "Strength of the Cavity effect"); + RNA_def_property_range(prop, 0.0f, 250.0f); + RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE); + RNA_def_property_update(prop, NC_SCENE | ND_LAYER_CONTENT, "rna_CollectionEngineSettings_update"); + RNA_LAYER_ENGINE_USE(ssao_factor_cavity) + + prop = RNA_def_property(srna, "ssao_factor_edge", PROP_FLOAT, PROP_NONE); + RNA_def_property_float_funcs(prop, "rna_LayerEngineSettings_ssao_factor_edge_get", "rna_LayerEngineSettings_ssao_factor_edge_set", NULL); + RNA_def_property_ui_text(prop, "Edge Strength", "Strength of the Edge effect"); + RNA_def_property_range(prop, 0.0f, 250.0f); + RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE); + RNA_def_property_update(prop, NC_SCENE | ND_LAYER_CONTENT, "rna_CollectionEngineSettings_update"); + RNA_LAYER_ENGINE_USE(ssao_factor_edge) + + prop = RNA_def_property(srna, "ssao_distance", PROP_FLOAT, PROP_NONE); + RNA_def_property_float_funcs(prop, "rna_LayerEngineSettings_ssao_distance_get", "rna_LayerEngineSettings_ssao_distance_set", NULL); + RNA_def_property_ui_text(prop, "Distance", "Distance of object that contribute to the Cavity/Edge effect"); + RNA_def_property_range(prop, 0.0f, 100000.0f); + RNA_def_property_ui_range(prop, 0.0f, 100.0f, 1, 3); + RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE); + RNA_def_property_update(prop, NC_SCENE | ND_LAYER_CONTENT, "rna_CollectionEngineSettings_update"); + RNA_LAYER_ENGINE_USE(ssao_distance) + + prop = RNA_def_property(srna, "ssao_attenuation", PROP_FLOAT, PROP_NONE); + RNA_def_property_float_funcs(prop, "rna_LayerEngineSettings_ssao_attenuation_get", "rna_LayerEngineSettings_ssao_attenuation_set", NULL); + RNA_def_property_ui_text(prop, "Attenuation", "Attenuation constant"); + RNA_def_property_range(prop, 1.0f, 100000.0f); + RNA_def_property_ui_range(prop, 1.0f, 100.0f, 1, 3); + RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE); + RNA_def_property_update(prop, NC_SCENE | ND_LAYER_CONTENT, "rna_CollectionEngineSettings_update"); + RNA_LAYER_ENGINE_USE(ssao_attenuation) +} + +static void rna_def_layer_collection_engine_settings(BlenderRNA *brna) +{ + StructRNA *srna; + PropertyRNA *prop; + + srna = RNA_def_struct(brna, "CollectionEngineSettings", NULL); + RNA_def_struct_ui_text(srna, "Collections Engine Settings", "Engine specific settings for this collection"); + RNA_def_struct_refine_func(srna, "rna_CollectionEngineSettings_refine"); + + prop = RNA_def_property(srna, "name", PROP_STRING, PROP_NONE); + RNA_def_property_ui_text(prop, "Name", "Engine name"); + RNA_def_property_clear_flag(prop, PROP_EDITABLE); + RNA_def_struct_name_property(srna, prop); + + /* the engine specific structs */ + rna_def_layer_collection_engine_settings_clay(brna); +} + +#undef RNA_LAYER_ENGINE_USE + static void rna_def_layer_collection(BlenderRNA *brna) { StructRNA *srna; PropertyRNA *prop; + FunctionRNA *func; + PropertyRNA *parm; + srna = RNA_def_struct(brna, "LayerCollection", NULL); RNA_def_struct_ui_text(srna, "Layer Collection", "Layer collection"); @@ -5638,6 +5940,15 @@ static void rna_def_layer_collection(BlenderRNA *brna) RNA_def_property_struct_type(prop, "LayerCollectionOverride"); RNA_def_property_ui_text(prop, "Collection Overrides", ""); + func = RNA_def_function(srna, "get_engine_settings", "rna_LayerCollection_engine_settings_get"); + RNA_def_function_ui_description(func, "Return the engine settings for this collection"); + RNA_def_function_flag(func, FUNC_USE_SELF_ID | FUNC_USE_CONTEXT); + parm = RNA_def_string(func, "engine", NO_ENGINE, MAX_NAME, "Engine", "use context one by default"); + RNA_def_parameter_clear_flags(parm, 0, PARM_REQUIRED); + parm = RNA_def_pointer(func, "result", "CollectionEngineSettings", "", ""); + RNA_def_parameter_flags(parm, 0, PARM_RNAPTR); + RNA_def_function_return(func, parm); + /* Flags */ prop = RNA_def_property(srna, "hide", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", COLLECTION_VISIBLE); @@ -6580,6 +6891,115 @@ static void rna_def_scene_quicktime_settings(BlenderRNA *brna) } #endif +#ifdef WITH_CLAY_ENGINE +static void rna_def_render_engine_settings_clay(BlenderRNA *brna) +{ + StructRNA *srna; + PropertyRNA *prop; + static EnumPropertyItem clay_matcap_items[] = { + {ICON_MATCAP_01, "01", ICON_MATCAP_01, "", ""}, + {ICON_MATCAP_02, "02", ICON_MATCAP_02, "", ""}, + {ICON_MATCAP_03, "03", ICON_MATCAP_03, "", ""}, + {ICON_MATCAP_04, "04", ICON_MATCAP_04, "", ""}, + {ICON_MATCAP_05, "05", ICON_MATCAP_05, "", ""}, + {ICON_MATCAP_06, "06", ICON_MATCAP_06, "", ""}, + {ICON_MATCAP_07, "07", ICON_MATCAP_07, "", ""}, + {ICON_MATCAP_08, "08", ICON_MATCAP_08, "", ""}, + {ICON_MATCAP_09, "09", ICON_MATCAP_09, "", ""}, + {ICON_MATCAP_10, "10", ICON_MATCAP_10, "", ""}, + {ICON_MATCAP_11, "11", ICON_MATCAP_11, "", ""}, + {ICON_MATCAP_12, "12", ICON_MATCAP_12, "", ""}, + {ICON_MATCAP_13, "13", ICON_MATCAP_13, "", ""}, + {ICON_MATCAP_14, "14", ICON_MATCAP_14, "", ""}, + {ICON_MATCAP_15, "15", ICON_MATCAP_15, "", ""}, + {ICON_MATCAP_16, "16", ICON_MATCAP_16, "", ""}, + {ICON_MATCAP_17, "17", ICON_MATCAP_17, "", ""}, + {ICON_MATCAP_18, "18", ICON_MATCAP_18, "", ""}, + {ICON_MATCAP_19, "19", ICON_MATCAP_19, "", ""}, + {ICON_MATCAP_20, "20", ICON_MATCAP_20, "", ""}, + {ICON_MATCAP_21, "21", ICON_MATCAP_21, "", ""}, + {ICON_MATCAP_22, "22", ICON_MATCAP_22, "", ""}, + {ICON_MATCAP_23, "23", ICON_MATCAP_23, "", ""}, + {ICON_MATCAP_24, "24", ICON_MATCAP_24, "", ""}, + {0, NULL, 0, NULL, NULL} + }; + + srna = RNA_def_struct(brna, "RenderEngineSettingsClay", "RenderEngineSettings"); + RNA_def_struct_ui_text(srna, "Material Clay Settings", "Clay Engine settings for a Material data-block"); + RNA_def_struct_sdna_from(srna, "RenderEngineSettingsClay", "data"); + + prop = RNA_def_property(srna, "matcap_icon", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_items(prop, clay_matcap_items); + RNA_def_property_ui_text(prop, "Matcap", "Image to use for Material Capture by this material"); + RNA_def_property_update(prop, 0, "rna_RenderEngineSettings_update"); + + prop = RNA_def_property(srna, "matcap_rotation", PROP_FLOAT, PROP_FACTOR); + RNA_def_property_float_sdna(prop, NULL, "matcap_rot"); + RNA_def_property_range(prop, 0.0f, 1.0f); + RNA_def_property_ui_text(prop, "Matcap Rotation", "Orientation of the matcap on the model"); + RNA_def_property_update(prop, 0, "rna_RenderEngineSettings_update"); + + prop = RNA_def_property(srna, "matcap_hue", PROP_FLOAT, PROP_FACTOR); + RNA_def_property_range(prop, 0.0f, 1.0f); + RNA_def_property_ui_text(prop, "Matcap Hue shift", "Hue correction of the matcap"); + RNA_def_property_update(prop, 0, "rna_RenderEngineSettings_update"); + + prop = RNA_def_property(srna, "matcap_saturation", PROP_FLOAT, PROP_FACTOR); + RNA_def_property_float_sdna(prop, NULL, "matcap_sat"); + RNA_def_property_range(prop, 0.0f, 1.0f); + RNA_def_property_ui_text(prop, "Matcap Saturation", "Saturation correction of the matcap"); + RNA_def_property_update(prop, 0, "rna_RenderEngineSettings_update"); + + prop = RNA_def_property(srna, "matcap_value", PROP_FLOAT, PROP_FACTOR); + RNA_def_property_float_sdna(prop, NULL, "matcap_val"); + RNA_def_property_range(prop, 0.0f, 1.0f); + RNA_def_property_ui_text(prop, "Matcap Value", "Value correction of the matcap"); + RNA_def_property_update(prop, 0, "rna_RenderEngineSettings_update"); + + prop = RNA_def_property(srna, "ssao_factor_cavity", PROP_FLOAT, PROP_NONE); + RNA_def_property_ui_text(prop, "Cavity Strength", "Strength of the Cavity effect"); + RNA_def_property_range(prop, 0.0f, 250.0f); + RNA_def_property_update(prop, 0, "rna_RenderEngineSettings_update"); + + prop = RNA_def_property(srna, "ssao_factor_edge", PROP_FLOAT, PROP_NONE); + RNA_def_property_ui_text(prop, "Edge Strength", "Strength of the Edge effect"); + RNA_def_property_range(prop, 0.0f, 250.0f); + RNA_def_property_update(prop, 0, "rna_RenderEngineSettings_update"); + + prop = RNA_def_property(srna, "ssao_distance", PROP_FLOAT, PROP_NONE); + RNA_def_property_ui_text(prop, "Distance", "Distance of object that contribute to the Cavity/Edge effect"); + RNA_def_property_range(prop, 0.0f, 100000.0f); + RNA_def_property_ui_range(prop, 0.0f, 100.0f, 1, 3); + RNA_def_property_update(prop, 0, "rna_RenderEngineSettings_update"); + + prop = RNA_def_property(srna, "ssao_attenuation", PROP_FLOAT, PROP_NONE); + RNA_def_property_ui_text(prop, "Attenuation", "Attenuation constant"); + RNA_def_property_range(prop, 1.0f, 100000.0f); + RNA_def_property_ui_range(prop, 1.0f, 100.0f, 1, 3); + RNA_def_property_update(prop, 0, "rna_RenderEngineSettings_update"); + + /* Clay settings */ + prop = RNA_def_property(srna, "ssao_samples", PROP_INT, PROP_NONE); + RNA_def_property_ui_text(prop, "Samples", "Number of samples"); + RNA_def_property_range(prop, 1, 500); + RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL); +} +#endif + +static void rna_def_scene_render_engine(BlenderRNA *brna) +{ + StructRNA *srna; + + srna = RNA_def_struct(brna, "RenderEngineSettings", NULL); + RNA_def_struct_ui_text(srna, "Render Engine Settings", "Engine specific render settings"); + RNA_def_struct_sdna(srna, "RenderEngineSettings"); + RNA_def_struct_refine_func(srna, "rna_RenderEngineSettings_refine"); + +#ifdef WITH_CLAY_ENGINE + rna_def_render_engine_settings_clay(brna); +#endif +} + static void rna_def_scene_render_data(BlenderRNA *brna) { StructRNA *srna; @@ -8075,7 +8495,17 @@ void RNA_def_scene(BlenderRNA *brna) RNA_def_property_pointer_sdna(prop, NULL, "r"); RNA_def_property_struct_type(prop, "RenderSettings"); RNA_def_property_ui_text(prop, "Render Data", ""); - + + /* Render Engine Data */ + prop = RNA_def_property(srna, "engines_settings", PROP_COLLECTION, PROP_NONE); + RNA_def_property_struct_type(prop, "RenderEngineSettings"); + RNA_def_property_ui_text(prop, "Render Engine Settings", "Engine specific render settings"); + + prop = RNA_def_property(srna, "active_engine_settings", PROP_POINTER, PROP_NONE); + RNA_def_property_struct_type(prop, "RenderEngineSettings"); + RNA_def_property_pointer_funcs(prop, "rna_RenderEngineSettings_active_get", NULL, NULL, NULL); + RNA_def_property_ui_text(prop, "Active Render Engine Settings", "Active Engine specific render settings for this scene"); + /* Safe Areas */ prop = RNA_def_property(srna, "safe_areas", PROP_POINTER, PROP_NONE); RNA_def_property_pointer_sdna(prop, NULL, "safe_areas"); @@ -8222,11 +8652,13 @@ void RNA_def_scene(BlenderRNA *brna) rna_def_scene_collection(brna); rna_def_layer_collection(brna); rna_def_layer_collection_override(brna); + rna_def_layer_collection_engine_settings(brna); rna_def_scene_layer(brna); rna_def_object_base(brna); RNA_define_animate_sdna(true); /* *** Animated *** */ rna_def_scene_render_data(brna); + rna_def_scene_render_engine(brna); rna_def_scene_render_layer(brna); rna_def_gpu_fx(brna); rna_def_scene_render_view(brna); @@ -8236,3 +8668,5 @@ void RNA_def_scene(BlenderRNA *brna) } #endif + +#undef NO_ENGINE diff --git a/source/blender/render/CMakeLists.txt b/source/blender/render/CMakeLists.txt index 9e40ab02ee4..27fa119bc88 100644 --- a/source/blender/render/CMakeLists.txt +++ b/source/blender/render/CMakeLists.txt @@ -35,6 +35,7 @@ set(INC ../makesdna ../makesrna ../physics + ../draw ../../../intern/guardedalloc ../../../intern/mikktspace ../../../intern/smoke/extern diff --git a/source/blender/render/extern/include/RE_engine.h b/source/blender/render/extern/include/RE_engine.h index f83a210275f..f1b3534b40a 100644 --- a/source/blender/render/extern/include/RE_engine.h +++ b/source/blender/render/extern/include/RE_engine.h @@ -39,6 +39,8 @@ struct bNode; struct bNodeTree; +struct CollectionEngineSettings; +struct Main; struct Object; struct Render; struct RenderData; @@ -63,6 +65,7 @@ struct BakePixel; #define RE_USE_TEXTURE_PREVIEW 128 #define RE_USE_SHADING_NODES_CUSTOM 256 #define RE_USE_SPHERICAL_STEREO 512 +#define RE_USE_OGL_PIPELINE 1024 /* RenderEngine.flag */ #define RE_ENGINE_ANIMATION 1 @@ -97,6 +100,8 @@ typedef struct RenderEngineType { void (*update_script_node)(struct RenderEngine *engine, struct bNodeTree *ntree, struct bNode *node); + void (*collection_settings_create)(struct RenderEngine *engine, struct CollectionEngineSettings *ces); + /* RNA integration */ ExtensionRNA ext; } RenderEngineType; @@ -164,6 +169,7 @@ void RE_engine_frame_set(struct RenderEngine *engine, int frame, float subframe) void RE_engines_init(void); void RE_engines_exit(void); +void RE_engines_register(struct Main *bmain, RenderEngineType *render_type); RenderEngineType *RE_engines_find(const char *idname); diff --git a/source/blender/render/intern/source/external_engine.c b/source/blender/render/intern/source/external_engine.c index fd9d95c63b6..1744d88a14f 100644 --- a/source/blender/render/intern/source/external_engine.c +++ b/source/blender/render/intern/source/external_engine.c @@ -45,6 +45,7 @@ #include "BKE_camera.h" #include "BKE_global.h" #include "BKE_colortools.h" +#include "BKE_layer.h" #include "BKE_report.h" #include "BKE_scene.h" @@ -58,6 +59,8 @@ #include "RE_pipeline.h" #include "RE_bake.h" +#include "DRW_engine.h" + #include "initrender.h" #include "renderpipeline.h" #include "render_types.h" @@ -68,7 +71,7 @@ static RenderEngineType internal_render_type = { NULL, NULL, "BLENDER_RENDER", N_("Blender Render"), RE_INTERNAL, - NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, {NULL, NULL, NULL} }; @@ -77,7 +80,7 @@ static RenderEngineType internal_render_type = { static RenderEngineType internal_game_type = { NULL, NULL, "BLENDER_GAME", N_("Blender Game"), RE_INTERNAL | RE_GAME, - NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, {NULL, NULL, NULL} }; @@ -87,16 +90,21 @@ ListBase R_engines = {NULL, NULL}; void RE_engines_init(void) { - BLI_addtail(&R_engines, &internal_render_type); + RE_engines_register(NULL, &internal_render_type); #ifdef WITH_GAMEENGINE - BLI_addtail(&R_engines, &internal_game_type); + RE_engines_register(NULL, &internal_game_type); #endif + DRW_engines_init(); } void RE_engines_exit(void) { RenderEngineType *type, *next; + DRW_engines_free(); + + BKE_layer_collection_engine_settings_callback_free(); + for (type = R_engines.first; type; type = next) { next = type->next; @@ -111,6 +119,14 @@ void RE_engines_exit(void) } } +void RE_engines_register(Main *bmain, RenderEngineType *render_type) +{ + if (render_type->collection_settings_create) { + BKE_layer_collection_engine_settings_callback_register(bmain, render_type->idname, render_type->collection_settings_create); + } + BLI_addtail(&R_engines, render_type); +} + RenderEngineType *RE_engines_find(const char *idname) { RenderEngineType *type; diff --git a/source/blenderplayer/bad_level_call_stubs/stubs.c b/source/blenderplayer/bad_level_call_stubs/stubs.c index e74f6f3208c..a9cf76adae3 100644 --- a/source/blenderplayer/bad_level_call_stubs/stubs.c +++ b/source/blenderplayer/bad_level_call_stubs/stubs.c @@ -186,6 +186,7 @@ struct wmWindowManager; #include "../blender/render/extern/include/RE_pipeline.h" #include "../blender/render/extern/include/RE_render_ext.h" #include "../blender/render/extern/include/RE_shader_ext.h" +#include "../blender/draw/DRW_engine.h" #include "../blender/windowmanager/WM_api.h" @@ -663,6 +664,7 @@ void RE_ReleaseResultImage(struct Render *re) RET_NONE int RE_engine_test_break(struct RenderEngine *engine) RET_ZERO void RE_engines_init() RET_NONE void RE_engines_exit() RET_NONE +void RE_engines_register(struct Main *bmain, RenderEngineType *render_type) RET_NONE void RE_engine_report(struct RenderEngine *engine, int type, const char *msg) RET_NONE ListBase R_engines = {NULL, NULL}; void RE_engine_free(struct RenderEngine *engine) RET_NONE @@ -679,6 +681,9 @@ void RE_instance_get_particle_info(struct ObjectInstanceRen *obi, float *index, void RE_FreeAllPersistentData(void) RET_NONE float RE_fresnel_dielectric(float incoming[3], float normal[3], float eta) RET_ZERO +/* Draw */ +void *DRW_render_settings_get(struct Scene *scene, const char *engine_name) RET_NULL + /* python */ struct wmOperatorType *WM_operatortype_find(const char *idname, bool quiet) RET_NULL void WM_operatortype_iter(struct GHashIterator *ghi) RET_NONE -- cgit v1.2.3