Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDalai Felinto <dfelinto@gmail.com>2017-02-03 19:22:51 +0300
committerDalai Felinto <dfelinto@gmail.com>2017-02-03 19:22:51 +0300
commit16385ae285688c5d1634fa4964bea9854ef96764 (patch)
treef6c9a832de6ade36de4206c7bc65ce3a7016da7e
parenteaf9748f23f2ccb3dd95ea73859479be2fe0d769 (diff)
parent2b04710d61bd12598ec397ad402b85cc9fb72c12 (diff)
Merge remote-tracking branch 'origin/clay-engine' into render-layers
-rw-r--r--CMakeLists.txt4
-rw-r--r--build_files/cmake/macros.cmake1
-rw-r--r--release/scripts/startup/bl_ui/properties_collection.py49
-rw-r--r--release/scripts/startup/bl_ui/properties_material.py22
-rw-r--r--release/scripts/startup/bl_ui/properties_render.py19
-rw-r--r--release/scripts/startup/bl_ui/properties_render_layer.py2
-rw-r--r--source/blender/CMakeLists.txt1
-rw-r--r--source/blender/blenkernel/BKE_layer.h28
-rw-r--r--source/blender/blenkernel/intern/layer.c240
-rw-r--r--source/blender/blenkernel/intern/material.c11
-rw-r--r--source/blender/blenkernel/intern/mesh_render.c2
-rw-r--r--source/blender/blenkernel/intern/scene.c8
-rw-r--r--source/blender/blenloader/intern/readfile.c24
-rw-r--r--source/blender/blenloader/intern/versioning_280.c1
-rw-r--r--source/blender/blenloader/intern/writefile.c59
-rw-r--r--source/blender/draw/CMakeLists.txt40
-rw-r--r--source/blender/draw/DRW_engine.h45
-rw-r--r--source/blender/draw/DRW_engines.h0
-rw-r--r--source/blender/draw/engines/clay/clay.c722
-rw-r--r--source/blender/draw/engines/clay/clay.h (renamed from source/blender/draw/DRW_defines.h)17
-rw-r--r--source/blender/draw/engines/clay/shaders/clay_frag.glsl207
-rw-r--r--source/blender/draw/engines/clay/shaders/clay_vert.glsl20
-rw-r--r--source/blender/draw/engines/clay/shaders/ssao_alchemy.glsl73
-rw-r--r--source/blender/draw/engines/clay/shaders/ssao_groundtruth.glsl120
-rw-r--r--source/blender/draw/intern/DRW_render.h221
-rw-r--r--source/blender/draw/intern/draw_cache.c543
-rw-r--r--source/blender/draw/intern/draw_cache.h56
-rw-r--r--source/blender/draw/intern/draw_manager.c1142
-rw-r--r--source/blender/draw/intern/draw_mode_pass.c787
-rw-r--r--source/blender/draw/intern/draw_mode_pass.h45
-rw-r--r--source/blender/editors/space_view3d/drawvolume.c2
-rw-r--r--source/blender/editors/space_view3d/space_view3d.c2
-rw-r--r--source/blender/editors/space_view3d/view3d_draw.c42
-rw-r--r--source/blender/editors/space_view3d/view3d_intern.h1
-rw-r--r--source/blender/gpu/CMakeLists.txt9
-rw-r--r--source/blender/gpu/GPU_extensions.h2
-rw-r--r--source/blender/gpu/GPU_framebuffer.h1
-rw-r--r--source/blender/gpu/GPU_shader.h9
-rw-r--r--source/blender/gpu/GPU_texture.h105
-rw-r--r--source/blender/gpu/GPU_uniformbuffer.h44
-rw-r--r--source/blender/gpu/GPU_viewport.h42
-rw-r--r--source/blender/gpu/gawain/batch.c86
-rw-r--r--source/blender/gpu/gawain/batch.h2
-rw-r--r--source/blender/gpu/intern/gpu_codegen.c2
-rw-r--r--source/blender/gpu/intern/gpu_compositing.c112
-rw-r--r--source/blender/gpu/intern/gpu_draw.c23
-rw-r--r--source/blender/gpu/intern/gpu_extensions.c15
-rw-r--r--source/blender/gpu/intern/gpu_framebuffer.c42
-rw-r--r--source/blender/gpu/intern/gpu_material.c4
-rw-r--r--source/blender/gpu/intern/gpu_shader.c40
-rw-r--r--source/blender/gpu/intern/gpu_texture.c662
-rw-r--r--source/blender/gpu/intern/gpu_uniformbuffer.c105
-rw-r--r--source/blender/gpu/intern/gpu_viewport.c198
-rw-r--r--source/blender/gpu/shaders/gpu_shader_3D_groundline_geom.glsl16
-rw-r--r--source/blender/gpu/shaders/gpu_shader_3D_groundline_vert.glsl8
-rw-r--r--source/blender/gpu/shaders/gpu_shader_3D_groundpoint_vert.glsl11
-rw-r--r--source/blender/gpu/shaders/gpu_shader_3D_instance_vert.glsl10
-rw-r--r--source/blender/gpu/shaders/gpu_shader_3D_lamp_vert.glsl24
-rw-r--r--source/blender/makesdna/DNA_layer_types.h47
-rw-r--r--source/blender/makesdna/DNA_material_types.h40
-rw-r--r--source/blender/makesdna/DNA_object_types.h3
-rw-r--r--source/blender/makesdna/DNA_scene_types.h49
-rw-r--r--source/blender/makesrna/RNA_access.h5
-rw-r--r--source/blender/makesrna/intern/CMakeLists.txt5
-rw-r--r--source/blender/makesrna/intern/rna_material.c143
-rw-r--r--source/blender/makesrna/intern/rna_render.c30
-rw-r--r--source/blender/makesrna/intern/rna_scene.c436
-rw-r--r--source/blender/render/CMakeLists.txt1
-rw-r--r--source/blender/render/extern/include/RE_engine.h6
-rw-r--r--source/blender/render/intern/source/external_engine.c24
-rw-r--r--source/blenderplayer/bad_level_call_stubs/stubs.c5
71 files changed, 6507 insertions, 415 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index de01be1d299..b1a9d6fcf3f 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -165,6 +165,7 @@ option_defaults_init(
_init_FFTW3
_init_GAMEENGINE
_init_OPENSUBDIV
+ _init_CLAY_ENGINE
)
# customize...
@@ -186,6 +187,7 @@ elseif(WIN32)
elseif(APPLE)
set(_init_JACK OFF)
set(_init_OPENSUBDIV OFF)
+ set(_init_CLAY_ENGINE OFF)
endif()
@@ -242,6 +244,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)" _init_CLAY_ENGINE)
+
# 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_material.py b/release/scripts/startup/bl_ui/properties_material.py
index d916007ea41..e8ba7cc8033 100644
--- a/release/scripts/startup/bl_ui/properties_material.py
+++ b/release/scripts/startup/bl_ui/properties_material.py
@@ -106,7 +106,7 @@ class MaterialButtonsPanel:
class MATERIAL_PT_context_material(MaterialButtonsPanel, Panel):
bl_label = ""
bl_options = {'HIDE_HEADER'}
- COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'}
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME', 'BLENDER_CLAY'}
@classmethod
def poll(cls, context):
@@ -1052,5 +1052,25 @@ class MATERIAL_PT_custom_props(MaterialButtonsPanel, PropertyPanel, Panel):
_context_path = "material"
_property_type = bpy.types.Material
+
+class MATERIAL_PT_clay_settings(MaterialButtonsPanel, Panel):
+ bl_label = "Matcap"
+ COMPAT_ENGINES = {'BLENDER_CLAY'}
+
+ def draw(self, context):
+ layout = self.layout;
+ settings = context.material.clay_settings
+ # layout.template_icon_view(settings, "matcap_icon")
+ # layout.prop(settings, "type")
+ # 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")
+
+
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 850606eb80b..5f2c9939dc9 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 e74cfbe9a11..c16d00de3e3 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 /* Base to ObjectBase 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 CollectionEngineSettings;
struct LayerCollection;
struct ID;
+struct ListBase;
struct Main;
struct Object;
struct ObjectBase;
+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 ObjectBase *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);
+int 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*/ \
ObjectBase *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 58427c6115b..3d3e621e97e 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;
}
@@ -579,6 +614,211 @@ void BKE_collection_override_datablock_add(LayerCollection *UNUSED(lc), const ch
}
/* ---------------------------------------------------------------------- */
+/* 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;
+}
+
+int 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 */
static void object_bases_Iterator_begin(Iterator *iter, void *data_in, const int flag)
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 c1316373b2a..cc136e8e748 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 90f7ddc5f6d..9206f4b65e4 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 ***************** */
@@ -4610,6 +4616,7 @@ static void direct_link_mesh(FileData *fd, Mesh *mesh)
mesh->bb = NULL;
mesh->edit_btmesh = NULL;
+ mesh->batch_cache = NULL;
/* happens with old files */
if (mesh->mselect == NULL) {
@@ -5551,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);
@@ -5923,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);
@@ -5937,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);
}
}
@@ -5949,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;
@@ -6211,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 2f3251fb702..92592e9fc62 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 c22acf2f758..fc4e16b2cd1 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);
@@ -2271,6 +2273,7 @@ static void write_meshes(WriteData *wd, ListBase *idbase)
CustomData_reset(&mesh->pdata);
CustomData_reset(&mesh->ldata);
mesh->edit_btmesh = NULL;
+ mesh->batch_cache = NULL;
/* now fill in polys to mfaces */
/* XXX This breaks writing design, by using temp allocated memory, which will likely generate
@@ -2468,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;
@@ -2504,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;
}
@@ -2638,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) {
@@ -2646,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;
@@ -2879,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_engine.h b/source/blender/draw/DRW_engine.h
new file mode 100644
index 00000000000..4f86e3fcd91
--- /dev/null
+++ b/source/blender/draw/DRW_engine.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2016, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contributor(s): Blender Institute
+ *
+ */
+
+/** \file DRW_engine.h
+ * \ingroup draw
+ */
+
+#ifndef __DRW_ENGINE_H__
+#define __DRW_ENGINE_H__
+
+//#define WITH_VIEWPORT_CACHE_TEST
+
+struct DRWPass;
+struct Material;
+struct Scene;
+
+void DRW_engines_init(void);
+void DRW_engines_free(void);
+
+/* This is here because GPUViewport needs it */
+void DRW_pass_free(struct DRWPass *pass);
+
+/* Settings */
+void *DRW_material_settings_get(struct Material *ma, const char *engine_name);
+void *DRW_render_settings_get(struct Scene *scene, const char *engine_name);
+
+#endif /* __DRW_ENGINE_H__ */ \ No newline at end of file
diff --git a/source/blender/draw/DRW_engines.h b/source/blender/draw/DRW_engines.h
deleted file mode 100644
index e69de29bb2d..00000000000
--- a/source/blender/draw/DRW_engines.h
+++ /dev/null
diff --git a/source/blender/draw/engines/clay/clay.c b/source/blender/draw/engines/clay/clay.c
new file mode 100644
index 00000000000..f443606f11d
--- /dev/null
+++ b/source/blender/draw/engines/clay/clay.c
@@ -0,0 +1,722 @@
+/*
+ * Copyright 2016, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contributor(s): Blender Institute
+ *
+ */
+
+#include "DRW_render.h"
+
+#include "BKE_icons.h"
+#include "BKE_main.h"
+
+#include "BLI_dynstr.h"
+#include "BLI_rand.h"
+
+#include "IMB_imbuf.h"
+#include "IMB_imbuf_types.h"
+
+#include "UI_resources.h"
+#include "UI_interface_icons.h"
+
+#include "clay.h"
+#ifdef WITH_CLAY_ENGINE
+/* Shaders */
+
+extern char datatoc_clay_frag_glsl[];
+extern char datatoc_clay_vert_glsl[];
+extern char datatoc_ssao_alchemy_glsl[];
+extern char datatoc_ssao_groundtruth_glsl[];
+
+/* Storage */
+
+/* UBOs data needs to be 16 byte aligned (size of vec4) */
+/* Reminder : float, int, bool are 4 bytes */
+typedef struct CLAY_UBO_Material {
+ float ssao_params_var[4];
+ /* - 16 -*/
+ float matcap_hsv[3];
+ float matcap_id; /* even float encoding have enough precision */
+ /* - 16 -*/
+ float matcap_rot[2];
+ float pad[2]; /* ensure 16 bytes alignement */
+} CLAY_UBO_Material; /* 48 bytes */
+
+typedef struct CLAY_UBO_Storage {
+ CLAY_UBO_Material materials[512]; /* 512 = 9 bit material id */
+} CLAY_UBO_Storage;
+
+static struct CLAY_data {
+ /* Depth Pre Pass */
+ struct GPUShader *depth_sh;
+ /* Shading Pass */
+ struct GPUShader *clay_sh;
+
+ /* Materials Parameter UBO */
+ struct GPUUniformBuffer *mat_ubo;
+ CLAY_UBO_Storage mat_storage;
+ short ubo_flag;
+
+ /* Matcap textures */
+ struct GPUTexture *matcap_array;
+ float matcap_colors[24][3];
+
+ /* Ssao */
+ float winmat[4][4];
+ float viewvecs[3][4];
+ float ssao_params[4];
+ struct GPUTexture *jitter_tx;
+ struct GPUTexture *sampling_tx;
+} data = {NULL};
+
+/* CLAY_data.ubo_flag */
+enum {
+ CLAY_UBO_CLEAR = (1 << 0),
+ CLAY_UBO_REFRESH = (1 << 1),
+};
+
+/* keep it under MAX_BUFFERS */
+typedef struct CLAY_FramebufferList{
+ /* default */
+ struct GPUFrameBuffer *default_fb;
+ /* engine specific */
+ struct GPUFrameBuffer *downsample_depth;
+} CLAY_FramebufferList;
+
+/* keep it under MAX_TEXTURES */
+typedef struct CLAY_TextureList{
+ /* default */
+ struct GPUTexture *color;
+ struct GPUTexture *depth;
+ /* engine specific */
+ struct GPUTexture *depth_low;
+} CLAY_TextureList;
+
+/* for clarity follow the same layout as CLAY_TextureList */
+enum {
+ SCENE_COLOR,
+ SCENE_DEPTH,
+ SCENE_DEPTH_LOW,
+};
+
+/* keep it under MAX_PASSES */
+typedef struct CLAY_PassList{
+ /* default */
+ struct DRWPass *non_meshes_pass;
+ struct DRWPass *ob_center_pass;
+ /* engine specific */
+ struct DRWPass *depth_pass;
+ struct DRWPass *clay_pass;
+ struct DRWPass *wire_overlay_pass;
+ struct DRWPass *wire_outline_pass;
+} CLAY_PassList;
+
+//#define GTAO
+
+/* Functions */
+
+static void add_icon_to_rect(PreviewImage *prv, float *final_rect, int layer)
+{
+ int image_size = prv->w[0] * prv->h[0];
+ float *new_rect = &final_rect[image_size * 4 * layer];
+
+ IMB_buffer_float_from_byte(new_rect, (unsigned char *)prv->rect[0], IB_PROFILE_SRGB, IB_PROFILE_SRGB,
+ false, prv->w[0], prv->h[0], prv->w[0], prv->w[0]);
+
+ /* Find overall color */
+ for (int y = 0; y < 4; ++y) {
+ for (int x = 0; x < 4; ++x) {
+ data.matcap_colors[layer][0] += new_rect[y * 512 * 128 * 4 + x * 128 * 4 + 0];
+ data.matcap_colors[layer][1] += new_rect[y * 512 * 128 * 4 + x * 128 * 4 + 1];
+ data.matcap_colors[layer][2] += new_rect[y * 512 * 128 * 4 + x * 128 * 4 + 2];
+ }
+ }
+
+ data.matcap_colors[layer][0] /= 16.0f * 2.0f; /* the * 2 is to darken for shadows */
+ data.matcap_colors[layer][1] /= 16.0f * 2.0f;
+ data.matcap_colors[layer][2] /= 16.0f * 2.0f;
+}
+
+static struct GPUTexture *load_matcaps(PreviewImage *prv[24], int nbr)
+{
+ struct GPUTexture *tex;
+ int w = prv[0]->w[0];
+ int h = prv[0]->h[0];
+ float *final_rect = MEM_callocN(sizeof(float) * 4 * w * h * nbr, "Clay Matcap array rect");
+
+ for (int i = 0; i < nbr; ++i) {
+ add_icon_to_rect(prv[i], final_rect, i);
+ BKE_previewimg_free(&prv[i]);
+ }
+
+ tex = DRW_texture_create_2D_array(w, h, nbr, DRW_TEX_RGBA_8, DRW_TEX_FILTER, final_rect);
+ MEM_freeN(final_rect);
+
+ return tex;
+}
+
+static int matcap_to_index(int matcap)
+{
+ if (matcap == ICON_MATCAP_02) return 1;
+ else if (matcap == ICON_MATCAP_03) return 2;
+ else if (matcap == ICON_MATCAP_04) return 3;
+ else if (matcap == ICON_MATCAP_05) return 4;
+ else if (matcap == ICON_MATCAP_06) return 5;
+ else if (matcap == ICON_MATCAP_07) return 6;
+ else if (matcap == ICON_MATCAP_08) return 7;
+ else if (matcap == ICON_MATCAP_09) return 8;
+ else if (matcap == ICON_MATCAP_10) return 9;
+ else if (matcap == ICON_MATCAP_11) return 10;
+ else if (matcap == ICON_MATCAP_12) return 11;
+ else if (matcap == ICON_MATCAP_13) return 12;
+ else if (matcap == ICON_MATCAP_14) return 13;
+ else if (matcap == ICON_MATCAP_15) return 14;
+ else if (matcap == ICON_MATCAP_16) return 15;
+ else if (matcap == ICON_MATCAP_17) return 16;
+ else if (matcap == ICON_MATCAP_18) return 17;
+ else if (matcap == ICON_MATCAP_19) return 18;
+ else if (matcap == ICON_MATCAP_20) return 19;
+ else if (matcap == ICON_MATCAP_21) return 20;
+ else if (matcap == ICON_MATCAP_22) return 21;
+ else if (matcap == ICON_MATCAP_23) return 22;
+ else if (matcap == ICON_MATCAP_24) return 23;
+ return 0;
+}
+
+static struct GPUTexture *create_spiral_sample_texture(int numsaples)
+{
+ struct GPUTexture *tex;
+ float (*texels)[2] = MEM_mallocN(sizeof(float[2]) * numsaples, "concentric_tex");
+ const float numsaples_inv = 1.0f / numsaples;
+ int i;
+ /* arbitrary number to ensure we don't get conciding samples every circle */
+ const float spirals = 7.357;
+
+ for (i = 0; i < numsaples; i++) {
+ float r = (i + 0.5f) * numsaples_inv;
+ float phi = r * spirals * (float)(2.0 * M_PI);
+ texels[i][0] = r * cosf(phi);
+ texels[i][1] = r * sinf(phi);
+ }
+
+ tex = DRW_texture_create_1D(numsaples, DRW_TEX_RG_16, 0, (float *)texels);
+
+ MEM_freeN(texels);
+ return tex;
+}
+
+static struct GPUTexture *create_jitter_texture(void)
+{
+ float jitter[64 * 64][2];
+ int i;
+
+ /* TODO replace by something more evenly distributed like blue noise */
+ for (i = 0; i < 64 * 64; i++) {
+#ifdef GTAO
+ jitter[i][0] = BLI_frand();
+ jitter[i][1] = BLI_frand();
+#else
+ jitter[i][0] = 2.0f * BLI_frand() - 1.0f;
+ jitter[i][1] = 2.0f * BLI_frand() - 1.0f;
+ normalize_v2(jitter[i]);
+#endif
+ }
+
+ return DRW_texture_create_2D(64, 64, DRW_TEX_RG_16, DRW_TEX_FILTER | DRW_TEX_WRAP, &jitter[0][0]);
+}
+
+static void clay_material_settings_init(MaterialEngineSettingsClay *ma)
+{
+ ma->matcap_icon = ICON_MATCAP_01;
+ ma->matcap_rot = 0.0f;
+ ma->matcap_hue = 0.5f;
+ ma->matcap_sat = 0.5f;
+ ma->matcap_val = 0.5f;
+ ma->ssao_distance = 0.2;
+ ma->ssao_attenuation = 1.0f;
+ ma->ssao_factor_cavity = 1.0f;
+ ma->ssao_factor_edge = 1.0f;
+}
+
+RenderEngineSettings *CLAY_render_settings_create(void)
+{
+ RenderEngineSettingsClay *settings = MEM_callocN(sizeof(RenderEngineSettingsClay), "RenderEngineSettingsClay");
+
+ clay_material_settings_init((MaterialEngineSettingsClay *)settings);
+
+ settings->ssao_samples = 32;
+
+ return (RenderEngineSettings *)settings;
+}
+
+MaterialEngineSettings *CLAY_material_settings_create(void)
+{
+ MaterialEngineSettingsClay *settings = MEM_callocN(sizeof(MaterialEngineSettingsClay), "MaterialEngineSettingsClay");
+
+ clay_material_settings_init(settings);
+
+ return (MaterialEngineSettings *)settings;
+}
+
+static void CLAY_engine_init(const bContext *C)
+{
+ Main *bmain = CTX_data_main(C);
+
+ /* Create Texture Array */
+ if (!data.matcap_array) {
+ PreviewImage *prv[24]; /* For now use all of the 24 internal matcaps */
+
+ /* TODO only load used matcaps */
+ prv[0] = UI_icon_to_preview(ICON_MATCAP_01);
+ prv[1] = UI_icon_to_preview(ICON_MATCAP_02);
+ prv[2] = UI_icon_to_preview(ICON_MATCAP_03);
+ prv[3] = UI_icon_to_preview(ICON_MATCAP_04);
+ prv[4] = UI_icon_to_preview(ICON_MATCAP_05);
+ prv[5] = UI_icon_to_preview(ICON_MATCAP_06);
+ prv[6] = UI_icon_to_preview(ICON_MATCAP_07);
+ prv[7] = UI_icon_to_preview(ICON_MATCAP_08);
+ prv[8] = UI_icon_to_preview(ICON_MATCAP_09);
+ prv[9] = UI_icon_to_preview(ICON_MATCAP_10);
+ prv[10] = UI_icon_to_preview(ICON_MATCAP_11);
+ prv[11] = UI_icon_to_preview(ICON_MATCAP_12);
+ prv[12] = UI_icon_to_preview(ICON_MATCAP_13);
+ prv[13] = UI_icon_to_preview(ICON_MATCAP_14);
+ prv[14] = UI_icon_to_preview(ICON_MATCAP_15);
+ prv[15] = UI_icon_to_preview(ICON_MATCAP_16);
+ prv[16] = UI_icon_to_preview(ICON_MATCAP_17);
+ prv[17] = UI_icon_to_preview(ICON_MATCAP_18);
+ prv[18] = UI_icon_to_preview(ICON_MATCAP_19);
+ prv[19] = UI_icon_to_preview(ICON_MATCAP_20);
+ prv[20] = UI_icon_to_preview(ICON_MATCAP_21);
+ prv[21] = UI_icon_to_preview(ICON_MATCAP_22);
+ prv[22] = UI_icon_to_preview(ICON_MATCAP_23);
+ prv[23] = UI_icon_to_preview(ICON_MATCAP_24);
+
+ data.matcap_array = load_matcaps(prv, 24);
+ }
+
+ /* AO Jitter */
+ if (!data.jitter_tx) {
+ data.jitter_tx = create_jitter_texture();
+ }
+
+ /* AO Samples */
+ /* TODO use hammersley sequence */
+ if (!data.sampling_tx) {
+ data.sampling_tx = create_spiral_sample_texture(500);
+ }
+
+ /* Depth prepass */
+ if (!data.depth_sh) {
+ data.depth_sh = DRW_shader_create_3D_depth_only();
+ }
+
+ if (!data.mat_ubo) {
+ data.mat_ubo = DRW_uniformbuffer_create(sizeof(CLAY_UBO_Storage), NULL);
+ }
+
+ /* Shading pass */
+ if (!data.clay_sh) {
+ DynStr *ds = BLI_dynstr_new();
+ const char *max_mat =
+ "#define MAX_MATERIAL 512\n"
+ "#define USE_ROTATION\n"
+ "#define USE_AO\n"
+ "#define USE_HSV\n";
+ char *matcap_with_ao;
+
+ BLI_dynstr_append(ds, datatoc_clay_frag_glsl);
+#ifdef GTAO
+ BLI_dynstr_append(ds, datatoc_ssao_groundtruth_glsl);
+#else
+ BLI_dynstr_append(ds, datatoc_ssao_alchemy_glsl);
+#endif
+
+ matcap_with_ao = BLI_dynstr_get_cstring(ds);
+
+ data.clay_sh = DRW_shader_create(datatoc_clay_vert_glsl, NULL, matcap_with_ao, max_mat);
+
+ BLI_dynstr_free(ds);
+ MEM_freeN(matcap_with_ao);
+ }
+
+ /* Cleanup all runtime data loaded from file */
+ for (Scene *sce = bmain->scene.first; sce; sce = sce->id.next) {
+ /* Using render settings as material settings */
+ MaterialEngineSettingsClay *res = DRW_render_settings_get(sce, RE_engine_id_BLENDER_CLAY);
+ res->flag = CLAY_OUTDATED;
+ res->ubo_index = -1;
+
+ /* Update Collections Materials */
+ for (SceneLayer *sl = sce->render_layers.first; sl; sl = sl->next) {
+ for (LayerCollection *lc = sl->layer_collections.first; lc; lc = lc->next) {
+ CollectionEngineSettings *ces;
+ ces = BKE_layer_collection_engine_get(lc, RE_engine_id_BLENDER_CLAY);
+ if (ces) { /* May not exists */
+ BKE_collection_engine_property_value_set_int(ces, "flag", CLAY_OUTDATED);
+ BKE_collection_engine_property_value_set_int(ces, "ubo_index", -1);
+ }
+ }
+ }
+ }
+
+ data.ubo_flag |= CLAY_UBO_REFRESH;
+}
+
+static void CLAY_ssao_setup(void)
+{
+ float invproj[4][4];
+ float dfdyfacs[2];
+ bool is_persp = DRW_viewport_is_persp_get();
+ /* view vectors for the corners of the view frustum. Can be used to recreate the world space position easily */
+ float viewvecs[3][4] = {
+ {-1.0f, -1.0f, -1.0f, 1.0f},
+ {1.0f, -1.0f, -1.0f, 1.0f},
+ {-1.0f, 1.0f, -1.0f, 1.0f}
+ };
+ int i;
+ float *size = DRW_viewport_size_get();
+ RenderEngineSettingsClay *settings = DRW_render_settings_get(NULL, RE_engine_id_BLENDER_CLAY);
+
+ DRW_get_dfdy_factors(dfdyfacs);
+
+ data.ssao_params[0] = settings->ssao_samples;
+ data.ssao_params[1] = size[0] / 64.0;
+ data.ssao_params[2] = size[1] / 64.0;
+ data.ssao_params[3] = dfdyfacs[1]; /* dfdy sign for offscreen */
+
+ /* invert the view matrix */
+ DRW_viewport_matrix_get(data.winmat, DRW_MAT_WIN);
+ invert_m4_m4(invproj, data.winmat);
+
+ /* convert the view vectors to view space */
+ for (i = 0; i < 3; i++) {
+ mul_m4_v4(invproj, viewvecs[i]);
+ /* normalized trick see http://www.derschmale.com/2014/01/26/reconstructing-positions-from-the-depth-buffer */
+ mul_v3_fl(viewvecs[i], 1.0f / viewvecs[i][3]);
+ if (is_persp)
+ mul_v3_fl(viewvecs[i], 1.0f / viewvecs[i][2]);
+ viewvecs[i][3] = 1.0;
+
+ copy_v4_v4(data.viewvecs[i], viewvecs[i]);
+ }
+
+ /* we need to store the differences */
+ data.viewvecs[1][0] -= data.viewvecs[0][0];
+ data.viewvecs[1][1] = data.viewvecs[2][1] - data.viewvecs[0][1];
+
+ /* calculate a depth offset as well */
+ if (!is_persp) {
+ float vec_far[] = {-1.0f, -1.0f, 1.0f, 1.0f};
+ mul_m4_v4(invproj, vec_far);
+ mul_v3_fl(vec_far, 1.0f / vec_far[3]);
+ data.viewvecs[1][2] = vec_far[2] - data.viewvecs[0][2];
+ }
+}
+
+static DRWShadingGroup *CLAY_shgroup_create(DRWPass *pass, int *UNUSED(material_id))
+{
+ const int depthloc = 0, matcaploc = 1, jitterloc = 2, sampleloc = 3;
+
+ //CLAY_UBO_Material *mat = &data.mat_storage.materials[0];
+ DRWShadingGroup *grp = DRW_shgroup_create(data.clay_sh, pass);
+
+ DRW_shgroup_uniform_vec2(grp, "screenres", DRW_viewport_size_get(), 1);
+ DRW_shgroup_uniform_buffer(grp, "depthtex", SCENE_DEPTH, depthloc);
+ DRW_shgroup_uniform_texture(grp, "matcaps", data.matcap_array, matcaploc);
+ DRW_shgroup_uniform_mat4(grp, "WinMatrix", (float *)data.winmat);
+ DRW_shgroup_uniform_vec4(grp, "viewvecs", (float *)data.viewvecs, 3);
+ DRW_shgroup_uniform_vec4(grp, "ssao_params", data.ssao_params, 1);
+ DRW_shgroup_uniform_vec3(grp, "matcaps_color", (float *)data.matcap_colors, 24);
+
+ //DRW_shgroup_uniform_int(grp, "material_id", material_id, 1);
+
+#ifndef GTAO
+ DRW_shgroup_uniform_texture(grp, "ssao_jitter", data.jitter_tx, jitterloc);
+ DRW_shgroup_uniform_texture(grp, "ssao_samples", data.sampling_tx, sampleloc);
+#endif
+
+ return grp;
+}
+
+static void update_ubo_storage(float matcap_rot, float matcap_hue, float matcap_sat, float matcap_val,
+ float ssao_distance, float ssao_factor_cavity, float ssao_factor_edge,
+ float ssao_attenuation, int matcap_icon, unsigned int current_id)
+{
+ CLAY_UBO_Material *ubo = &data.mat_storage.materials[current_id];
+
+ ubo->matcap_rot[0] = cosf(matcap_rot * 3.14159f * 2.0f);
+ ubo->matcap_rot[1] = sinf(matcap_rot * 3.14159f * 2.0f);
+
+ ubo->matcap_hsv[0] = matcap_hue + 0.5f;
+ ubo->matcap_hsv[1] = matcap_sat * 2.0f;
+ ubo->matcap_hsv[2] = matcap_val * 2.0f;
+
+ ubo->ssao_params_var[0] = ssao_distance;
+ ubo->ssao_params_var[1] = ssao_factor_cavity;
+ ubo->ssao_params_var[2] = ssao_factor_edge;
+ ubo->ssao_params_var[3] = ssao_attenuation;
+
+
+ ubo->matcap_id = matcap_to_index(matcap_icon);
+}
+
+static void CLAY_update_material_ubo(const struct bContext *C)
+{
+ Main *bmain = CTX_data_main(C);
+
+ /* Update Default materials */
+ for (Scene *sce = bmain->scene.first; sce; sce = sce->id.next) {
+ /* Using render settings as material settings */
+ MaterialEngineSettingsClay *res = DRW_render_settings_get(sce, RE_engine_id_BLENDER_CLAY);
+
+ if (res->flag & CLAY_OUTDATED)
+ data.ubo_flag |= CLAY_UBO_REFRESH;
+
+ if (res->matcap_icon < ICON_MATCAP_01 ||
+ res->matcap_icon > ICON_MATCAP_24)
+ {
+ res->matcap_icon = ICON_MATCAP_01;
+ }
+
+ res->flag &= ~CLAY_OUTDATED;
+
+
+ /* Update Collections Materials */
+ for (SceneLayer *sl = sce->render_layers.first; sl; sl = sl->next) {
+ for (LayerCollection *lc = sl->layer_collections.first; lc; lc = lc->next) {
+ CollectionEngineSettings *ces;
+ ces = BKE_layer_collection_engine_get(lc, RE_engine_id_BLENDER_CLAY);
+
+ BKE_collection_engine_property_value_set_int(ces, "flag", 0);
+ BKE_collection_engine_property_value_set_int(ces, "ubo_index", 0);
+ }
+ }
+ }
+
+ if (data.ubo_flag & CLAY_UBO_REFRESH) {
+ int current_id = 0;
+
+
+ /* Default materials */
+ for (Scene *sce = bmain->scene.first; sce; sce = sce->id.next) {
+ MaterialEngineSettingsClay *res = DRW_render_settings_get(sce, RE_engine_id_BLENDER_CLAY);
+
+ update_ubo_storage(res->matcap_rot, res->matcap_hue, res->matcap_sat, res->matcap_val,
+ res->ssao_distance, res->ssao_factor_cavity, res->ssao_factor_edge,
+ res->ssao_attenuation, res->matcap_icon, current_id);
+ current_id++;
+
+ for (SceneLayer *sl = sce->render_layers.first; sl; sl = sl->next) {
+ for (LayerCollection *lc = sl->layer_collections.first; lc; lc = lc->next) {
+ /* TODO */
+ current_id++;
+ }
+ }
+ current_id++;
+ }
+
+
+ DRW_uniformbuffer_update(data.mat_ubo, &data.mat_storage);
+ }
+
+ data.ubo_flag = 0;
+}
+
+static void CLAY_create_cache(CLAY_PassList *passes, const struct bContext *C)
+{
+ SceneLayer *sl = CTX_data_scene_layer(C);
+ DRWShadingGroup *default_shgrp, *depthbatch;
+
+ /* Depth Pass */
+ {
+ passes->depth_pass = DRW_pass_create("Depth Pass", DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS);
+
+ depthbatch = DRW_shgroup_create(data.depth_sh, passes->depth_pass);
+ }
+
+ /* Clay Pass */
+ {
+ MaterialEngineSettingsClay *settings = DRW_render_settings_get(NULL, RE_engine_id_BLENDER_CLAY);
+
+ passes->clay_pass = DRW_pass_create("Clay Pass", DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS);
+
+ default_shgrp = CLAY_shgroup_create(passes->clay_pass, &settings->ubo_index);
+ DRW_shgroup_uniform_block(default_shgrp, "material_block", data.mat_ubo, 0);
+ }
+
+ /* Object Mode */
+ {
+ DRW_pass_setup_common(&passes->wire_overlay_pass,
+ &passes->wire_outline_pass,
+ &passes->non_meshes_pass,
+ &passes->ob_center_pass);
+ }
+
+ /* TODO Create hash table of batch based on material id*/
+ Object *ob;
+ DEG_OBJECT_ITER(sl, ob)
+ {
+ if ((ob->base_flag & BASE_VISIBLED) == 0) {
+ continue;
+ }
+
+ struct Batch *geom;
+ //bool do_outlines;
+
+ switch (ob->type) {
+ case OB_MESH:
+ geom = DRW_cache_surface_get(ob);
+
+ /* Add everything for now */
+ DRW_shgroup_call_add(depthbatch, geom, ob->obmat);
+ DRW_shgroup_call_add(default_shgrp, geom, ob->obmat);
+
+ //DRW_shgroup_wire_overlay(passes->wire_overlay_pass, ob);
+
+ //do_outlines = ((ob->base_flag & BASE_SELECTED) != 0);
+ //DRW_shgroup_wire_outline(passes->wire_outline_pass, ob, false, false, do_outlines);
+
+ /* When encountering a new material :
+ * - Create new Batch
+ * - Initialize Batch
+ * - Push it to the hash table
+ * - The pass takes care of inserting it
+ * next to the same shader calls */
+
+ /* Free hash table */
+ break;
+ case OB_LAMP:
+ case OB_CAMERA:
+ case OB_EMPTY:
+ default:
+ DRW_shgroup_non_meshes(passes->non_meshes_pass, ob);
+ break;
+ }
+
+ DRW_shgroup_object_center(passes->ob_center_pass, ob);
+ DRW_shgroup_relationship_lines(passes->non_meshes_pass, ob);
+ }
+ DEG_OBJECT_ITER_END
+}
+
+static void CLAY_view_draw(RenderEngine *UNUSED(engine), const bContext *context)
+{
+ /* This function may run for multiple viewports
+ * so get the current viewport buffers */
+ CLAY_FramebufferList *buffers = NULL;
+ CLAY_TextureList *textures = NULL;
+ CLAY_PassList *passes = NULL;
+
+ DRW_viewport_init(context, (void **)&buffers, (void **)&textures, (void **)&passes);
+
+ CLAY_engine_init(context);
+
+ CLAY_update_material_ubo(context);
+
+ /* TODO : tag to refresh by the deps graph */
+ /* ideally only refresh when objects are added/removed */
+ /* or render properties / materials change */
+#ifdef WITH_VIEWPORT_CACHE_TEST
+ static bool once = false;
+#endif
+ if (DRW_viewport_cache_is_dirty()
+#ifdef WITH_VIEWPORT_CACHE_TEST
+ && !once
+#endif
+ ) {
+#ifdef WITH_VIEWPORT_CACHE_TEST
+ once = true;
+#endif
+ CLAY_create_cache(passes, context);
+ }
+
+ /* Start Drawing */
+ DRW_draw_background();
+
+ /* Pass 1 : Depth pre-pass */
+ DRW_draw_pass(passes->depth_pass);
+
+ /* Pass 2 (Optionnal) : Separated Downsampled AO */
+ DRW_framebuffer_texture_detach(textures->depth);
+ /* TODO */
+
+ /* Pass 3 : Shading */
+ CLAY_ssao_setup();
+ DRW_draw_pass(passes->clay_pass);
+
+ /* Pass 4 : Overlays */
+ DRW_framebuffer_texture_attach(buffers->default_fb, textures->depth, 0);
+ //DRW_draw_pass(passes->wire_overlay_pass);
+ //DRW_draw_pass(passes->wire_outline_pass);
+ DRW_draw_pass(passes->non_meshes_pass);
+ DRW_draw_pass(passes->ob_center_pass);
+
+ /* Always finish by this */
+ DRW_state_reset();
+}
+
+static void CLAY_collection_settings_create(RenderEngine *UNUSED(engine), CollectionEngineSettings *ces)
+{
+ BLI_assert(ces);
+ BKE_collection_engine_property_add_int(ces, "matcap_icon", ICON_MATCAP_01);
+ BKE_collection_engine_property_add_int(ces, "type", CLAY_MATCAP_NONE);
+ BKE_collection_engine_property_add_float(ces, "matcap_rotation", 0.0f);
+ BKE_collection_engine_property_add_float(ces, "matcap_hue", 0.5f);
+ BKE_collection_engine_property_add_float(ces, "matcap_saturation", 0.5f);
+ BKE_collection_engine_property_add_float(ces, "matcap_value", 0.5f);
+ BKE_collection_engine_property_add_float(ces, "ssao_distance", 0.2f);
+ BKE_collection_engine_property_add_float(ces, "ssao_attenuation", 1.0f);
+ BKE_collection_engine_property_add_float(ces, "ssao_factor_cavity", 1.0f);
+ BKE_collection_engine_property_add_float(ces, "ssao_factor_edge", 1.0f);
+
+ /* Runtime data (not display in settings) */
+ BKE_collection_engine_property_add_int(ces, "ubo_index", -1);
+ BKE_collection_engine_property_add_int(ces, "flag", CLAY_OUTDATED);
+}
+
+void clay_engine_free(void)
+{
+ /* data.depth_sh Is builtin so it's automaticaly freed */
+ if (data.clay_sh) {
+ DRW_shader_free(data.clay_sh);
+ }
+
+ if (data.matcap_array) {
+ DRW_texture_free(data.matcap_array);
+ }
+
+ if (data.jitter_tx) {
+ DRW_texture_free(data.jitter_tx);
+ }
+
+ if (data.sampling_tx) {
+ DRW_texture_free(data.sampling_tx);
+ }
+
+ if (data.mat_ubo) {
+ DRW_uniformbuffer_free(data.mat_ubo);
+ }
+}
+
+RenderEngineType viewport_clay_type = {
+ NULL, NULL,
+ "BLENDER_CLAY", N_("Clay"), RE_INTERNAL | RE_USE_OGL_PIPELINE,
+ NULL, NULL, NULL, NULL, &CLAY_view_draw, NULL, &CLAY_collection_settings_create,
+ {NULL, NULL, NULL}
+};
+#endif \ No newline at end of file
diff --git a/source/blender/draw/DRW_defines.h b/source/blender/draw/engines/clay/clay.h
index 212c39e203b..404924be2a1 100644
--- a/source/blender/draw/DRW_defines.h
+++ b/source/blender/draw/engines/clay/clay.h
@@ -19,7 +19,18 @@
*
*/
-#ifndef __DRW_DEFINES_H__
-#define __DRW_DEFINES_H__
+/** \file clay.h
+ * \ingroup DNA
+ */
+
+#ifndef __ENGINE_CLAY_H__
+#define __ENGINE_CLAY_H__
+
+extern RenderEngineType viewport_clay_type;
+
+struct RenderEngineSettings *CLAY_render_settings_create(void);
+struct MaterialEngineSettings *CLAY_material_settings_create(void);
+
+void clay_engine_free(void);
-#endif /* __DRW_DEFINES_H__ */
+#endif /* __ENGINE_CLAY_H__ */ \ No newline at end of file
diff --git a/source/blender/draw/engines/clay/shaders/clay_frag.glsl b/source/blender/draw/engines/clay/shaders/clay_frag.glsl
new file mode 100644
index 00000000000..d9b372b652a
--- /dev/null
+++ b/source/blender/draw/engines/clay/shaders/clay_frag.glsl
@@ -0,0 +1,207 @@
+uniform vec2 screenres;
+uniform sampler2D depthtex;
+uniform mat4 WinMatrix;
+
+/* Matcap */
+uniform sampler2DArray matcaps;
+uniform vec3 matcaps_color[24];
+
+/* Screen Space Occlusion */
+/* store the view space vectors for the corners of the view frustum here.
+ * It helps to quickly reconstruct view space vectors by using uv coordinates,
+ * see http://www.derschmale.com/2014/01/26/reconstructing-positions-from-the-depth-buffer */
+uniform vec4 viewvecs[3];
+uniform vec4 ssao_params;
+
+uniform sampler2D ssao_jitter;
+uniform sampler1D ssao_samples;
+
+/* Material Parameters packed in an UBO */
+struct Material {
+ vec4 ssao_params_var;
+ vec4 matcap_hsv_id;
+ vec4 matcap_rot; /* vec4 to ensure 16 bytes alignement (don't trust compiler) */
+};
+
+layout(std140) uniform material_block {
+ Material matcaps_param[MAX_MATERIAL];
+};
+
+int mat_id;
+
+/* Aliases */
+#define ssao_samples_num ssao_params.x
+#define jitter_tilling ssao_params.yz
+#define dfdy_sign ssao_params.w
+
+#define matcap_hsv matcaps_param[mat_id].matcap_hsv_id.xyz
+#define matcap_index matcaps_param[mat_id].matcap_hsv_id.w
+#define matcap_rotation matcaps_param[mat_id].matcap_rot.xy
+
+in vec3 normal;
+out vec4 fragColor;
+
+/* TODO Move this to SSAO modules */
+/* simple depth reconstruction, see http://www.derschmale.com/2014/01/26/reconstructing-positions-from-the-depth-buffer
+ * we change the factors from the article to fit the OpennGL model. */
+vec3 get_view_space_from_depth(in vec2 uvcoords, in float depth)
+{
+ if (WinMatrix[3][3] == 0.0) {
+ /* Perspective */
+ float d = 2.0 * depth - 1.0;
+
+ float zview = -WinMatrix[3][2] / (d + WinMatrix[2][2]);
+
+ return zview * (viewvecs[0].xyz + vec3(uvcoords, 0.0) * viewvecs[1].xyz);
+ }
+ else {
+ /* Orthographic */
+ vec3 offset = vec3(uvcoords, depth);
+
+ return viewvecs[0].xyz + offset * viewvecs[1].xyz;
+ }
+}
+
+/* TODO remove this when switching to geometric normals */
+vec3 calculate_view_space_normal(in vec3 viewposition)
+{
+ vec3 normal = cross(normalize(dFdx(viewposition)), dfdy_sign * normalize(dFdy(viewposition)));
+ return normalize(normal);
+}
+
+#ifdef USE_HSV
+void rgb_to_hsv(vec3 rgb, out vec3 outcol)
+{
+ float cmax, cmin, h, s, v, cdelta;
+ vec3 c;
+
+ cmax = max(rgb[0], max(rgb[1], rgb[2]));
+ cmin = min(rgb[0], min(rgb[1], rgb[2]));
+ cdelta = cmax - cmin;
+
+ v = cmax;
+ if (cmax != 0.0)
+ s = cdelta / cmax;
+ else {
+ s = 0.0;
+ h = 0.0;
+ }
+
+ if (s == 0.0) {
+ h = 0.0;
+ }
+ else {
+ c = (vec3(cmax, cmax, cmax) - rgb.xyz) / cdelta;
+
+ if (rgb.x == cmax) h = c[2] - c[1];
+ else if (rgb.y == cmax) h = 2.0 + c[0] - c[2];
+ else h = 4.0 + c[1] - c[0];
+
+ h /= 6.0;
+
+ if (h < 0.0)
+ h += 1.0;
+ }
+
+ outcol = vec3(h, s, v);
+}
+
+void hsv_to_rgb(vec3 hsv, out vec3 outcol)
+{
+ float i, f, p, q, t, h, s, v;
+ vec3 rgb;
+
+ h = hsv[0];
+ s = hsv[1];
+ v = hsv[2];
+
+ if (s == 0.0) {
+ rgb = vec3(v, v, v);
+ }
+ else {
+ if (h == 1.0)
+ h = 0.0;
+
+ h *= 6.0;
+ i = floor(h);
+ f = h - i;
+ rgb = vec3(f, f, f);
+ p = v * (1.0 - s);
+ q = v * (1.0 - (s * f));
+ t = v * (1.0 - (s * (1.0 - f)));
+
+ if (i == 0.0) rgb = vec3(v, t, p);
+ else if (i == 1.0) rgb = vec3(q, v, p);
+ else if (i == 2.0) rgb = vec3(p, v, t);
+ else if (i == 3.0) rgb = vec3(p, q, v);
+ else if (i == 4.0) rgb = vec3(t, p, v);
+ else rgb = vec3(v, p, q);
+ }
+
+ outcol = rgb;
+}
+
+void hue_sat(float hue, float sat, float value, inout vec3 col)
+{
+ vec3 hsv;
+
+ rgb_to_hsv(col, hsv);
+
+ hsv.x += hue;
+ hsv.x -= floor(hsv.x);
+ hsv.y *= sat;
+ hsv.y = clamp(hsv.y, 0.0, 1.0);
+ hsv.z *= value;
+ hsv.z = clamp(hsv.z, 0.0, 1.0);
+
+ hsv_to_rgb(hsv, col);
+}
+#endif
+
+#ifdef USE_AO
+/* Prototype */
+void ssao_factors(in float depth, in vec3 normal, in vec3 position, in vec2 screenco, out float cavities, out float edges);
+#endif
+
+void main() {
+ vec2 screenco = vec2(gl_FragCoord.xy) / screenres;
+ float depth = texture(depthtex, screenco).r;
+
+ vec3 position = get_view_space_from_depth(screenco, depth);
+ vec3 normal = calculate_view_space_normal(position);
+
+ //mat_id = int(screenco.x*3.0);
+
+ /* Manual Depth test */
+ /* Doing this test earlier gives problem with dfdx calculations
+ * TODO move this before when we have proper geometric normals */
+ if (gl_FragCoord.z > depth + 1e-5)
+ discard;
+
+#ifdef USE_ROTATION
+ /* Rotate texture coordinates */
+ vec2 rotY = vec2(-matcap_rotation.y, matcap_rotation.x);
+ vec2 texco = abs(vec2(dot(normal.xy, matcap_rotation), dot(normal.xy, rotY)) * .49 + 0.5);
+#else
+ vec2 texco = abs(normal.xy * .49 + 0.5);
+#endif
+ vec3 col = texture(matcaps, vec3(texco, matcap_index)).rgb;
+
+#ifdef USE_AO
+ float cavity, edges;
+ ssao_factors(depth, normal, position, screenco, cavity, edges);
+
+ col *= mix(vec3(1.0), matcaps_color[int(matcap_index)], cavity);
+#endif
+
+#ifdef USE_HSV
+ hue_sat(matcap_hsv.x, matcap_hsv.y, matcap_hsv.z, col);
+#endif
+
+#ifdef USE_AO
+ /* Apply highlights after hue shift */
+ col *= edges + 1.0;
+#endif
+
+ fragColor = vec4(col, 1.0);
+}
diff --git a/source/blender/draw/engines/clay/shaders/clay_vert.glsl b/source/blender/draw/engines/clay/shaders/clay_vert.glsl
new file mode 100644
index 00000000000..0b598ea0291
--- /dev/null
+++ b/source/blender/draw/engines/clay/shaders/clay_vert.glsl
@@ -0,0 +1,20 @@
+uniform mat4 ModelViewProjectionMatrix;
+uniform mat3 NormalMatrix;
+
+#if __VERSION__ == 120
+attribute vec3 pos;
+attribute vec3 nor;
+varying vec3 normal;
+#else
+in vec3 pos;
+in vec3 nor;
+out vec3 normal;
+#endif
+
+
+void main()
+{
+ normal = normalize(NormalMatrix * nor);
+ gl_Position = ModelViewProjectionMatrix * vec4(pos, 1.0);
+}
+
diff --git a/source/blender/draw/engines/clay/shaders/ssao_alchemy.glsl b/source/blender/draw/engines/clay/shaders/ssao_alchemy.glsl
new file mode 100644
index 00000000000..d032fb91c01
--- /dev/null
+++ b/source/blender/draw/engines/clay/shaders/ssao_alchemy.glsl
@@ -0,0 +1,73 @@
+#define ssao_distance matcaps_param[mat_id].ssao_params_var.x
+#define ssao_factor_cavity matcaps_param[mat_id].ssao_params_var.y
+#define ssao_factor_edge matcaps_param[mat_id].ssao_params_var.z
+#define ssao_attenuation matcaps_param[mat_id].ssao_params_var.w
+
+/* from The Alchemy screen-space ambient obscurance algorithm
+ * http://graphics.cs.williams.edu/papers/AlchemyHPG11/VV11AlchemyAO.pdf */
+
+void ssao_factors(in float depth, in vec3 normal, in vec3 position, in vec2 screenco, out float cavities, out float edges)
+{
+ /* take the normalized ray direction here */
+ vec2 rotX = texture2D(ssao_jitter, screenco.xy * jitter_tilling).rg;
+ vec2 rotY = vec2(-rotX.y, rotX.x);
+
+ /* find the offset in screen space by multiplying a point
+ * in camera space at the depth of the point by the projection matrix. */
+ vec2 offset;
+ float homcoord = WinMatrix[2][3] * position.z + WinMatrix[3][3];
+ offset.x = WinMatrix[0][0] * ssao_distance / homcoord;
+ offset.y = WinMatrix[1][1] * ssao_distance / homcoord;
+ /* convert from -1.0...1.0 range to 0.0..1.0 for easy use with texture coordinates */
+ offset *= 0.5;
+
+ cavities = edges = 0.0;
+ int x;
+ int num_samples = int(ssao_samples_num);
+
+ for (x = 0; x < num_samples; x++) {
+ /* TODO : optimisation replace by constant */
+ vec2 dir_sample = texture1D(ssao_samples, (float(x) + 0.5) / ssao_samples_num).rg;
+
+ /* rotate with random direction to get jittered result */
+ vec2 dir_jittered = vec2(dot(dir_sample, rotX), dot(dir_sample, rotY));
+
+ vec2 uvcoords = screenco.xy + dir_jittered * offset;
+
+ if (uvcoords.x > 1.0 || uvcoords.x < 0.0 || uvcoords.y > 1.0 || uvcoords.y < 0.0)
+ continue;
+
+ float depth_new = texture2D(depthtex, uvcoords).r;
+
+ /* Handle Background case */
+ bool is_background = (depth_new == 1.0);
+
+ /* This trick provide good edge effect even if no neighboor is found. */
+ vec3 pos_new = get_view_space_from_depth(uvcoords, (is_background) ? depth : depth_new);
+
+ if (is_background)
+ pos_new.z -= ssao_distance;
+
+ vec3 dir = pos_new - position;
+ float len = length(dir);
+ float f_cavities = dot(dir, normal);
+ float f_edge = -f_cavities;
+ float f_bias = 0.05 * len + 0.0001;
+
+ float attenuation = 1.0 / (len * (1.0 + len * len * ssao_attenuation));
+
+ /* use minor bias here to avoid self shadowing */
+ if (f_cavities > -f_bias)
+ cavities += f_cavities * attenuation;
+
+ if (f_edge > f_bias)
+ edges += f_edge * attenuation;
+ }
+
+ cavities /= ssao_samples_num;
+ edges /= ssao_samples_num;
+
+ /* don't let cavity wash out the surface appearance */
+ cavities = clamp(cavities * ssao_factor_cavity, 0.0, 1.0);
+ edges = edges * ssao_factor_edge;
+}
diff --git a/source/blender/draw/engines/clay/shaders/ssao_groundtruth.glsl b/source/blender/draw/engines/clay/shaders/ssao_groundtruth.glsl
new file mode 100644
index 00000000000..2f29624824e
--- /dev/null
+++ b/source/blender/draw/engines/clay/shaders/ssao_groundtruth.glsl
@@ -0,0 +1,120 @@
+#define ssao_distance matcaps_param[mat_id].ssao_params_var.x
+#define ssao_factor_cavity matcaps_param[mat_id].ssao_params_var.y
+#define ssao_factor_edge matcaps_param[mat_id].ssao_params_var.z
+#define ssao_attenuation matcaps_param[mat_id].ssao_params_var.w
+
+/* Based on Practical Realtime Strategies for Accurate Indirect Occlusion
+ * http://blog.selfshadow.com/publications/s2016-shading-course/activision/s2016_pbs_activision_occlusion.pdf
+ * http://blog.selfshadow.com/publications/s2016-shading-course/activision/s2016_pbs_activision_occlusion.pptx */
+
+#define COSINE_WEIGHTING
+
+float integrate_arc(in float h1, in float h2, in float gamma, in float n_proj_len)
+{
+ float a = 0.0;
+#ifdef COSINE_WEIGHTING
+ float cos_gamma = cos(gamma);
+ float sin_gamma_2 = 2.0 * sin(gamma);
+ a += -cos(2.0 * h1 - gamma) + cos_gamma + h1 * sin_gamma_2;
+ a += -cos(2.0 * h2 - gamma) + cos_gamma + h2 * sin_gamma_2;
+ a *= 0.25; /* 1/4 */
+ a *= n_proj_len;
+#else
+ /* Uniform weighting (slide 59) */
+ a += 1 - cos(h1);
+ a += 1 - cos(h2);
+#endif
+ return a;
+}
+
+float get_max_horizon(in vec2 co, in vec3 x, in vec3 omega_o, in float h)
+{
+ if (co.x > 1.0 || co.x < 0.0 || co.y > 1.0 || co.y < 0.0)
+ return h;
+
+ float depth = texture2D(depthtex, co).r;
+
+ /* Background case */
+ if (depth == 1.0)
+ return h;
+
+ vec3 s = get_view_space_from_depth(co, depth); /* s View coordinate */
+ vec3 omega_s = s - x;
+ float len = length(omega_s);
+
+ if (len < ssao_distance) {
+ omega_s /= len;
+ h = max(h, dot(omega_s, omega_o));
+ }
+ return h;
+}
+
+void ssao_factors(in float depth, in vec3 normal, in vec3 position, in vec2 screenco, out float cavities, out float edges)
+{
+ /* Renaming */
+ vec3 omega_o = -normalize(position); /* viewvec */
+ vec2 x_ = screenco; /* x^ Screen coordinate */
+ vec3 x = position; /* x view space coordinate */
+
+#ifdef SPATIAL_DENOISE
+ float noise_dir = (1.0 / 16.0) * float(((int(gl_FragCoord.x + gl_FragCoord.y) & 0x3) << 2) + (int(gl_FragCoord.x) & 0x3));
+ float noise_offset = (1.0 / 4.0) * float(int(gl_FragCoord.y - gl_FragCoord.x) & 0x3);
+#else
+ float noise_dir = (1.0 / 16.0) * float(((int(gl_FragCoord.x + gl_FragCoord.y) & 0x3) << 2) + (int(gl_FragCoord.x) & 0x3));
+ float noise_offset = (0.5 / 16.0) + (1.0 / 16.0) * float(((int(gl_FragCoord.x - gl_FragCoord.y) & 0x3) << 2) + (int(gl_FragCoord.x) & 0x3));
+#endif
+
+ const float phi_step = 16.0;
+ const float theta_step = 16.0;
+ const float m_pi = 3.14159265358979323846;
+ vec2 pixel_ratio = vec2(screenres.y / screenres.x, 1.0);
+ vec2 pixel_size = vec2(1.0) / screenres.xy;
+ float min_stride = length(pixel_size);
+ float homcco = WinMatrix[2][3] * position.z + WinMatrix[3][3];
+ float n = max(min_stride * theta_step, ssao_distance / homcco); /* Search distance */
+
+ /* Integral over PI */
+ float A = 0.0;
+ for (float i = 0.0; i < phi_step; i++) {
+ float phi = m_pi * ((noise_dir + i) / phi_step);
+
+ vec2 t_phi = vec2(cos(phi), sin(phi)); /* Screen space direction */
+
+ /* Search maximum horizon angles Theta1 and Theta2 */
+ float theta1 = -1.0, theta2 = -1.0; /* init at cos(pi) */
+ for (float j = 0.0; j < theta_step; j++) {
+ vec2 s_ = t_phi * pixel_ratio * n * ((j + noise_offset)/ theta_step); /* s^ Screen coordinate */
+ vec2 co;
+
+ co = x_ + s_;
+ theta1 = get_max_horizon(co, x, omega_o, theta1);
+
+ co = x_ - s_;
+ theta2 = get_max_horizon(co, x, omega_o, theta2);
+ }
+
+ /* (Slide 54) */
+ theta1 = -acos(theta1);
+ theta2 = acos(theta2);
+
+ /* Projecting Normal to Plane P defined by t_phi and omega_o */
+ vec3 h = normalize(cross(vec3(t_phi, 0.0), omega_o)); /* Normal vector to Integration plane */
+ vec3 t = cross(h, omega_o); /* Normal vector to plane */
+ vec3 n_proj = normal - h * dot(normal, h);
+ float n_proj_len = length(n_proj);
+ vec3 n_proj_norm = normalize(n_proj);
+
+ /* Clamping thetas (slide 58) */
+ float gamma = sign(dot(n_proj_norm, t)) * acos(dot(normal, omega_o)); /* Angle between view vec and normal */
+ theta1 = gamma + max(theta1 - gamma, -m_pi * 0.5);
+ theta2 = gamma + min(theta2 - gamma, m_pi * 0.5);
+
+ /* Solving inner integral */
+ A += integrate_arc(theta1, theta2, gamma, n_proj_len);
+ }
+
+ A /= phi_step;
+
+ cavities = 1.0 - A;
+ edges = 0.0;
+} \ No newline at end of file
diff --git a/source/blender/draw/intern/DRW_render.h b/source/blender/draw/intern/DRW_render.h
new file mode 100644
index 00000000000..90412e65a51
--- /dev/null
+++ b/source/blender/draw/intern/DRW_render.h
@@ -0,0 +1,221 @@
+/*
+ * Copyright 2016, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contributor(s): Blender Institute
+ *
+ */
+
+/** \file DRW_render.h
+ * \ingroup draw
+ */
+
+/* This is the Render Functions used by Realtime engines to draw with OpenGL */
+
+#ifndef __DRW_RENDER_H__
+#define __DRW_RENDER_H__
+
+#include "BKE_context.h"
+#include "BKE_layer.h"
+#include "BKE_scene.h"
+
+#include "BLI_listbase.h"
+#include "BLI_math_matrix.h"
+#include "BLI_math_vector.h"
+#include "BLI_string.h"
+
+#include "BLT_translation.h"
+
+#include "DNA_object_types.h"
+#include "DNA_lamp_types.h"
+#include "DNA_material_types.h"
+#include "DNA_scene_types.h"
+
+#include "draw_mode_pass.h"
+#include "draw_cache.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "RE_engine.h"
+
+//#define WITH_VIEWPORT_CACHE_TEST
+
+struct GPUFrameBuffer;
+struct GPUShader;
+struct GPUTexture;
+struct GPUUniformBuffer;
+struct Object;
+struct Batch;
+
+typedef struct DRWUniform DRWUniform;
+typedef struct DRWInterface DRWInterface;
+typedef struct DRWPass DRWPass;
+typedef struct DRWShadingGroup DRWShadingGroup;
+
+/* Textures */
+
+typedef enum {
+ DRW_TEX_RGBA_8,
+ DRW_TEX_RGBA_16,
+ DRW_TEX_RGBA_32,
+ DRW_TEX_RGB_8,
+ DRW_TEX_RGB_16,
+ DRW_TEX_RGB_32,
+ DRW_TEX_RG_8,
+ DRW_TEX_RG_16,
+ DRW_TEX_RG_32,
+ DRW_TEX_R_8,
+ DRW_TEX_R_16,
+ DRW_TEX_R_32,
+ DRW_TEX_DEPTH_16,
+ DRW_TEX_DEPTH_24,
+ DRW_TEX_DEPTH_32,
+} DRWTextureFormat;
+
+typedef enum {
+ DRW_TEX_FILTER = (1 << 0),
+ DRW_TEX_WRAP = (1 << 1),
+ DRW_TEX_COMPARE = (1 << 2),
+} DRWTextureFlag;
+
+struct GPUTexture *DRW_texture_create_1D(
+ int w, DRWTextureFormat format, DRWTextureFlag flags, const float *fpixels);
+struct GPUTexture *DRW_texture_create_2D(
+ int w, int h, DRWTextureFormat format, DRWTextureFlag flags, const float *fpixels);
+struct GPUTexture *DRW_texture_create_2D_array(
+ int w, int h, int d, DRWTextureFormat UNUSED(format), DRWTextureFlag flags, const float *fpixels);
+void DRW_texture_free(struct GPUTexture *tex);
+
+/* UBOs */
+struct GPUUniformBuffer *DRW_uniformbuffer_create(int size, const void *data);
+void DRW_uniformbuffer_update(struct GPUUniformBuffer *ubo, const void *data);
+void DRW_uniformbuffer_free(struct GPUUniformBuffer *ubo);
+
+/* Buffers */
+
+/* DRWFboTexture->format */
+#define DRW_BUF_DEPTH_16 1
+#define DRW_BUF_DEPTH_24 2
+#define DRW_BUF_R_8 3
+#define DRW_BUF_R_16 4
+#define DRW_BUF_R_32 5
+#define DRW_BUF_RG_8 6
+#define DRW_BUF_RG_16 7
+#define DRW_BUF_RG_32 8
+#define DRW_BUF_RGB_8 9
+#define DRW_BUF_RGB_16 10
+#define DRW_BUF_RGB_32 11
+#define DRW_BUF_RGBA_8 12
+#define DRW_BUF_RGBA_16 13
+#define DRW_BUF_RGBA_32 14
+
+#define MAX_FBO_TEX 5
+
+typedef struct DRWFboTexture {
+ struct GPUTexture **tex;
+ int format;
+} DRWFboTexture;
+
+void DRW_framebuffer_init(struct GPUFrameBuffer **fb, int width, int height, DRWFboTexture textures[MAX_FBO_TEX], int texnbr);
+void DRW_framebuffer_bind(struct GPUFrameBuffer *fb);
+void DRW_framebuffer_texture_attach(struct GPUFrameBuffer *fb, struct GPUTexture *tex, int slot);
+void DRW_framebuffer_texture_detach(struct GPUTexture *tex);
+/* Shaders */
+struct GPUShader *DRW_shader_create(const char *vert, const char *geom, const char *frag, const char *defines);
+struct GPUShader *DRW_shader_create_2D(const char *frag, const char *defines);
+struct GPUShader *DRW_shader_create_3D(const char *frag, const char *defines);
+struct GPUShader *DRW_shader_create_3D_depth_only(void);
+void DRW_shader_free(struct GPUShader *shader);
+
+/* Batches */
+
+typedef enum {
+ DRW_STATE_WRITE_DEPTH = (1 << 0),
+ DRW_STATE_WRITE_COLOR = (1 << 1),
+ DRW_STATE_DEPTH_LESS = (1 << 2),
+ DRW_STATE_DEPTH_EQUAL = (1 << 3),
+ DRW_STATE_CULL_BACK = (1 << 4),
+ DRW_STATE_CULL_FRONT = (1 << 5),
+ DRW_STATE_WIRE = (1 << 6),
+ DRW_STATE_WIRE_LARGE = (1 << 7),
+ DRW_STATE_POINT = (1 << 8),
+ DRW_STATE_STIPPLE_2 = (1 << 9),
+ DRW_STATE_STIPPLE_3 = (1 << 10),
+ DRW_STATE_STIPPLE_4 = (1 << 11),
+ DRW_STATE_BLEND = (1 << 12),
+} DRWState;
+
+/* Used by DRWShadingGroup.dyntype */
+#define DRW_DYN_POINTS 1
+#define DRW_DYN_LINES 2
+#define DRW_DYN_INSTANCE 3
+
+DRWShadingGroup *DRW_shgroup_create(struct GPUShader *shader, DRWPass *pass);
+void DRW_shgroup_free(struct DRWShadingGroup *shgroup);
+void DRW_shgroup_call_add(DRWShadingGroup *shgroup, struct Batch *geom, float (*obmat)[4]);
+void DRW_shgroup_state_set(DRWShadingGroup *shgroup, DRWState state);
+void DRW_shgroup_dyntype_set(DRWShadingGroup *shgroup, int type);
+
+void DRW_shgroup_uniform_texture(DRWShadingGroup *shgroup, const char *name, const struct GPUTexture *tex, int loc);
+void DRW_shgroup_uniform_block(DRWShadingGroup *shgroup, const char *name, const struct GPUUniformBuffer *ubo, int loc);
+void DRW_shgroup_uniform_buffer(DRWShadingGroup *shgroup, const char *name, const int value, int loc);
+void DRW_shgroup_uniform_bool(DRWShadingGroup *shgroup, const char *name, const bool *value, int arraysize);
+void DRW_shgroup_uniform_float(DRWShadingGroup *shgroup, const char *name, const float *value, int arraysize);
+void DRW_shgroup_uniform_vec2(DRWShadingGroup *shgroup, const char *name, const float *value, int arraysize);
+void DRW_shgroup_uniform_vec3(DRWShadingGroup *shgroup, const char *name, const float *value, int arraysize);
+void DRW_shgroup_uniform_vec4(DRWShadingGroup *shgroup, const char *name, const float *value, int arraysize);
+void DRW_shgroup_uniform_int(DRWShadingGroup *shgroup, const char *name, const int *value, int arraysize);
+void DRW_shgroup_uniform_ivec2(DRWShadingGroup *shgroup, const char *name, const int *value, int arraysize);
+void DRW_shgroup_uniform_ivec3(DRWShadingGroup *shgroup, const char *name, const int *value, int arraysize);
+void DRW_shgroup_uniform_mat3(DRWShadingGroup *shgroup, const char *name, const float *value);
+void DRW_shgroup_uniform_mat4(DRWShadingGroup *shgroup, const char *name, const float *value);
+
+/* Passes */
+DRWPass *DRW_pass_create(const char *name, DRWState state);
+DRWShadingGroup *DRW_pass_nth_shgroup_get(DRWPass *pass, int n);
+
+/* Viewport */
+typedef enum {
+ DRW_MAT_PERS,
+ DRW_MAT_WIEW,
+ DRW_MAT_WIN,
+} DRWViewportMatrixType;
+
+void DRW_viewport_init(const bContext *C, void **buffers, void **textures, void **passes);
+void DRW_viewport_matrix_get(float mat[4][4], DRWViewportMatrixType type);
+float *DRW_viewport_size_get(void);
+float *DRW_viewport_screenvecs_get(void);
+float *DRW_viewport_pixelsize_get(void);
+bool DRW_viewport_is_persp_get(void);
+bool DRW_viewport_cache_is_dirty(void);
+
+/* Settings */
+#ifndef __DRW_ENGINE_H__
+void *DRW_material_settings_get(Material *ma, const char *engine_name);
+void *DRW_render_settings_get(Scene *scene, const char *engine_name);
+#endif /* __DRW_ENGINE_H__ */
+
+/* Draw commands */
+void DRW_draw_background(void);
+void DRW_centercircle(const float co[3]);
+void DRW_draw_pass(DRWPass *pass);
+
+void DRW_state_reset(void);
+
+/* Other */
+void DRW_get_dfdy_factors(float dfdyfac[2]);
+
+#endif /* __DRW_RENDER_H__ */ \ No newline at end of file
diff --git a/source/blender/draw/intern/draw_cache.c b/source/blender/draw/intern/draw_cache.c
new file mode 100644
index 00000000000..1255a083b82
--- /dev/null
+++ b/source/blender/draw/intern/draw_cache.c
@@ -0,0 +1,543 @@
+/*
+ * Copyright 2016, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contributor(s): Blender Institute
+ *
+ */
+
+/** \file draw_cache.c
+ * \ingroup draw
+ */
+
+
+#include "DNA_scene_types.h"
+#include "DNA_mesh_types.h"
+#include "DNA_object_types.h"
+
+#include "BLI_utildefines.h"
+#include "BLI_math.h"
+
+#include "BKE_mesh_render.h"
+
+#include "GPU_batch.h"
+
+#include "draw_cache.h"
+
+static struct DRWShapeCache{
+ Batch *drw_single_vertice;
+ Batch *drw_fullscreen_quad;
+ Batch *drw_plain_axes;
+ Batch *drw_single_arrow;
+ Batch *drw_single_arrow_line;
+ Batch *drw_cube;
+ Batch *drw_circle;
+ Batch *drw_empty_sphere;
+ Batch *drw_empty_cone;
+ Batch *drw_arrows;
+ Batch *drw_lamp;
+ Batch *drw_lamp_sunrays;
+} SHC = {NULL};
+
+void DRW_shape_cache_free(void)
+{
+ if (SHC.drw_single_vertice)
+ Batch_discard_all(SHC.drw_single_vertice);
+ if (SHC.drw_fullscreen_quad)
+ Batch_discard_all(SHC.drw_fullscreen_quad);
+ if (SHC.drw_plain_axes)
+ Batch_discard_all(SHC.drw_plain_axes);
+ if (SHC.drw_single_arrow)
+ Batch_discard_all(SHC.drw_single_arrow);
+ if (SHC.drw_single_arrow_line)
+ Batch_discard_all(SHC.drw_single_arrow_line);
+ if (SHC.drw_cube)
+ Batch_discard_all(SHC.drw_cube);
+ if (SHC.drw_circle)
+ Batch_discard_all(SHC.drw_circle);
+ if (SHC.drw_empty_sphere)
+ Batch_discard_all(SHC.drw_empty_sphere);
+ if (SHC.drw_empty_cone)
+ Batch_discard_all(SHC.drw_empty_cone);
+ if (SHC.drw_arrows)
+ Batch_discard_all(SHC.drw_arrows);
+ if (SHC.drw_lamp)
+ Batch_discard_all(SHC.drw_lamp);
+ if (SHC.drw_lamp_sunrays)
+ Batch_discard_all(SHC.drw_lamp_sunrays);
+}
+
+/* Quads */
+Batch *DRW_cache_fullscreen_quad_get(void)
+{
+ if (!SHC.drw_fullscreen_quad) {
+ float v1[2] = {-1.0f, -1.0f};
+ float v2[2] = { 1.0f, -1.0f};
+ float v3[2] = {-1.0f, 1.0f};
+ float v4[2] = { 1.0f, 1.0f};
+
+ /* Position Only 3D format */
+ static VertexFormat format = { 0 };
+ static unsigned pos_id;
+ if (format.attrib_ct == 0) {
+ pos_id = add_attrib(&format, "pos", GL_FLOAT, 3, KEEP_FLOAT);
+ }
+
+ VertexBuffer *vbo = VertexBuffer_create_with_format(&format);
+ VertexBuffer_allocate_data(vbo, 6);
+
+ setAttrib(vbo, pos_id, 0, v1);
+ setAttrib(vbo, pos_id, 1, v2);
+ setAttrib(vbo, pos_id, 2, v3);
+
+ setAttrib(vbo, pos_id, 3, v2);
+ setAttrib(vbo, pos_id, 4, v3);
+ setAttrib(vbo, pos_id, 5, v4);
+
+ SHC.drw_fullscreen_quad = Batch_create(GL_TRIANGLES, vbo, NULL);
+ }
+ return SHC.drw_fullscreen_quad;
+}
+
+/* Common */
+
+Batch *DRW_cache_cube_get(void)
+{
+ if (!SHC.drw_cube) {
+ const GLfloat verts[8][3] = {
+ {-1.0f, -1.0f, -1.0f},
+ {-1.0f, -1.0f, 1.0f},
+ {-1.0f, 1.0f, -1.0f},
+ {-1.0f, 1.0f, 1.0f},
+ { 1.0f, -1.0f, -1.0f},
+ { 1.0f, -1.0f, 1.0f},
+ { 1.0f, 1.0f, -1.0f},
+ { 1.0f, 1.0f, 1.0f}
+ };
+
+ const GLubyte indices[24] = {0,1,1,3,3,2,2,0,0,4,4,5,5,7,7,6,6,4,1,5,3,7,2,6};
+
+ /* Position Only 3D format */
+ static VertexFormat format = { 0 };
+ static unsigned pos_id;
+ if (format.attrib_ct == 0) {
+ pos_id = add_attrib(&format, "pos", GL_FLOAT, 3, KEEP_FLOAT);
+ }
+
+ VertexBuffer *vbo = VertexBuffer_create_with_format(&format);
+ VertexBuffer_allocate_data(vbo, 24);
+
+ for (int i = 0; i < 24; ++i) {
+ setAttrib(vbo, pos_id, i, verts[indices[i]]);
+ }
+
+ SHC.drw_cube = Batch_create(GL_LINES, vbo, NULL);
+ }
+ return SHC.drw_cube;
+}
+
+
+Batch *DRW_cache_circle_get(void)
+{
+#define CIRCLE_RESOL 32
+ if (!SHC.drw_circle) {
+ float v[3] = {0.0f, 0.0f, 0.0f};
+
+ /* Position Only 3D format */
+ static VertexFormat format = { 0 };
+ static unsigned pos_id;
+ if (format.attrib_ct == 0) {
+ pos_id = add_attrib(&format, "pos", GL_FLOAT, 3, KEEP_FLOAT);
+ }
+
+ VertexBuffer *vbo = VertexBuffer_create_with_format(&format);
+ VertexBuffer_allocate_data(vbo, CIRCLE_RESOL * 2);
+
+ for (int a = 0; a < CIRCLE_RESOL; a++) {
+ v[0] = sinf((2.0f * M_PI * a) / ((float)CIRCLE_RESOL));
+ v[1] = cosf((2.0f * M_PI * a) / ((float)CIRCLE_RESOL));
+ v[2] = 0.0f;
+ setAttrib(vbo, pos_id, a * 2, v);
+
+ v[0] = sinf((2.0f * M_PI * (a + 1)) / ((float)CIRCLE_RESOL));
+ v[1] = cosf((2.0f * M_PI * (a + 1)) / ((float)CIRCLE_RESOL));
+ v[2] = 0.0f;
+ setAttrib(vbo, pos_id, a * 2 + 1, v);
+ }
+
+ SHC.drw_circle = Batch_create(GL_LINES, vbo, NULL);
+ }
+ return SHC.drw_circle;
+#undef CIRCLE_RESOL
+}
+
+/* Empties */
+Batch *DRW_cache_plain_axes_get(void)
+{
+ if (!SHC.drw_plain_axes) {
+ int axis;
+ float v1[3] = {0.0f, 0.0f, 0.0f};
+ float v2[3] = {0.0f, 0.0f, 0.0f};
+
+ /* Position Only 3D format */
+ static VertexFormat format = { 0 };
+ static unsigned pos_id;
+ if (format.attrib_ct == 0) {
+ pos_id = add_attrib(&format, "pos", GL_FLOAT, 3, KEEP_FLOAT);
+ }
+
+ VertexBuffer *vbo = VertexBuffer_create_with_format(&format);
+ VertexBuffer_allocate_data(vbo, 6);
+
+ for (axis = 0; axis < 3; axis++) {
+ v1[axis] = 1.0f;
+ v2[axis] = -1.0f;
+
+ setAttrib(vbo, pos_id, axis * 2, v1);
+ setAttrib(vbo, pos_id, axis * 2 + 1, v2);
+
+ /* reset v1 & v2 to zero for next axis */
+ v1[axis] = v2[axis] = 0.0f;
+ }
+
+ SHC.drw_plain_axes = Batch_create(GL_LINES, vbo, NULL);
+ }
+ return SHC.drw_plain_axes;
+}
+
+Batch *DRW_cache_single_arrow_get(Batch **line)
+{
+ if (!SHC.drw_single_arrow_line || !SHC.drw_single_arrow) {
+ float v1[3] = {0.0f, 0.0f, 0.0f}, v2[3], v3[3];
+
+ /* Position Only 3D format */
+ static VertexFormat format = { 0 };
+ static unsigned pos_id;
+ if (format.attrib_ct == 0) {
+ pos_id = add_attrib(&format, "pos", GL_FLOAT, 3, KEEP_FLOAT);
+ }
+
+ /* Line */
+ VertexBuffer *vbo = VertexBuffer_create_with_format(&format);
+ VertexBuffer_allocate_data(vbo, 2);
+
+ setAttrib(vbo, pos_id, 0, v1);
+ v1[2] = 1.0f;
+ setAttrib(vbo, pos_id, 1, v1);
+
+ SHC.drw_single_arrow_line = Batch_create(GL_LINES, vbo, NULL);
+
+ /* Square Pyramid */
+ vbo = VertexBuffer_create_with_format(&format);
+ VertexBuffer_allocate_data(vbo, 12);
+
+ v2[0] = 0.035f; v2[1] = 0.035f;
+ v3[0] = -0.035f; v3[1] = 0.035f;
+ v2[2] = v3[2] = 0.75f;
+
+ for (int sides = 0; sides < 4; sides++) {
+ if (sides % 2 == 1) {
+ v2[0] = -v2[0];
+ v3[1] = -v3[1];
+ }
+ else {
+ v2[1] = -v2[1];
+ v3[0] = -v3[0];
+ }
+
+ setAttrib(vbo, pos_id, sides * 3 + 0, v1);
+ setAttrib(vbo, pos_id, sides * 3 + 1, v2);
+ setAttrib(vbo, pos_id, sides * 3 + 2, v3);
+ }
+
+ SHC.drw_single_arrow = Batch_create(GL_TRIANGLES, vbo, NULL);
+ }
+ *line = SHC.drw_single_arrow_line;
+ return SHC.drw_single_arrow;
+}
+
+Batch *DRW_cache_empty_sphere_get(void)
+{
+#define NSEGMENTS 16
+ if (!SHC.drw_empty_sphere) {
+ /* a single ring of vertices */
+ float p[NSEGMENTS][2];
+ for (int i = 0; i < NSEGMENTS; ++i) {
+ float angle = 2 * M_PI * ((float)i / (float)NSEGMENTS);
+ p[i][0] = cosf(angle);
+ p[i][1] = sinf(angle);
+ }
+
+ /* Position Only 3D format */
+ static VertexFormat format = { 0 };
+ static unsigned pos_id;
+ if (format.attrib_ct == 0) {
+ pos_id = add_attrib(&format, "pos", GL_FLOAT, 3, KEEP_FLOAT);
+ }
+
+ VertexBuffer *vbo = VertexBuffer_create_with_format(&format);
+ VertexBuffer_allocate_data(vbo, NSEGMENTS * 2 * 3);
+
+ for (int axis = 0; axis < 3; ++axis) {
+ for (int i = 0; i < NSEGMENTS; ++i) {
+ for (int j = 0; j < 2; ++j) {
+ float cv[2], v[3];
+
+ cv[0] = p[(i+j) % NSEGMENTS][0];
+ cv[1] = p[(i+j) % NSEGMENTS][1];
+
+ if (axis == 0)
+ v[0] = cv[0], v[1] = cv[1], v[2] = 0.0f;
+ else if (axis == 1)
+ v[0] = cv[0], v[1] = 0.0f, v[2] = cv[1];
+ else
+ v[0] = 0.0f, v[1] = cv[0], v[2] = cv[1];
+
+ setAttrib(vbo, pos_id, i*2 + j + (NSEGMENTS * 2 * axis), v);
+ }
+ }
+ }
+
+ SHC.drw_empty_sphere = Batch_create(GL_LINES, vbo, NULL);
+ }
+ return SHC.drw_empty_sphere;
+#undef NSEGMENTS
+}
+
+Batch *DRW_cache_empty_cone_get(void)
+{
+#define NSEGMENTS 8
+ if (!SHC.drw_empty_cone) {
+ /* a single ring of vertices */
+ float p[NSEGMENTS][2];
+ for (int i = 0; i < NSEGMENTS; ++i) {
+ float angle = 2 * M_PI * ((float)i / (float)NSEGMENTS);
+ p[i][0] = cosf(angle);
+ p[i][1] = sinf(angle);
+ }
+
+ /* Position Only 3D format */
+ static VertexFormat format = { 0 };
+ static unsigned pos_id;
+ if (format.attrib_ct == 0) {
+ pos_id = add_attrib(&format, "pos", GL_FLOAT, 3, KEEP_FLOAT);
+ }
+
+ VertexBuffer *vbo = VertexBuffer_create_with_format(&format);
+ VertexBuffer_allocate_data(vbo, NSEGMENTS * 4);
+
+ for (int i = 0; i < NSEGMENTS; ++i) {
+ float cv[2], v[3];
+ cv[0] = p[(i) % NSEGMENTS][0];
+ cv[1] = p[(i) % NSEGMENTS][1];
+
+ /* cone sides */
+ v[0] = cv[0], v[1] = 0.0f, v[2] = cv[1];
+ setAttrib(vbo, pos_id, i*4, v);
+ v[0] = 0.0f, v[1] = 2.0f, v[2] = 0.0f;
+ setAttrib(vbo, pos_id, i*4 + 1, v);
+
+ /* end ring */
+ v[0] = cv[0], v[1] = 0.0f, v[2] = cv[1];
+ setAttrib(vbo, pos_id, i*4 + 2, v);
+ cv[0] = p[(i+1) % NSEGMENTS][0];
+ cv[1] = p[(i+1) % NSEGMENTS][1];
+ v[0] = cv[0], v[1] = 0.0f, v[2] = cv[1];
+ setAttrib(vbo, pos_id, i*4 + 3, v);
+ }
+
+ SHC.drw_empty_cone = Batch_create(GL_LINES, vbo, NULL);
+ }
+ return SHC.drw_empty_cone;
+#undef NSEGMENTS
+}
+
+Batch *DRW_cache_arrows_get(void)
+{
+ if (!SHC.drw_arrows) {
+ float v1[3] = {0.0, 0.0, 0.0};
+ float v2[3] = {0.0, 0.0, 0.0};
+
+ /* Position Only 3D format */
+ static VertexFormat format = { 0 };
+ static unsigned pos_id;
+ if (format.attrib_ct == 0) {
+ pos_id = add_attrib(&format, "pos", GL_FLOAT, 3, KEEP_FLOAT);
+ }
+
+ /* Line */
+ VertexBuffer *vbo = VertexBuffer_create_with_format(&format);
+ VertexBuffer_allocate_data(vbo, 6 * 3);
+
+ for (int axis = 0; axis < 3; axis++) {
+ const int arrow_axis = (axis == 0) ? 1 : 0;
+
+ v2[axis] = 1.0f;
+ setAttrib(vbo, pos_id, axis * 6 + 0, v1);
+ setAttrib(vbo, pos_id, axis * 6 + 1, v2);
+
+ v1[axis] = 0.85f;
+ v1[arrow_axis] = -0.08f;
+ setAttrib(vbo, pos_id, axis * 6 + 2, v1);
+ setAttrib(vbo, pos_id, axis * 6 + 3, v2);
+
+ v1[arrow_axis] = 0.08f;
+ setAttrib(vbo, pos_id, axis * 6 + 4, v1);
+ setAttrib(vbo, pos_id, axis * 6 + 5, v2);
+
+ /* reset v1 & v2 to zero */
+ v1[arrow_axis] = v1[axis] = v2[axis] = 0.0f;
+ }
+
+ SHC.drw_arrows = Batch_create(GL_LINES, vbo, NULL);
+ }
+ return SHC.drw_arrows;
+}
+
+/* Lamps */
+Batch *DRW_cache_lamp_get(void)
+{
+#define NSEGMENTS 8
+ if (!SHC.drw_lamp) {
+ float v[2];
+
+ /* Position Only 3D format */
+ static VertexFormat format = { 0 };
+ static unsigned pos_id;
+ if (format.attrib_ct == 0) {
+ pos_id = add_attrib(&format, "pos", GL_FLOAT, 2, KEEP_FLOAT);
+ }
+
+ VertexBuffer *vbo = VertexBuffer_create_with_format(&format);
+ VertexBuffer_allocate_data(vbo, NSEGMENTS * 2);
+
+ for (int a = 0; a < NSEGMENTS; a++) {
+ v[0] = sinf((2.0f * M_PI * a) / ((float)NSEGMENTS));
+ v[1] = cosf((2.0f * M_PI * a) / ((float)NSEGMENTS));
+ setAttrib(vbo, pos_id, a * 2, v);
+
+ v[0] = sinf((2.0f * M_PI * (a + 1)) / ((float)NSEGMENTS));
+ v[1] = cosf((2.0f * M_PI * (a + 1)) / ((float)NSEGMENTS));
+ setAttrib(vbo, pos_id, a * 2 + 1, v);
+ }
+
+ SHC.drw_lamp = Batch_create(GL_LINES, vbo, NULL);
+ }
+ return SHC.drw_lamp;
+#undef NSEGMENTS
+}
+
+Batch *DRW_cache_lamp_sunrays_get(void)
+{
+ if (!SHC.drw_lamp_sunrays) {
+ float v[2], v1[2], v2[2];
+
+ /* Position Only 3D format */
+ static VertexFormat format = { 0 };
+ static unsigned pos_id;
+ if (format.attrib_ct == 0) {
+ pos_id = add_attrib(&format, "pos", GL_FLOAT, 2, KEEP_FLOAT);
+ }
+
+ VertexBuffer *vbo = VertexBuffer_create_with_format(&format);
+ VertexBuffer_allocate_data(vbo, 16);
+
+ for (int a = 0; a < 8; a++) {
+ v[0] = sinf((2.0f * M_PI * a) / 8.0f);
+ v[1] = cosf((2.0f * M_PI * a) / 8.0f);
+
+ mul_v2_v2fl(v1, v, 1.2f);
+ mul_v2_v2fl(v2, v, 2.5f);
+
+ setAttrib(vbo, pos_id, a * 2, v1);
+ setAttrib(vbo, pos_id, a * 2 + 1, v2);
+ }
+
+ SHC.drw_lamp_sunrays = Batch_create(GL_LINES, vbo, NULL);
+ }
+ return SHC.drw_lamp_sunrays;
+}
+
+
+/* Object Center */
+Batch *DRW_cache_single_vert_get(void)
+{
+ if (!SHC.drw_single_vertice) {
+ float v1[3] = {0.0f, 0.0f, 0.0f};
+
+ /* Position Only 3D format */
+ static VertexFormat format = { 0 };
+ static unsigned pos_id;
+ if (format.attrib_ct == 0) {
+ pos_id = add_attrib(&format, "pos", GL_FLOAT, 3, KEEP_FLOAT);
+ }
+
+ VertexBuffer *vbo = VertexBuffer_create_with_format(&format);
+ VertexBuffer_allocate_data(vbo, 1);
+
+ setAttrib(vbo, pos_id, 0, v1);
+
+ SHC.drw_single_vertice = Batch_create(GL_POINTS, vbo, NULL);
+ }
+ return SHC.drw_single_vertice;
+}
+
+/* Meshes */
+Batch *DRW_cache_wire_overlay_get(Object *ob)
+{
+ Batch *overlay_wire = NULL;
+
+ BLI_assert(ob->type == OB_MESH);
+
+ Mesh *me = ob->data;
+#if 1 /* new version not working */
+ overlay_wire = BKE_mesh_batch_cache_get_overlay_edges(me);
+#else
+ overlay_wire = BKE_mesh_batch_cache_get_all_edges(me);
+#endif
+ return overlay_wire;
+}
+
+Batch *DRW_cache_wire_outline_get(Object *ob)
+{
+ Batch *fancy_wire = NULL;
+
+ BLI_assert(ob->type == OB_MESH);
+
+ Mesh *me = ob->data;
+ fancy_wire = BKE_mesh_batch_cache_get_fancy_edges(me);
+
+ return fancy_wire;
+}
+
+Batch *DRW_cache_surface_get(Object *ob)
+{
+ Batch *surface = NULL;
+
+ BLI_assert(ob->type == OB_MESH);
+
+ Mesh *me = ob->data;
+ surface = BKE_mesh_batch_cache_get_all_triangles(me);
+
+ return surface;
+}
+
+#if 0 /* TODO */
+struct Batch *DRW_cache_surface_material_get(Object *ob, int nr) {
+ /* TODO */
+ return NULL;
+}
+#endif \ No newline at end of file
diff --git a/source/blender/draw/intern/draw_cache.h b/source/blender/draw/intern/draw_cache.h
new file mode 100644
index 00000000000..c53f3d88af3
--- /dev/null
+++ b/source/blender/draw/intern/draw_cache.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2016, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contributor(s): Blender Institute
+ *
+ */
+
+/** \file draw_cache.h
+ * \ingroup draw
+ */
+
+#ifndef __DRAW_CACHE_H__
+#define __DRAW_CACHE_H__
+
+struct Batch;
+struct Object;
+
+void DRW_shape_cache_free(void);
+
+/* Common Shapes */
+struct Batch *DRW_cache_fullscreen_quad_get(void);
+struct Batch *DRW_cache_single_vert_get(void);
+
+/* Empties */
+struct Batch *DRW_cache_plain_axes_get(void);
+struct Batch *DRW_cache_single_arrow_get(struct Batch **line);
+struct Batch *DRW_cache_cube_get(void);
+struct Batch *DRW_cache_circle_get(void);
+struct Batch *DRW_cache_empty_sphere_get(void);
+struct Batch *DRW_cache_empty_cone_get(void);
+struct Batch *DRW_cache_arrows_get(void);
+
+/* Lamps */
+struct Batch *DRW_cache_lamp_get(void);
+struct Batch *DRW_cache_lamp_sunrays_get(void);
+
+/* Meshes */
+struct Batch *DRW_cache_wire_overlay_get(struct Object *ob);
+struct Batch *DRW_cache_wire_outline_get(struct Object *ob);
+struct Batch *DRW_cache_surface_get(struct Object *ob);
+
+#endif /* __DRAW_CACHE_H__ */ \ No newline at end of file
diff --git a/source/blender/draw/intern/draw_manager.c b/source/blender/draw/intern/draw_manager.c
new file mode 100644
index 00000000000..729d9d19ce8
--- /dev/null
+++ b/source/blender/draw/intern/draw_manager.c
@@ -0,0 +1,1142 @@
+/*
+ * Copyright 2016, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contributor(s): Blender Institute
+ *
+ */
+
+/** \file blender/draw/draw_manager.c
+ * \ingroup draw
+ */
+
+#include <stdio.h>
+
+#include "BLI_listbase.h"
+#include "BLI_rect.h"
+#include "BLI_string.h"
+
+#include "BIF_glutil.h"
+
+#include "BKE_global.h"
+
+#include "BLT_translation.h"
+
+#include "DRW_engine.h"
+#include "DRW_render.h"
+
+#include "DNA_view3d_types.h"
+
+#include "GPU_basic_shader.h"
+#include "GPU_batch.h"
+#include "GPU_draw.h"
+#include "GPU_extensions.h"
+#include "GPU_framebuffer.h"
+#include "GPU_immediate.h"
+#include "GPU_matrix.h"
+#include "GPU_shader.h"
+#include "GPU_texture.h"
+#include "GPU_uniformbuffer.h"
+#include "GPU_viewport.h"
+
+#include "RE_engine.h"
+
+#include "UI_resources.h"
+
+#include "clay.h"
+
+extern char datatoc_gpu_shader_2D_vert_glsl[];
+extern char datatoc_gpu_shader_3D_vert_glsl[];
+extern char datatoc_gpu_shader_basic_vert_glsl[];
+
+/* Structures */
+typedef enum {
+ DRW_UNIFORM_BOOL,
+ DRW_UNIFORM_INT,
+ DRW_UNIFORM_FLOAT,
+ DRW_UNIFORM_TEXTURE,
+ DRW_UNIFORM_BUFFER,
+ DRW_UNIFORM_MAT3,
+ DRW_UNIFORM_MAT4,
+ DRW_UNIFORM_BLOCK
+} DRWUniformType;
+
+struct DRWUniform {
+ struct DRWUniform *next, *prev;
+ DRWUniformType type;
+ int location;
+ int length;
+ int arraysize;
+ int bindloc;
+ const void *value;
+};
+
+struct DRWInterface {
+ ListBase uniforms;
+ /* matrices locations */
+ int modelview;
+ int projection;
+ int modelviewprojection;
+ int viewprojection;
+ int normal;
+ int eye;
+};
+
+struct DRWPass {
+ ListBase shgroups;
+ DRWState state;
+ float state_param; /* Line / Point width */
+};
+
+typedef struct DRWCall {
+ struct DRWCall *next, *prev;
+ Batch *geometry;
+ float(*obmat)[4];
+} DRWCall;
+
+struct DRWShadingGroup {
+ struct DRWShadingGroup *next, *prev;
+ struct GPUShader *shader; /* Shader to bind */
+ struct DRWInterface *interface; /* Uniforms pointers */
+ ListBase calls; /* List with all geometry and transforms */
+ int state; /* State changes for this batch only */
+ short dyntype; /* Dynamic Batch type, 0 is normal */
+ Batch *dyngeom; /* Dynamic batch */
+ GLuint instance_vbo; /* Dynamic batch VBO storing Model Matrices */
+ int instance_count; /* Dynamic batch Number of instance to render */
+};
+
+/* Render State */
+static struct DRWGlobalState{
+ GPUShader *shader;
+ struct GPUFrameBuffer *default_framebuffer;
+ FramebufferList *current_fbl;
+ TextureList *current_txl;
+ PassList *current_psl;
+ ListBase bound_texs;
+ int tex_bind_id;
+ float size[2];
+ float screenvecs[2][3];
+ float pixsize;
+ /* Current rendering context set by DRW_viewport_init */
+ const struct bContext *context;
+} DST = {NULL};
+
+/* ***************************************** TEXTURES ******************************************/
+static void drw_texture_get_format(DRWTextureFormat format, GPUFormat *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_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_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;
+ case DRW_TEX_R_16: *data_type = GPU_R16F; break;
+ case DRW_TEX_R_32: *data_type = GPU_R32F; break;
+ 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;
+ }
+
+ 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;
+ GPUFormat 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;
+ GPUFormat 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/drawvolume.c b/source/blender/editors/space_view3d/drawvolume.c
index 27ecbf83db5..debdcb58d71 100644
--- a/source/blender/editors/space_view3d/drawvolume.c
+++ b/source/blender/editors/space_view3d/drawvolume.c
@@ -160,7 +160,7 @@ static GPUTexture *create_field_texture(SmokeDomainSettings *sds)
default: return NULL;
}
- return GPU_texture_create_3D(sds->res[0], sds->res[1], sds->res[2], 1, field);
+ return GPU_texture_create_3D_custom(sds->res[0], sds->res[1], sds->res[2], 1, GPU_R8, field, NULL);
}
typedef struct VolumeSlicer {
diff --git a/source/blender/editors/space_view3d/space_view3d.c b/source/blender/editors/space_view3d/space_view3d.c
index ddaba639fbc..6021f705035 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 21a7e26998e..f428b2cec47 100644
--- a/source/blender/editors/space_view3d/view3d_draw.c
+++ b/source/blender/editors/space_view3d/view3d_draw.c
@@ -2096,12 +2096,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;
}
@@ -2109,12 +2139,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 504a8383a41..71d6a47c41c 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_texture.h b/source/blender/gpu/GPU_texture.h
index 756fe79151b..3ddeb9c1f44 100644
--- a/source/blender/gpu/GPU_texture.h
+++ b/source/blender/gpu/GPU_texture.h
@@ -55,25 +55,101 @@ typedef struct GPUTexture GPUTexture;
* - if created with from_blender, will not free the texture
*/
-typedef enum GPUHDRType {
- GPU_HDR_NONE = 0,
- GPU_HDR_HALF_FLOAT = 1,
- GPU_HDR_FULL_FLOAT = (1 << 1),
-} GPUHDRType;
+/* From OpenGl 3.3 specification */
+typedef enum GPUFormat {
+ /* Formats texture & renderbuffer */
+ GPU_RGBA32F,
+ GPU_RGBA32I,
+ GPU_RGBA32UI,
+ GPU_RGBA16,
+ GPU_RGBA16F,
+ GPU_RGBA16I,
+ GPU_RGBA16UI,
+ GPU_RGBA8,
+ GPU_RGBA8I,
+ GPU_RGBA8UI,
+ GPU_RG32F,
+ GPU_RG32I,
+ GPU_RG32UI,
+ GPU_RG16,
+ GPU_RG16F,
+ GPU_RG16I,
+ GPU_RG16UI,
+ GPU_RG8,
+ GPU_RG8I,
+ GPU_RG8UI,
+ GPU_R32F,
+ GPU_R32I,
+ GPU_R32UI,
+ GPU_R16F,
+ GPU_R16I,
+ GPU_R16UI,
+ GPU_R16,
+ GPU_R8,
+ GPU_R8I,
+ GPU_R8UI,
+
+ /* Special formats texture & renderbuffer */
+ GPU_R11F_G11F_B10F,
+ GPU_RGB10_A2,
+ GPU_RGB10_A2UI,
+ GPU_DEPTH32F_STENCIL8,
+ GPU_DEPTH24_STENCIL8,
+
+ /* Texture only format */
+ GPU_RGBA16_SNORM,
+ GPU_RGBA8_SNORM,
+ GPU_RGB32F,
+ GPU_RGB32I,
+ GPU_RGB32UI,
+ GPU_RGB16_SNORM,
+ GPU_RGB16F,
+ GPU_RGB16I,
+ GPU_RGB16UI,
+ GPU_RGB16,
+ GPU_RGB8_SNORM,
+ GPU_RGB8,
+ GPU_RGB8I,
+ GPU_RGB8UI,
+ GPU_RG16_SNORM,
+ GPU_RG8_SNORM,
+ GPU_R16_SNORM,
+ GPU_R8_SNORM,
+
+ /* Special formats texture only */
+ GPU_SRGB8_A8,
+ GPU_SRGB8,
+ GPU_RGB9_E5,
+ GPU_COMPRESSED_RG_RGTC2,
+ GPU_COMPRESSED_SIGNED_RG_RGTC2,
+ GPU_COMPRESSED_RED_RGTC1,
+ GPU_COMPRESSED_SIGNED_RED_RGTC1,
+
+ /* Depth Formats */
+ GPU_DEPTH_COMPONENT32F,
+ GPU_DEPTH_COMPONENT24,
+ GPU_DEPTH_COMPONENT16,
+} GPUFormat;
GPUTexture *GPU_texture_create_1D(int w, const float *pixels, char err_out[256]);
-GPUTexture *GPU_texture_create_2D(int w, int h, const float *pixels, GPUHDRType hdr, char err_out[256]);
-GPUTexture *GPU_texture_create_3D(int w, int h, int depth, int channels, const float *fpixels);
+GPUTexture *GPU_texture_create_1D_custom(
+ int w, int channels, GPUFormat data_type, const float *pixels, char err_out[256]);
+GPUTexture *GPU_texture_create_2D(int w, int h, const float *pixels, char err_out[256]);
+GPUTexture *GPU_texture_create_2D_custom(
+ int w, int h, int channels, GPUFormat data_type, const float *pixels, char err_out[256]);
+GPUTexture *GPU_texture_create_2D_multisample(int w, int h, const float *pixels, int samples, char err_out[256]);
+GPUTexture *GPU_texture_create_2D_array(int w, int h, int d, const float *pixels, char err_out[256]);
+GPUTexture *GPU_texture_create_3D(int w, int h, int d, const float *pixels, char err_out[256]);
+GPUTexture *GPU_texture_create_3D_custom(
+ int w, int h, int d, int channels, GPUFormat data_type, const float *pixels, char err_out[256]);
GPUTexture *GPU_texture_create_depth(int w, int h, char err_out[256]);
-GPUTexture *GPU_texture_create_vsm_shadow_map(int size, char err_out[256]);
-GPUTexture *GPU_texture_create_2D_procedural(int w, int h, const float *pixels, bool repeat, char err_out[256]);
-GPUTexture *GPU_texture_create_1D_procedural(int w, const float *pixels, char err_out[256]);
-GPUTexture *GPU_texture_create_2D_multisample(
- int w, int h, const float *pixels, GPUHDRType hdr, int samples, char err_out[256]);
GPUTexture *GPU_texture_create_depth_multisample(int w, int h, int samples, char err_out[256]);
+GPUTexture *GPU_texture_create_vsm_shadow_map(int size, char err_out[256]);
+
GPUTexture *GPU_texture_from_blender(
struct Image *ima, struct ImageUser *iuser, int textarget, bool is_data, double time, int mipmap);
GPUTexture *GPU_texture_from_preview(struct PreviewImage *prv, int mipmap);
+
void GPU_invalid_tex_init(void);
void GPU_invalid_tex_bind(int mode);
void GPU_invalid_tex_free(void);
@@ -81,12 +157,13 @@ void GPU_invalid_tex_free(void);
void GPU_texture_free(GPUTexture *tex);
void GPU_texture_ref(GPUTexture *tex);
-
void GPU_texture_bind(GPUTexture *tex, int number);
void GPU_texture_unbind(GPUTexture *tex);
int GPU_texture_bound_number(GPUTexture *tex);
-void GPU_texture_filter_mode(GPUTexture *tex, bool compare, bool use_filter);
+void GPU_texture_compare_mode(GPUTexture *tex, bool use_compare);
+void GPU_texture_filter_mode(GPUTexture *tex, bool use_filter);
+void GPU_texture_wrap_mode(GPUTexture *tex, bool use_repeat);
struct GPUFrameBuffer *GPU_texture_framebuffer(GPUTexture *tex);
int GPU_texture_framebuffer_attachment(GPUTexture *tex);
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 <stdbool.h>
+#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_codegen.c b/source/blender/gpu/intern/gpu_codegen.c
index 211394e7932..4223ec54f74 100644
--- a/source/blender/gpu/intern/gpu_codegen.c
+++ b/source/blender/gpu/intern/gpu_codegen.c
@@ -1192,7 +1192,7 @@ static void gpu_node_input_link(GPUNode *node, GPUNodeLink *link, const GPUType
#if 0
input->tex = GPU_texture_create_2D(link->texturesize, link->texturesize, link->ptr2, NULL);
#endif
- input->tex = GPU_texture_create_2D(link->texturesize, 1, link->ptr1, GPU_HDR_NONE, NULL);
+ input->tex = GPU_texture_create_2D(link->texturesize, 1, link->ptr1, NULL);
input->textarget = GL_TEXTURE_2D;
MEM_freeN(link->ptr1);
diff --git a/source/blender/gpu/intern/gpu_compositing.c b/source/blender/gpu/intern/gpu_compositing.c
index 13596f2a0de..528bdefc209 100644
--- a/source/blender/gpu/intern/gpu_compositing.c
+++ b/source/blender/gpu/intern/gpu_compositing.c
@@ -225,7 +225,13 @@ static GPUTexture * create_concentric_sample_texture(int side)
}
}
- tex = GPU_texture_create_1D_procedural(side * side, texels, NULL);
+ tex = GPU_texture_create_1D_custom(side * side, 2, GPU_RG16F, (float *)texels, NULL);
+
+ /* Set parameters */
+ GPU_texture_bind(tex, 0);
+ GPU_texture_filter_mode(tex, false);
+ GPU_texture_unbind(tex);
+
MEM_freeN(texels);
return tex;
}
@@ -247,7 +253,13 @@ static GPUTexture *create_spiral_sample_texture(int numsaples)
texels[i][1] = r * sinf(phi);
}
- tex = GPU_texture_create_1D_procedural(numsaples, (float *)texels, NULL);
+ tex = GPU_texture_create_1D_custom(numsaples, 2, GPU_RG16F, (float *)texels, NULL);
+
+ /* Set parameters */
+ GPU_texture_bind(tex, 0);
+ GPU_texture_filter_mode(tex, false);
+ GPU_texture_unbind(tex);
+
MEM_freeN(texels);
return tex;
}
@@ -358,6 +370,7 @@ void GPU_fx_compositor_destroy(GPUFX *fx)
static GPUTexture * create_jitter_texture(void)
{
+ GPUTexture *tex;
float jitter[64 * 64][2];
int i;
@@ -367,7 +380,15 @@ static GPUTexture * create_jitter_texture(void)
normalize_v2(jitter[i]);
}
- return GPU_texture_create_2D_procedural(64, 64, &jitter[0][0], true, NULL);
+ tex = GPU_texture_create_2D_custom(64, 64, 2, GPU_RG16F, &jitter[0][0], NULL);
+
+ /* Set parameters */
+ GPU_texture_bind(tex, 0);
+ GPU_texture_filter_mode(tex, false);
+ GPU_texture_wrap_mode(tex, true);
+ GPU_texture_unbind(tex);
+
+ return tex;
}
@@ -433,7 +454,7 @@ bool GPU_fx_compositor_initialize_passes(
if (!fx->color_buffer || !fx->depth_buffer || w != fx->gbuffer_dim[0] || h != fx->gbuffer_dim[1]) {
cleanup_fx_gl_data(fx, false);
- if (!(fx->color_buffer = GPU_texture_create_2D(w, h, NULL, GPU_HDR_NONE, err_out))) {
+ if (!(fx->color_buffer = GPU_texture_create_2D(w, h, NULL, err_out))) {
printf(".256%s\n", err_out);
cleanup_fx_gl_data(fx, true);
return false;
@@ -485,38 +506,42 @@ bool GPU_fx_compositor_initialize_passes(
{
if (!(fx->dof_half_downsampled_near = GPU_texture_create_2D(
- fx->dof_downsampled_w, fx->dof_downsampled_h, NULL, GPU_HDR_NONE, err_out)))
+ fx->dof_downsampled_w, fx->dof_downsampled_h, NULL, err_out)))
{
printf("%.256s\n", err_out);
cleanup_fx_gl_data(fx, true);
return false;
}
if (!(fx->dof_half_downsampled_far = GPU_texture_create_2D(
- fx->dof_downsampled_w, fx->dof_downsampled_h, NULL, GPU_HDR_NONE, err_out)))
+ fx->dof_downsampled_w, fx->dof_downsampled_h, NULL, err_out)))
{
printf("%.256s\n", err_out);
cleanup_fx_gl_data(fx, true);
return false;
}
- if (!(fx->dof_nearfar_coc = GPU_texture_create_2D_procedural(
- fx->dof_downsampled_w, fx->dof_downsampled_h, NULL, false, err_out)))
+
+ if (!(fx->dof_nearfar_coc = GPU_texture_create_2D_custom(
+ fx->dof_downsampled_w, fx->dof_downsampled_h, 2, GPU_RG16F, NULL, err_out)))
{
printf("%.256s\n", err_out);
cleanup_fx_gl_data(fx, true);
return false;
}
+ GPU_texture_bind(fx->dof_nearfar_coc, 0);
+ GPU_texture_filter_mode(fx->dof_nearfar_coc, false);
+ GPU_texture_wrap_mode(fx->dof_nearfar_coc, false);
+ GPU_texture_unbind(fx->dof_nearfar_coc);
-
- if (!(fx->dof_near_blur = GPU_texture_create_2D(
- fx->dof_downsampled_w, fx->dof_downsampled_h, NULL, GPU_HDR_HALF_FLOAT, err_out)))
+ if (!(fx->dof_near_blur = GPU_texture_create_2D_custom(
+ fx->dof_downsampled_w, fx->dof_downsampled_h, 2, GPU_RGBA16F, NULL, err_out)))
{
printf("%.256s\n", err_out);
cleanup_fx_gl_data(fx, true);
return false;
}
- if (!(fx->dof_far_blur = GPU_texture_create_2D(
- fx->dof_downsampled_w, fx->dof_downsampled_h, NULL, GPU_HDR_HALF_FLOAT, err_out)))
+ if (!(fx->dof_far_blur = GPU_texture_create_2D_custom(
+ fx->dof_downsampled_w, fx->dof_downsampled_h, 2, GPU_RGBA16F, NULL, err_out)))
{
printf("%.256s\n", err_out);
cleanup_fx_gl_data(fx, true);
@@ -531,21 +556,21 @@ bool GPU_fx_compositor_initialize_passes(
if (!fx->dof_near_coc_buffer || !fx->dof_near_coc_blurred_buffer || !fx->dof_near_coc_final_buffer) {
if (!(fx->dof_near_coc_buffer = GPU_texture_create_2D(
- fx->dof_downsampled_w, fx->dof_downsampled_h, NULL, GPU_HDR_NONE, err_out)))
+ fx->dof_downsampled_w, fx->dof_downsampled_h, NULL, err_out)))
{
printf("%.256s\n", err_out);
cleanup_fx_gl_data(fx, true);
return false;
}
if (!(fx->dof_near_coc_blurred_buffer = GPU_texture_create_2D(
- fx->dof_downsampled_w, fx->dof_downsampled_h, NULL, GPU_HDR_NONE, err_out)))
+ fx->dof_downsampled_w, fx->dof_downsampled_h, NULL, err_out)))
{
printf("%.256s\n", err_out);
cleanup_fx_gl_data(fx, true);
return false;
}
if (!(fx->dof_near_coc_final_buffer = GPU_texture_create_2D(
- fx->dof_downsampled_w, fx->dof_downsampled_h, NULL, GPU_HDR_NONE, err_out)))
+ fx->dof_downsampled_w, fx->dof_downsampled_h, NULL, err_out)))
{
printf("%.256s\n", err_out);
cleanup_fx_gl_data(fx, true);
@@ -564,7 +589,7 @@ bool GPU_fx_compositor_initialize_passes(
/* we need to pass data between shader stages, allocate an extra color buffer */
if (num_passes > 1) {
if (!fx->color_buffer_sec) {
- if (!(fx->color_buffer_sec = GPU_texture_create_2D(w, h, NULL, GPU_HDR_NONE, err_out))) {
+ if (!(fx->color_buffer_sec = GPU_texture_create_2D(w, h, NULL, err_out))) {
printf(".256%s\n", err_out);
cleanup_fx_gl_data(fx, true);
return false;
@@ -692,14 +717,16 @@ void GPU_fx_compositor_XRay_resolve(GPUFX *fx)
GPU_shader_bind(depth_resolve_shader);
GPU_texture_bind(fx->depth_buffer_xray, 0);
- GPU_texture_filter_mode(fx->depth_buffer_xray, false, true);
+ GPU_texture_compare_mode(fx->depth_buffer_xray, false);
+ GPU_texture_filter_mode(fx->depth_buffer_xray, true);
GPU_shader_uniform_texture(depth_resolve_shader, interface->depth_uniform, fx->depth_buffer_xray);
/* draw */
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
/* disable bindings */
- GPU_texture_filter_mode(fx->depth_buffer_xray, true, false);
+ GPU_texture_compare_mode(fx->depth_buffer_xray, true);
+ GPU_texture_filter_mode(fx->depth_buffer_xray, false);
GPU_texture_unbind(fx->depth_buffer_xray);
GPU_shader_unbind();
@@ -814,7 +841,8 @@ bool GPU_fx_do_composite_pass(
GPU_shader_uniform_texture(ssao_shader, interface->color_uniform, src);
GPU_texture_bind(fx->depth_buffer, numslots++);
- GPU_texture_filter_mode(fx->depth_buffer, false, true);
+ GPU_texture_compare_mode(fx->depth_buffer, false);
+ GPU_texture_filter_mode(fx->depth_buffer, true);
GPU_shader_uniform_texture(ssao_shader, interface->depth_uniform, fx->depth_buffer);
GPU_texture_bind(fx->jitter_buffer, numslots++);
@@ -830,7 +858,8 @@ bool GPU_fx_do_composite_pass(
/* disable bindings */
GPU_texture_unbind(src);
- GPU_texture_filter_mode(fx->depth_buffer, true, false);
+ GPU_texture_compare_mode(fx->depth_buffer, true);
+ GPU_texture_filter_mode(fx->depth_buffer, false);
GPU_texture_unbind(fx->depth_buffer);
GPU_texture_unbind(fx->jitter_buffer);
GPU_texture_unbind(fx->ssao_spiral_samples_tex);
@@ -906,12 +935,13 @@ bool GPU_fx_do_composite_pass(
GPU_shader_uniform_vector(dof_shader_pass1, interface->invrendertargetdim_uniform, 2, 1, invrendertargetdim);
GPU_texture_bind(fx->depth_buffer, numslots++);
- GPU_texture_filter_mode(fx->depth_buffer, false, false);
+ GPU_texture_compare_mode(fx->depth_buffer, false);
+ GPU_texture_filter_mode(fx->depth_buffer, false);
GPU_shader_uniform_texture(dof_shader_pass1, interface->depth_uniform, fx->depth_buffer);
GPU_texture_bind(src, numslots++);
/* disable filtering for the texture so custom downsample can do the right thing */
- GPU_texture_filter_mode(src, false, false);
+ GPU_texture_filter_mode(src, false);
GPU_shader_uniform_texture(dof_shader_pass2, interface->color_uniform, src);
/* target is the downsampled coc buffer */
@@ -925,9 +955,10 @@ bool GPU_fx_do_composite_pass(
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
/* disable bindings */
- GPU_texture_filter_mode(src, false, true);
+ GPU_texture_filter_mode(src, true);
GPU_texture_unbind(src);
- GPU_texture_filter_mode(fx->depth_buffer, true, false);
+ GPU_texture_compare_mode(fx->depth_buffer, true);
+ GPU_texture_filter_mode(fx->depth_buffer, false);
GPU_texture_unbind(fx->depth_buffer);
GPU_framebuffer_texture_detach(fx->dof_half_downsampled_near);
@@ -958,7 +989,7 @@ bool GPU_fx_do_composite_pass(
GPU_texture_bind(fx->dof_half_downsampled_far, numslots++);
GPU_texture_bind(fx->dof_half_downsampled_near, numslots++);
GPU_shader_uniform_texture(dof_shader_pass2, interface->color_uniform, fx->dof_half_downsampled_far);
- GPU_texture_filter_mode(fx->dof_half_downsampled_far, false, false);
+ GPU_texture_filter_mode(fx->dof_half_downsampled_far, false);
/* target is the downsampled coc buffer */
GPU_framebuffer_texture_attach(fx->gbuffer, fx->dof_far_blur, 0);
@@ -978,7 +1009,7 @@ bool GPU_fx_do_composite_pass(
GPU_framebuffer_texture_detach(fx->dof_far_blur);
GPU_shader_uniform_texture(dof_shader_pass2, interface->color_uniform, fx->dof_half_downsampled_near);
- GPU_texture_filter_mode(fx->dof_half_downsampled_near, false, false);
+ GPU_texture_filter_mode(fx->dof_half_downsampled_near, false);
selection[0] = 1.0f;
selection[1] = 0.0f;
@@ -1018,14 +1049,15 @@ bool GPU_fx_do_composite_pass(
GPU_texture_bind(fx->dof_near_blur, numslots++);
GPU_shader_uniform_texture(dof_shader_pass3, interface->near_uniform, fx->dof_near_blur);
- GPU_texture_filter_mode(fx->dof_near_blur, false, true);
+ GPU_texture_filter_mode(fx->dof_near_blur, true);
GPU_texture_bind(fx->dof_far_blur, numslots++);
GPU_shader_uniform_texture(dof_shader_pass3, interface->far_uniform, fx->dof_far_blur);
- GPU_texture_filter_mode(fx->dof_far_blur, false, true);
+ GPU_texture_filter_mode(fx->dof_far_blur, true);
GPU_texture_bind(fx->depth_buffer, numslots++);
- GPU_texture_filter_mode(fx->depth_buffer, false, false);
+ GPU_texture_compare_mode(fx->depth_buffer, false);
+ GPU_texture_filter_mode(fx->depth_buffer, false);
GPU_shader_uniform_texture(dof_shader_pass3, interface->depth_uniform, fx->depth_buffer);
GPU_texture_bind(src, numslots++);
@@ -1040,7 +1072,7 @@ bool GPU_fx_do_composite_pass(
GPU_texture_unbind(fx->dof_near_blur);
GPU_texture_unbind(fx->dof_far_blur);
GPU_texture_unbind(src);
- GPU_texture_filter_mode(fx->depth_buffer, true, false);
+ GPU_texture_compare_mode(fx->depth_buffer, true);
GPU_texture_unbind(fx->depth_buffer);
/* may not be attached, in that case this just returns */
@@ -1100,7 +1132,8 @@ bool GPU_fx_do_composite_pass(
GPU_shader_uniform_texture(dof_shader_pass1, interface->color_uniform, src);
GPU_texture_bind(fx->depth_buffer, numslots++);
- GPU_texture_filter_mode(fx->depth_buffer, false, true);
+ GPU_texture_compare_mode(fx->depth_buffer, false);
+ GPU_texture_filter_mode(fx->depth_buffer, true);
GPU_shader_uniform_texture(dof_shader_pass1, interface->depth_uniform, fx->depth_buffer);
/* target is the downsampled coc buffer */
@@ -1111,7 +1144,8 @@ bool GPU_fx_do_composite_pass(
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
/* disable bindings */
GPU_texture_unbind(src);
- GPU_texture_filter_mode(fx->depth_buffer, true, false);
+ GPU_texture_compare_mode(fx->depth_buffer, true);
+ GPU_texture_filter_mode(fx->depth_buffer, false);
GPU_texture_unbind(fx->depth_buffer);
GPU_framebuffer_texture_detach(fx->dof_near_coc_buffer);
@@ -1137,7 +1171,8 @@ bool GPU_fx_do_composite_pass(
GPU_shader_uniform_vector(dof_shader_pass2, interface->viewvecs_uniform, 4, 3, viewvecs[0]);
GPU_texture_bind(fx->depth_buffer, numslots++);
- GPU_texture_filter_mode(fx->depth_buffer, false, true);
+ GPU_texture_compare_mode(fx->depth_buffer, false);
+ GPU_texture_filter_mode(fx->depth_buffer, true);
GPU_shader_uniform_texture(dof_shader_pass2, interface->depth_uniform, fx->depth_buffer);
GPU_texture_bind(fx->dof_near_coc_buffer, numslots++);
@@ -1165,7 +1200,8 @@ bool GPU_fx_do_composite_pass(
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
/* *unbind/detach */
- GPU_texture_filter_mode(fx->depth_buffer, true, false);
+ GPU_texture_compare_mode(fx->depth_buffer, true);
+ GPU_texture_filter_mode(fx->depth_buffer, false);
GPU_texture_unbind(fx->depth_buffer);
GPU_texture_unbind(fx->dof_near_coc_final_buffer);
@@ -1249,7 +1285,8 @@ bool GPU_fx_do_composite_pass(
GPU_shader_uniform_texture(dof_shader_pass5, interface->medium_blurred_uniform, fx->dof_near_coc_buffer);
GPU_texture_bind(fx->depth_buffer, numslots++);
- GPU_texture_filter_mode(fx->depth_buffer, false, true);
+ GPU_texture_compare_mode(fx->depth_buffer, false);
+ GPU_texture_filter_mode(fx->depth_buffer, true);
GPU_shader_uniform_texture(dof_shader_pass5, interface->depth_uniform, fx->depth_buffer);
/* if this is the last pass, prepare for rendering on the frambuffer */
@@ -1260,7 +1297,8 @@ bool GPU_fx_do_composite_pass(
GPU_texture_unbind(fx->dof_near_coc_buffer);
GPU_texture_unbind(fx->dof_near_coc_blurred_buffer);
GPU_texture_unbind(src);
- GPU_texture_filter_mode(fx->depth_buffer, true, false);
+ GPU_texture_compare_mode(fx->depth_buffer, true);
+ GPU_texture_filter_mode(fx->depth_buffer, false);
GPU_texture_unbind(fx->depth_buffer);
/* may not be attached, in that case this just returns */
diff --git a/source/blender/gpu/intern/gpu_draw.c b/source/blender/gpu/intern/gpu_draw.c
index c8d5d92b66b..36c61fde36c 100644
--- a/source/blender/gpu/intern/gpu_draw.c
+++ b/source/blender/gpu/intern/gpu_draw.c
@@ -1438,31 +1438,40 @@ void GPU_create_smoke(SmokeModifierData *smd, int highres)
if (smoke_has_colors(sds->fluid)) {
float *data = MEM_callocN(sizeof(float) * sds->total_cells * 4, "smokeColorTexture");
smoke_get_rgba(sds->fluid, data, 0);
- sds->tex = GPU_texture_create_3D(sds->res[0], sds->res[1], sds->res[2], 4, data);
+ sds->tex = GPU_texture_create_3D(sds->res[0], sds->res[1], sds->res[2], data, NULL);
MEM_freeN(data);
}
/* density only */
else {
- sds->tex = GPU_texture_create_3D(sds->res[0], sds->res[1], sds->res[2], 1, smoke_get_density(sds->fluid));
+ sds->tex = GPU_texture_create_3D_custom(sds->res[0], sds->res[1], sds->res[2], 1,
+ GPU_R8, smoke_get_density(sds->fluid), NULL);
}
- sds->tex_flame = (smoke_has_fuel(sds->fluid)) ? GPU_texture_create_3D(sds->res[0], sds->res[1], sds->res[2], 1, smoke_get_flame(sds->fluid)) : NULL;
+ sds->tex_flame = (smoke_has_fuel(sds->fluid)) ?
+ GPU_texture_create_3D_custom(sds->res[0], sds->res[1], sds->res[2], 1,
+ GPU_R8, smoke_get_flame(sds->fluid), NULL) :
+ NULL;
}
else if (!sds->tex && highres) {
/* rgba texture for color + density */
if (smoke_turbulence_has_colors(sds->wt)) {
float *data = MEM_callocN(sizeof(float) * smoke_turbulence_get_cells(sds->wt) * 4, "smokeColorTexture");
smoke_turbulence_get_rgba(sds->wt, data, 0);
- sds->tex = GPU_texture_create_3D(sds->res_wt[0], sds->res_wt[1], sds->res_wt[2], 4, data);
+ sds->tex = GPU_texture_create_3D(sds->res_wt[0], sds->res_wt[1], sds->res_wt[2], data, NULL);
MEM_freeN(data);
}
/* density only */
else {
- sds->tex = GPU_texture_create_3D(sds->res_wt[0], sds->res_wt[1], sds->res_wt[2], 1, smoke_turbulence_get_density(sds->wt));
+ sds->tex = GPU_texture_create_3D_custom(sds->res_wt[0], sds->res_wt[1], sds->res_wt[2], 1,
+ GPU_R8, smoke_turbulence_get_density(sds->wt), NULL);
}
- sds->tex_flame = (smoke_turbulence_has_fuel(sds->wt)) ? GPU_texture_create_3D(sds->res_wt[0], sds->res_wt[1], sds->res_wt[2], 1, smoke_turbulence_get_flame(sds->wt)) : NULL;
+ sds->tex_flame = (smoke_turbulence_has_fuel(sds->wt)) ?
+ GPU_texture_create_3D_custom(sds->res_wt[0], sds->res_wt[1], sds->res_wt[2], 1,
+ GPU_R8, smoke_turbulence_get_flame(sds->wt), NULL):
+ NULL;
}
- sds->tex_shadow = GPU_texture_create_3D(sds->res[0], sds->res[1], sds->res[2], 1, sds->shadow);
+ sds->tex_shadow = GPU_texture_create_3D_custom(sds->res[0], sds->res[1], sds->res[2], 1,
+ GPU_R8, sds->shadow, NULL);
}
#else // WITH_SMOKE
(void)highres;
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 ec1471744fa..1efc451f4a8 100644
--- a/source/blender/gpu/intern/gpu_framebuffer.c
+++ b/source/blender/gpu/intern/gpu_framebuffer.c
@@ -54,7 +54,7 @@ struct GPUFrameBuffer {
static void GPU_print_framebuffer_error(GLenum status, char err_out[256])
{
- const char *format = "GPUFrameBuffer: framebuffer status %s";
+ const char *format = "GPUFrameBuffer: framebuffer status %s\n";
const char *err = "unknown";
#define format_status(X) \
@@ -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)
@@ -453,7 +489,7 @@ GPUOffScreen *GPU_offscreen_create(int width, int height, int samples, char err_
return NULL;
}
- ofs->color = GPU_texture_create_2D_multisample(width, height, NULL, GPU_HDR_NONE, samples, err_out);
+ ofs->color = GPU_texture_create_2D_multisample(width, height, NULL, samples, err_out);
if (!ofs->color) {
GPU_offscreen_free(ofs);
return NULL;
diff --git a/source/blender/gpu/intern/gpu_material.c b/source/blender/gpu/intern/gpu_material.c
index 56b7af787e7..90e78af48c1 100644
--- a/source/blender/gpu/intern/gpu_material.c
+++ b/source/blender/gpu/intern/gpu_material.c
@@ -2415,7 +2415,7 @@ GPULamp *GPU_lamp_from_blender(Scene *scene, Object *ob, Object *par)
}
/* Shadow color map */
- lamp->tex = GPU_texture_create_vsm_shadow_map(lamp->size, NULL);
+ lamp->tex = GPU_texture_create_2D_custom(lamp->size, lamp->size, 2, GPU_RG32F, NULL, NULL);
if (!lamp->tex) {
gpu_lamp_shadow_free(lamp);
return lamp;
@@ -2438,7 +2438,7 @@ GPULamp *GPU_lamp_from_blender(Scene *scene, Object *ob, Object *par)
return lamp;
}
- lamp->blurtex = GPU_texture_create_vsm_shadow_map(lamp->size * 0.5, NULL);
+ lamp->blurtex = GPU_texture_create_2D_custom(lamp->size * 0.5, lamp->size * 0.5, 2, GPU_RG32F, NULL, NULL);
if (!lamp->blurtex) {
gpu_lamp_shadow_free(lamp);
return lamp;
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 6956a815ac5..2cc709db3b3 100644
--- a/source/blender/gpu/intern/gpu_texture.c
+++ b/source/blender/gpu/intern/gpu_texture.c
@@ -49,9 +49,8 @@ static struct GPUTextureGlobal {
} GG = {NULL, NULL, NULL};
/* GPUTexture */
-
struct GPUTexture {
- int w, h; /* width/height */
+ int w, h, d; /* width/height/depth */
int number; /* number for multitexture binding */
int refcount; /* reference count */
GLenum target; /* GL_TEXTURE_* */
@@ -62,42 +61,211 @@ struct GPUTexture {
GPUFrameBuffer *fb; /* GPUFramebuffer this texture is attached to */
int fb_attachment; /* slot the texture is attached to */
- int depth; /* is a depth texture? if 3D how deep? */
+ bool depth; /* is a depth texture? */
};
-static unsigned char *GPU_texture_convert_pixels(int length, const float *fpixels)
+static GLenum GPU_texture_get_format(int components, GPUFormat data_type, GLenum *format, bool *is_depth)
{
- unsigned char *pixels, *p;
- const float *fp = fpixels;
- const int len = 4 * length;
+ if (data_type == GPU_DEPTH_COMPONENT24 ||
+ data_type == GPU_DEPTH_COMPONENT16 ||
+ data_type == GPU_DEPTH_COMPONENT32F)
+ {
+ *is_depth = true;
+ *format = GL_DEPTH_COMPONENT;
+ }
+ else {
+ *is_depth = false;
+
+ switch (components) {
+ case 1: *format = GL_RED; break;
+ case 2: *format = GL_RG; break;
+ case 3: *format = GL_RGB; break;
+ case 4: *format = GL_RGBA; break;
+ default: break;
+ }
+ }
- p = pixels = MEM_callocN(sizeof(unsigned char) * len, "GPUTexturePixels");
+ switch (data_type) {
+ /* Formats texture & renderbuffer */
+ case GPU_RGBA32F: return GL_RGBA32F;
+ case GPU_RGBA32I: return GL_RGBA32I;
+ case GPU_RGBA32UI: return GL_RGBA32UI;
+ case GPU_RGBA16: return GL_RGBA16;
+ case GPU_RGBA16F: return GL_RGBA16F;
+ case GPU_RGBA16I: return GL_RGBA16I;
+ case GPU_RGBA16UI: return GL_RGBA16UI;
+ case GPU_RGBA8: return GL_RGBA8;
+ case GPU_RGBA8I: return GL_RGBA8I;
+ case GPU_RGBA8UI: return GL_RGBA8UI;
+ case GPU_RG32F: return GL_RG32F;
+ case GPU_RG32I: return GL_RG32I;
+ case GPU_RG32UI: return GL_RG32UI;
+ case GPU_RG16: return GL_RG16;
+ case GPU_RG16F: return GL_RG16F;
+ case GPU_RG16I: return GL_RG16I;
+ case GPU_RG16UI: return GL_RG16UI;
+ case GPU_RG8: return GL_RG8;
+ case GPU_RG8I: return GL_RG8I;
+ case GPU_RG8UI: return GL_RG8UI;
+ case GPU_R32F: return GL_R32F;
+ case GPU_R32I: return GL_R32I;
+ case GPU_R32UI: return GL_R32UI;
+ case GPU_R16F: return GL_R16F;
+ case GPU_R16I: return GL_R16I;
+ case GPU_R16UI: return GL_R16UI;
+ case GPU_R16: return GL_R16;
+ case GPU_R8: return GL_R8;
+ case GPU_R8I: return GL_R8I;
+ case GPU_R8UI: return GL_R8UI;
+ /* Special formats texture & renderbuffer */
+ case GPU_R11F_G11F_B10F: return GL_R11F_G11F_B10F;
+ case GPU_RGB10_A2: return GL_RGB10_A2;
+ case GPU_RGB10_A2UI: return GL_RGB10_A2UI;
+ case GPU_DEPTH32F_STENCIL8: return GL_DEPTH32F_STENCIL8;
+ case GPU_DEPTH24_STENCIL8: return GL_DEPTH24_STENCIL8;
+ /* Texture only format */
+ case GPU_RGBA16_SNORM: return GL_RGBA16_SNORM;
+ case GPU_RGBA8_SNORM: return GL_RGBA8_SNORM;
+ case GPU_RGB32F: return GL_RGB32F;
+ case GPU_RGB32I: return GL_RGB32I;
+ case GPU_RGB32UI: return GL_RGB32UI;
+ case GPU_RGB16_SNORM: return GL_RGB16_SNORM;
+ case GPU_RGB16F: return GL_RGB16F;
+ case GPU_RGB16I: return GL_RGB16I;
+ case GPU_RGB16UI: return GL_RGB16UI;
+ case GPU_RGB16: return GL_RGB16;
+ case GPU_RGB8_SNORM: return GL_RGB8_SNORM;
+ case GPU_RGB8: return GL_RGB8;
+ case GPU_RGB8I: return GL_RGB8I;
+ case GPU_RGB8UI: return GL_RGB8UI;
+ case GPU_RG16_SNORM: return GL_RG16_SNORM;
+ case GPU_RG8_SNORM: return GL_RG8_SNORM;
+ case GPU_R16_SNORM: return GL_R16_SNORM;
+ case GPU_R8_SNORM: return GL_R8_SNORM;
+ /* Special formats texture only */
+#if 0 /* Absent ? */
+ case GPU_SRGB8_A8: return GL_SRGB8_A8;
+#endif
+ case GPU_SRGB8: return GL_SRGB8;
+ case GPU_RGB9_E5: return GL_RGB9_E5;
+ case GPU_COMPRESSED_RG_RGTC2: return GL_COMPRESSED_RG_RGTC2;
+ case GPU_COMPRESSED_SIGNED_RG_RGTC2: return GL_COMPRESSED_SIGNED_RG_RGTC2;
+ case GPU_COMPRESSED_RED_RGTC1: return GL_COMPRESSED_RED_RGTC1;
+ case GPU_COMPRESSED_SIGNED_RED_RGTC1: return GL_COMPRESSED_SIGNED_RED_RGTC1;
+ /* Depth Formats */
+ case GPU_DEPTH_COMPONENT32F: return GL_DEPTH_COMPONENT32F;
+ case GPU_DEPTH_COMPONENT24: return GL_DEPTH_COMPONENT24;
+ case GPU_DEPTH_COMPONENT16: return GL_DEPTH_COMPONENT16;
+ default:
+ fprintf(stderr, "Texture format incorrect or unsupported\n");
+ return 0;
+ }
+}
- for (int a = 0; a < len; a++, p++, fp++)
- *p = FTOCHAR((*fp));
+static float *GPU_texture_3D_rescale(GPUTexture *tex, int w, int h, int d, int channels, const float *fpixels)
+{
+ const unsigned int xf = w / tex->w, yf = h / tex->h, zf = d / tex->d;
+ float *nfpixels = MEM_mallocN(channels * sizeof(float) * tex->w * tex->h * tex->d, "GPUTexture Rescaled 3Dtex");
+
+ if (nfpixels) {
+ GPU_print_error_debug("You need to scale a 3D texture, feel the pain!");
+
+ for (unsigned k = 0; k < tex->d; k++) {
+ for (unsigned j = 0; j < tex->h; j++) {
+ for (unsigned i = 0; i < tex->w; i++) {
+ /* obviously doing nearest filtering here,
+ * it's going to be slow in any case, let's not make it worse */
+ float xb = i * xf;
+ float yb = j * yf;
+ float zb = k * zf;
+ unsigned int offset = k * (tex->w * tex->h) + i * tex->h + j;
+ unsigned int offset_orig = (zb) * (w * h) + (xb) * h + (yb);
+
+ if (channels == 4) {
+ nfpixels[offset * 4] = fpixels[offset_orig * 4];
+ nfpixels[offset * 4 + 1] = fpixels[offset_orig * 4 + 1];
+ nfpixels[offset * 4 + 2] = fpixels[offset_orig * 4 + 2];
+ nfpixels[offset * 4 + 3] = fpixels[offset_orig * 4 + 3];
+ }
+ else
+ nfpixels[offset] = fpixels[offset_orig];
+ }
+ }
+ }
+ }
- return pixels;
+ return nfpixels;
}
-static void GPU_glTexSubImageEmpty(GLenum target, GLenum format, int x, int y, int w, int h)
+/* This tries to allocate video memory for a given texture
+ * If alloc fails, lower the resolution until it fits. */
+static bool GPU_texture_try_alloc(
+ GPUTexture *tex, GLenum proxy, GLenum internalformat, GLenum format, int channels,
+ bool try_rescale, const float *fpixels, float **rescaled_fpixels)
{
- void *pixels = MEM_callocN(sizeof(char) * 4 * w * h, "GPUTextureEmptyPixels");
+ int r_width;
- if (target == GL_TEXTURE_1D)
- glTexSubImage1D(target, 0, x, w, format, GL_UNSIGNED_BYTE, pixels);
- else
- glTexSubImage2D(target, 0, x, y, w, h, format, GL_UNSIGNED_BYTE, pixels);
-
- MEM_freeN(pixels);
+ if (proxy == GL_PROXY_TEXTURE_1D)
+ glTexImage1D(proxy, 0, internalformat, tex->w, 0, format, GL_FLOAT, NULL);
+ else if (proxy == GL_PROXY_TEXTURE_2D)
+ glTexImage2D(proxy, 0, internalformat, tex->w, tex->h, 0, format, GL_FLOAT, NULL);
+ else if (proxy == GL_PROXY_TEXTURE_3D)
+ glTexImage3D(proxy, 0, internalformat, tex->w, tex->h, tex->d, 0, format, GL_FLOAT, NULL);
+
+ glGetTexLevelParameteriv(proxy, 0, GL_TEXTURE_WIDTH, &r_width);
+
+ if (r_width == 0 && try_rescale) {
+ const int w = tex->w, h = tex->h, d = tex->d;
+
+ /* Find largest texture possible */
+ while (r_width == 0) {
+ tex->w /= 2;
+ tex->h /= 2;
+ tex->d /= 2;
+
+ /* really unlikely to happen but keep this just in case */
+ if (tex->w == 0) break;
+ if (tex->h == 0 && proxy != GL_PROXY_TEXTURE_1D) break;
+ if (tex->d == 0 && proxy == GL_PROXY_TEXTURE_3D) break;
+
+ if (proxy == GL_PROXY_TEXTURE_1D)
+ glTexImage1D(proxy, 0, internalformat, tex->w, 0, format, GL_FLOAT, NULL);
+ else if (proxy == GL_PROXY_TEXTURE_2D)
+ glTexImage2D(proxy, 0, internalformat, tex->w, tex->h, 0, format, GL_FLOAT, NULL);
+ else if (proxy == GL_PROXY_TEXTURE_3D)
+ glTexImage3D(proxy, 0, internalformat, tex->w, tex->h, tex->d, 0, format, GL_FLOAT, NULL);
+
+ glGetTexLevelParameteriv(GL_PROXY_TEXTURE_3D, 0, GL_TEXTURE_WIDTH, &r_width);
+ }
+
+ /* Rescale */
+ if (r_width > 0) {
+ if (proxy == GL_PROXY_TEXTURE_1D) {
+ /* Do nothing for now */
+ return false;
+ }
+ else if (proxy == GL_PROXY_TEXTURE_2D) {
+ /* Do nothing for now */
+ return false;
+ }
+ else if (proxy == GL_PROXY_TEXTURE_3D) {
+ *rescaled_fpixels = GPU_texture_3D_rescale(tex, w, h, d, channels, fpixels);
+ return (bool)*rescaled_fpixels;
+ }
+ }
+ }
+
+ return (r_width > 0);
}
static GPUTexture *GPU_texture_create_nD(
- int w, int h, int n, const float *fpixels, int depth,
- GPUHDRType hdr_type, int components, int samples,
- char err_out[256])
+ int w, int h, int d, int n, const float *fpixels,
+ GPUFormat data_type, int components, int samples,
+ const bool can_rescale, char err_out[256])
{
- GLenum type, format, internalformat;
- void *pixels = NULL;
+ GLenum format, internalformat, proxy;
+ float *rescaled_fpixels = NULL, *pix;
+ bool valid;
if (samples) {
CLAMP_MAX(samples, GPU_max_color_texture_samples());
@@ -106,121 +274,94 @@ static GPUTexture *GPU_texture_create_nD(
GPUTexture *tex = MEM_callocN(sizeof(GPUTexture), "GPUTexture");
tex->w = w;
tex->h = h;
+ tex->d = d;
tex->number = -1;
tex->refcount = 1;
- tex->target = (n == 1) ? GL_TEXTURE_1D : (samples ? GL_TEXTURE_2D_MULTISAMPLE : GL_TEXTURE_2D);
- tex->target_base = (n == 1) ? GL_TEXTURE_1D : GL_TEXTURE_2D;
- tex->depth = depth;
+
+ if (n == 1) {
+ if (h == 0)
+ tex->target_base = tex->target = GL_TEXTURE_1D;
+ else
+ tex->target_base = tex->target = GL_TEXTURE_1D_ARRAY;
+ }
+ else if (n == 2) {
+ if (d == 0)
+ tex->target_base = tex->target = GL_TEXTURE_2D;
+ else
+ tex->target_base = tex->target = GL_TEXTURE_2D_ARRAY;
+ }
+ else if (n == 3) {
+ tex->target_base = tex->target = GL_TEXTURE_3D;
+ }
+
tex->fb_attachment = -1;
+ if (samples && n == 2 && d == 0)
+ tex->target = GL_TEXTURE_2D_MULTISAMPLE;
+
+ internalformat = GPU_texture_get_format(components, data_type, &format, &tex->depth);
+
+ /* Generate Texture object */
glGenTextures(1, &tex->bindcode);
if (!tex->bindcode) {
- if (err_out) {
+ if (err_out)
BLI_snprintf(err_out, 256, "GPUTexture: texture create failed");
- }
- else {
+ else
fprintf(stderr, "GPUTexture: texture create failed");
- }
GPU_texture_free(tex);
return NULL;
}
-#if 0 /* this should be a compile-time check */
- if (!GPU_full_non_power_of_two_support()) {
- tex->w = power_of_2_max_i(tex->w);
- tex->h = power_of_2_max_i(tex->h);
- }
-#endif
-
tex->number = 0;
glBindTexture(tex->target, tex->bindcode);
- if (depth) {
- type = GL_UNSIGNED_BYTE;
- format = GL_DEPTH_COMPONENT;
- internalformat = GL_DEPTH_COMPONENT;
- }
- else {
- type = GL_FLOAT;
-
- if (components == 4) {
- format = GL_RGBA;
- switch (hdr_type) {
- case GPU_HDR_NONE:
- internalformat = GL_RGBA8;
- break;
- /* the following formats rely on ARB_texture_float or OpenGL 3.0 */
- case GPU_HDR_HALF_FLOAT:
- internalformat = GL_RGBA16F_ARB;
- break;
- case GPU_HDR_FULL_FLOAT:
- internalformat = GL_RGBA32F_ARB;
- break;
- default:
- break;
- }
- }
- else if (components == 2) {
- /* these formats rely on ARB_texture_rg or OpenGL 3.0 */
- format = GL_RG;
- switch (hdr_type) {
- case GPU_HDR_NONE:
- internalformat = GL_RG8;
- break;
- case GPU_HDR_HALF_FLOAT:
- internalformat = GL_RG16F;
- break;
- case GPU_HDR_FULL_FLOAT:
- internalformat = GL_RG32F;
- break;
- default:
- break;
- }
- }
+ /* Check if texture fit in VRAM */
+ if (d > 0)
+ proxy = GL_PROXY_TEXTURE_3D;
+ else if (h > 0)
+ proxy = GL_PROXY_TEXTURE_2D;
+ else
+ proxy = GL_PROXY_TEXTURE_1D;
- if (fpixels && hdr_type == GPU_HDR_NONE) {
- type = GL_UNSIGNED_BYTE;
- pixels = GPU_texture_convert_pixels(w * h, fpixels);
- }
- }
+ valid = GPU_texture_try_alloc(tex, proxy, internalformat, format, components, can_rescale, fpixels,
+ &rescaled_fpixels);
- if (tex->target == GL_TEXTURE_1D) {
- glTexImage1D(tex->target, 0, internalformat, tex->w, 0, format, type, NULL);
+ if (!valid) {
+ if (err_out)
+ BLI_snprintf(err_out, 256, "GPUTexture: texture alloc failed");
+ else
+ fprintf(stderr, "GPUTexture: texture alloc failed. Not enough Video Memory.");
+ GPU_texture_free(tex);
+ return NULL;
+ }
- if (fpixels) {
- glTexSubImage1D(tex->target, 0, 0, w, format, type,
- pixels ? pixels : fpixels);
+ /* Upload Texture */
+ pix = (rescaled_fpixels) ? rescaled_fpixels : fpixels;
- if (tex->w > w) {
- GPU_glTexSubImageEmpty(tex->target, format, w, 0, tex->w - w, 1);
- }
- }
+ if (tex->target == GL_TEXTURE_1D) {
+ glTexImage1D(tex->target, 0, internalformat, tex->w, 0, format, GL_FLOAT, pix);
}
- else {
+ else if (tex->target == GL_TEXTURE_1D_ARRAY ||
+ tex->target == GL_TEXTURE_2D)
+ {
if (samples) {
glTexImage2DMultisample(tex->target, samples, internalformat, tex->w, tex->h, true);
+ glTexSubImage2D(tex->target, 0, 0, 0, tex->w, tex->h, format, GL_FLOAT, pix);
}
else {
- glTexImage2D(tex->target, 0, internalformat, tex->w, tex->h, 0,
- format, type, NULL);
- }
-
- if (fpixels) {
- glTexSubImage2D(tex->target, 0, 0, 0, w, h,
- format, type, pixels ? pixels : fpixels);
-
- if (tex->w > w)
- GPU_glTexSubImageEmpty(tex->target, format, w, 0, tex->w - w, tex->h);
- if (tex->h > h)
- GPU_glTexSubImageEmpty(tex->target, format, 0, h, w, tex->h - h);
+ glTexImage2D(tex->target, 0, internalformat, tex->w, tex->h, 0, format, GL_FLOAT, pix);
}
}
+ else {
+ glTexImage3D(tex->target, 0, internalformat, tex->w, tex->h, tex->d, 0, format, GL_FLOAT, pix);
+ }
- if (pixels)
- MEM_freeN(pixels);
+ if (rescaled_fpixels)
+ MEM_freeN(rescaled_fpixels);
- if (depth) {
+ /* Texture Parameters */
+ if (tex->depth) {
glTexParameteri(tex->target_base, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(tex->target_base, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(tex->target_base, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_R_TO_TEXTURE);
@@ -232,127 +373,9 @@ static GPUTexture *GPU_texture_create_nD(
glTexParameteri(tex->target_base, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
}
- if (tex->target_base != GL_TEXTURE_1D) {
- glTexParameteri(tex->target_base, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
- glTexParameteri(tex->target_base, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
- }
- else
- glTexParameteri(tex->target_base, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
-
- return tex;
-}
-
-
-GPUTexture *GPU_texture_create_3D(int w, int h, int depth, int channels, const float *fpixels)
-{
- GLenum type, format, internalformat;
- void *pixels = NULL;
-
- GPUTexture *tex = MEM_callocN(sizeof(GPUTexture), "GPUTexture");
- tex->w = w;
- tex->h = h;
- tex->depth = depth;
- tex->number = -1;
- tex->refcount = 1;
- tex->target = GL_TEXTURE_3D;
- tex->target_base = GL_TEXTURE_3D;
-
- glGenTextures(1, &tex->bindcode);
-
- if (!tex->bindcode) {
- fprintf(stderr, "GPUTexture: texture create failed");
- GPU_texture_free(tex);
- return NULL;
- }
-
- tex->number = 0;
- glBindTexture(tex->target, tex->bindcode);
-
- type = GL_FLOAT;
- if (channels == 4) {
- format = GL_RGBA;
- internalformat = GL_RGBA8;
- }
- else {
- format = GL_RED;
- internalformat = GL_INTENSITY8;
- }
-
- /* 3D textures are quite heavy, test if it's possible to create them first */
- glTexImage3D(GL_PROXY_TEXTURE_3D, 0, internalformat, tex->w, tex->h, tex->depth, 0, format, type, NULL);
-
- bool rescale = false;
- int r_width;
-
- glGetTexLevelParameteriv(GL_PROXY_TEXTURE_3D, 0, GL_TEXTURE_WIDTH, &r_width);
-
- while (r_width == 0) {
- rescale = true;
- tex->w /= 2;
- tex->h /= 2;
- tex->depth /= 2;
- glTexImage3D(GL_PROXY_TEXTURE_3D, 0, internalformat, tex->w, tex->h, tex->depth, 0, format, type, NULL);
- glGetTexLevelParameteriv(GL_PROXY_TEXTURE_3D, 0, GL_TEXTURE_WIDTH, &r_width);
- }
-
- /* really unlikely to happen but keep this just in case */
- tex->w = max_ii(tex->w, 1);
- tex->h = max_ii(tex->h, 1);
- tex->depth = max_ii(tex->depth, 1);
-
-#if 0
- if (fpixels)
- pixels = GPU_texture_convert_pixels(w*h*depth, fpixels);
-#endif
-
- /* hardcore stuff, 3D texture rescaling - warning, this is gonna hurt your performance a lot, but we need it
- * for gooseberry */
- if (rescale && fpixels) {
- /* FIXME: should these be floating point? */
- const unsigned int xf = w / tex->w, yf = h / tex->h, zf = depth / tex->depth;
- float *tex3d = MEM_mallocN(channels * sizeof(float) * tex->w * tex->h * tex->depth, "tex3d");
-
- GPU_print_error_debug("You need to scale a 3D texture, feel the pain!");
-
- for (unsigned k = 0; k < tex->depth; k++) {
- for (unsigned j = 0; j < tex->h; j++) {
- for (unsigned i = 0; i < tex->w; i++) {
- /* obviously doing nearest filtering here,
- * it's going to be slow in any case, let's not make it worse */
- float xb = i * xf;
- float yb = j * yf;
- float zb = k * zf;
- unsigned int offset = k * (tex->w * tex->h) + i * tex->h + j;
- unsigned int offset_orig = (zb) * (w * h) + (xb) * h + (yb);
-
- if (channels == 4) {
- tex3d[offset * 4] = fpixels[offset_orig * 4];
- tex3d[offset * 4 + 1] = fpixels[offset_orig * 4 + 1];
- tex3d[offset * 4 + 2] = fpixels[offset_orig * 4 + 2];
- tex3d[offset * 4 + 3] = fpixels[offset_orig * 4 + 3];
- }
- else
- tex3d[offset] = fpixels[offset_orig];
- }
- }
- }
-
- glTexImage3D(tex->target, 0, internalformat, tex->w, tex->h, tex->depth, 0, format, type, tex3d);
-
- MEM_freeN(tex3d);
- }
- else if (fpixels) {
- glTexImage3D(tex->target, 0, internalformat, tex->w, tex->h, tex->depth, 0, format, type, fpixels);
- }
-
- glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
- glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
- glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
- glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
- glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
-
- if (pixels)
- MEM_freeN(pixels);
+ glTexParameteri(tex->target_base, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ if (n != 1) glTexParameteri(tex->target_base, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+ if (n == 3) glTexParameteri(tex->target_base, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
GPU_texture_unbind(tex);
@@ -464,114 +487,64 @@ GPUTexture *GPU_texture_from_preview(PreviewImage *prv, int mipmap)
}
-GPUTexture *GPU_texture_create_1D(int w, const float *fpixels, char err_out[256])
+GPUTexture *GPU_texture_create_1D(int w, const float *pixels, char err_out[256])
{
- GPUTexture *tex = GPU_texture_create_nD(w, 1, 1, fpixels, 0, GPU_HDR_NONE, 4, 0, err_out);
-
- if (tex)
- GPU_texture_unbind(tex);
-
- return tex;
+ return GPU_texture_create_nD(w, 0, 0, 1, pixels, GPU_RGBA8, 4, 0, false, err_out);
}
-GPUTexture *GPU_texture_create_2D(int w, int h, const float *fpixels, GPUHDRType hdr, char err_out[256])
+GPUTexture *GPU_texture_create_1D_custom(
+ int w, int channels, GPUFormat data_type, const float *pixels, char err_out[256])
{
- GPUTexture *tex = GPU_texture_create_nD(w, h, 2, fpixels, 0, hdr, 4, 0, err_out);
-
- if (tex)
- GPU_texture_unbind(tex);
-
- return tex;
+ return GPU_texture_create_nD(w, 0, 0, 1, pixels, data_type, channels, 0, false, err_out);
}
-GPUTexture *GPU_texture_create_2D_multisample(
- int w, int h, const float *fpixels, GPUHDRType hdr, int samples, char err_out[256])
-{
- GPUTexture *tex = GPU_texture_create_nD(w, h, 2, fpixels, 0, hdr, 4, samples, err_out);
- if (tex)
- GPU_texture_unbind(tex);
-
- return tex;
+GPUTexture *GPU_texture_create_2D(int w, int h, const float *pixels, char err_out[256])
+{
+ return GPU_texture_create_nD(w, h, 0, 2, pixels, GPU_RGBA8, 4, 0, false, err_out);
}
-GPUTexture *GPU_texture_create_depth(int w, int h, char err_out[256])
+GPUTexture *GPU_texture_create_2D_custom(
+ int w, int h, int channels, GPUFormat data_type, const float *pixels, char err_out[256])
{
- GPUTexture *tex = GPU_texture_create_nD(w, h, 2, NULL, 1, GPU_HDR_NONE, 1, 0, err_out);
-
- if (tex)
- GPU_texture_unbind(tex);
-
- return tex;
+ return GPU_texture_create_nD(w, h, 0, 2, pixels, data_type, channels, 0, false, err_out);
}
-GPUTexture *GPU_texture_create_depth_multisample(int w, int h, int samples, char err_out[256])
-{
- GPUTexture *tex = GPU_texture_create_nD(w, h, 2, NULL, 1, GPU_HDR_NONE, 1, samples, err_out);
-
- if (tex)
- GPU_texture_unbind(tex);
- return tex;
+GPUTexture *GPU_texture_create_2D_multisample(int w, int h, const float *pixels, int samples, char err_out[256])
+{
+ return GPU_texture_create_nD(w, h, 0, 2, pixels, GPU_RGBA8, 4, samples, false, err_out);
}
-/**
- * A shadow map for VSM needs two components (depth and depth^2)
- */
-GPUTexture *GPU_texture_create_vsm_shadow_map(int size, char err_out[256])
+GPUTexture *GPU_texture_create_2D_array(int w, int h, int d, const float *pixels, char err_out[256])
{
- GPUTexture *tex = GPU_texture_create_nD(size, size, 2, NULL, 0, GPU_HDR_FULL_FLOAT, 2, 0, err_out);
-
- if (tex) {
- /* Now we tweak some of the settings */
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
-
- GPU_texture_unbind(tex);
- }
-
- return tex;
+ return GPU_texture_create_nD(w, h, d, 2, pixels, GPU_RGBA8, 4, 0, false, err_out);
}
-GPUTexture *GPU_texture_create_2D_procedural(int w, int h, const float *pixels, bool repeat, char err_out[256])
+GPUTexture *GPU_texture_create_3D(int w, int h, int d, const float *pixels, char err_out[256])
{
- GPUTexture *tex = GPU_texture_create_nD(w, h, 2, pixels, 0, GPU_HDR_HALF_FLOAT, 2, 0, err_out);
-
- if (tex) {
- /* Now we tweak some of the settings */
- if (repeat) {
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
- }
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
-
- GPU_texture_unbind(tex);
- }
-
- return tex;
+ return GPU_texture_create_nD(w, h, d, 3, pixels, GPU_RGBA8, 4, 0, true, err_out);
}
-GPUTexture *GPU_texture_create_1D_procedural(int w, const float *pixels, char err_out[256])
+GPUTexture *GPU_texture_create_3D_custom(int w, int h, int d, int channels, GPUFormat data_type, const float *pixels, char err_out[256])
{
- GPUTexture *tex = GPU_texture_create_nD(w, 0, 1, pixels, 0, GPU_HDR_HALF_FLOAT, 2, 0, err_out);
-
- if (tex) {
- /* Now we tweak some of the settings */
- glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_S, GL_REPEAT);
- glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
- glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ return GPU_texture_create_nD(w, h, d, 3, pixels, data_type, channels, 0, true, err_out);
+}
- GPU_texture_unbind(tex);
- }
+GPUTexture *GPU_texture_create_depth(int w, int h, char err_out[256])
+{
+ return GPU_texture_create_nD(w, h, 0, 2, NULL, GPU_DEPTH_COMPONENT24, 1, 0, false, err_out);
+}
- return tex;
+GPUTexture *GPU_texture_create_depth_multisample(int w, int h, int samples, char err_out[256])
+{
+ return GPU_texture_create_nD(w, h, 0, 2, NULL, GPU_DEPTH_COMPONENT24, 1, samples, false, err_out);
}
void GPU_invalid_tex_init(void)
{
const float color[4] = {1.0f, 0.0f, 1.0f, 1.0f};
GG.invalid_tex_1D = GPU_texture_create_1D(1, color, NULL);
- GG.invalid_tex_2D = GPU_texture_create_2D(1, 1, color, GPU_HDR_NONE, NULL);
- GG.invalid_tex_3D = GPU_texture_create_3D(1, 1, 1, 4, color);
+ GG.invalid_tex_2D = GPU_texture_create_2D(1, 1, color, NULL);
+ GG.invalid_tex_3D = GPU_texture_create_3D(1, 1, 1, color, NULL);
}
void GPU_invalid_tex_bind(int mode)
@@ -624,7 +597,13 @@ void GPU_texture_bind(GPUTexture *tex, int number)
else
GPU_invalid_tex_bind(tex->target_base);
- glEnable(tex->target_base); /* TODO: remove this line once we're using GLSL everywhere */
+ /* TODO: remove this lines */
+ GLenum target = tex->target_base;
+ if (tex->target_base == GL_TEXTURE_1D_ARRAY)
+ target = GL_TEXTURE_2D;
+ if (tex->target_base == GL_TEXTURE_2D_ARRAY)
+ target = GL_TEXTURE_3D;
+ glEnable(target);
if (number != 0)
glActiveTexture(GL_TEXTURE0);
@@ -646,7 +625,14 @@ void GPU_texture_unbind(GPUTexture *tex)
glActiveTexture(GL_TEXTURE0 + tex->number);
glBindTexture(tex->target_base, 0);
- glDisable(tex->target_base); /* TODO: remove this line */
+
+ /* TODO: remove this lines */
+ GLenum target = tex->target_base;
+ if (tex->target_base == GL_TEXTURE_1D_ARRAY)
+ target = GL_TEXTURE_2D;
+ if (tex->target_base == GL_TEXTURE_2D_ARRAY)
+ target = GL_TEXTURE_3D;
+ glDisable(target);
if (tex->number != 0)
glActiveTexture(GL_TEXTURE0);
@@ -659,7 +645,7 @@ int GPU_texture_bound_number(GPUTexture *tex)
return tex->number;
}
-void GPU_texture_filter_mode(GPUTexture *tex, bool compare, bool use_filter)
+void GPU_texture_compare_mode(GPUTexture *tex, bool use_compare)
{
if (tex->number >= GPU_max_textures()) {
fprintf(stderr, "Not enough texture slots.\n");
@@ -672,13 +658,53 @@ void GPU_texture_filter_mode(GPUTexture *tex, bool compare, bool use_filter)
if (tex->number != 0)
glActiveTexture(GL_TEXTURE0 + tex->number);
- if (tex->depth) {
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, compare ? GL_COMPARE_R_TO_TEXTURE : GL_NONE);
+ if (tex->depth)
+ glTexParameteri(tex->target_base, GL_TEXTURE_COMPARE_MODE, use_compare ? GL_COMPARE_R_TO_TEXTURE : GL_NONE);
+
+ if (tex->number != 0)
+ glActiveTexture(GL_TEXTURE0);
+}
+
+void GPU_texture_filter_mode(GPUTexture *tex, bool use_filter)
+{
+ if (tex->number >= GPU_max_textures()) {
+ fprintf(stderr, "Not enough texture slots.\n");
+ return;
}
+ if (tex->number == -1)
+ return;
+
+ if (tex->number != 0)
+ glActiveTexture(GL_TEXTURE0 + tex->number);
+
GLenum filter = use_filter ? GL_LINEAR : GL_NEAREST;
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filter);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filter);
+ glTexParameteri(tex->target_base, GL_TEXTURE_MAG_FILTER, filter);
+ glTexParameteri(tex->target_base, GL_TEXTURE_MIN_FILTER, filter);
+
+ if (tex->number != 0)
+ glActiveTexture(GL_TEXTURE0);
+}
+
+void GPU_texture_wrap_mode(GPUTexture *tex, bool use_repeat)
+{
+ if (tex->number >= GPU_max_textures()) {
+ fprintf(stderr, "Not enough texture slots.\n");
+ return;
+ }
+
+ if (tex->number == -1)
+ return;
+
+ if (tex->number != 0)
+ glActiveTexture(GL_TEXTURE0 + tex->number);
+
+ GLenum repeat = use_repeat ? GL_REPEAT : GL_CLAMP_TO_EDGE;
+ glTexParameteri(tex->target_base, GL_TEXTURE_WRAP_S, repeat);
+ if (tex->target_base != GL_TEXTURE_1D)
+ glTexParameteri(tex->target_base, GL_TEXTURE_WRAP_T, repeat);
+ if (tex->target_base == GL_TEXTURE_3D)
+ glTexParameteri(tex->target_base, GL_TEXTURE_WRAP_R, repeat);
if (tex->number != 0)
glActiveTexture(GL_TEXTURE0);
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 2f91adde133..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 <string.h>
+
+#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,26 +52,207 @@ 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 ********************/
bool GPU_viewport_debug_depth_create(GPUViewport *viewport, int width, int height, char err_out[256])
{
- viewport->debug_depth = GPU_texture_create_2D(width, height, NULL, GPU_HDR_HALF_FLOAT, err_out);
+ viewport->debug_depth = GPU_texture_create_2D_custom(width, height, 4, GPU_RGBA16F, NULL, err_out);
return (viewport->debug_depth != NULL);
}
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 d725a56d826..7b78d5123b2 100644
--- a/source/blender/makesdna/DNA_layer_types.h
+++ b/source/blender/makesdna/DNA_layer_types.h
@@ -55,6 +55,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 {
@@ -98,8 +99,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 cb267002a5f..9345129a504 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;
@@ -545,6 +546,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 */
typedef struct RenderData {
@@ -1713,6 +1758,9 @@ typedef struct Scene {
struct SceneCollection *collection;
int active_layer;
int pad4;
+
+ ListBase engines_settings; /* RenderEngineSettings */
+ int pad5[2];
} Scene;
/* **************** RENDERDATA ********************* */
@@ -1901,6 +1949,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 bc442692b67..48efee411bc 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 af15743f2d9..c8211886253 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