diff options
author | Clément Foucault <foucault.clem@gmail.com> | 2017-02-07 13:20:15 +0300 |
---|---|---|
committer | Dalai Felinto <dfelinto@gmail.com> | 2017-02-07 13:31:22 +0300 |
commit | 83adc544382689217e19564fd5f2dd62160956cb (patch) | |
tree | 1026a590c1079b4907a6cab43e2c5759339c4350 /source | |
parent | aeb8e81f2741aabc95d14bce7a83cef45481959c (diff) |
Clay-Engine (merge clay-engine)
Initial work by Clément Foucault with contributions from Dalai Felinto
(mainly per-collection engine settings logic, and depsgraph iterator placeholder).
This makes Blender require OpenGL 3.3. Which means Intel graphic card
and OSX will break. Disable CLAY_ENGINE in CMake in those cases.
This is a prototype render engine intended to help the design of real
render engines. This is mainly an engine with enphasis in matcap and
ambient occlusion.
Implemented Features
--------------------
* Clay Render Engine, following the new API, to be used as reference for
future engines
* A more complete Matcap customization with more options
* Per-Collection render engine settings
* New Ground Truth AO - not enabled
Missing Features
----------------
* Finish object edit mode
- Fix shaders to use new matrix
- Fix artifacts when edge does off screen
- Fix depth issue
- Selection sillhouette
- Mesh wires
- Use mesh normals (for higher quality matcap)
- Non-Mesh objects drawing
- Widget drawing
- Performance issues
* Finish mesh edit mode
- Derived-Mesh-less edit mode API (mesh_rende.c)
* General edit mode
- Per-collection edit mode settings
* General engines
- Per-collection engine settings
(they are their, but they still need to be flushed by depsgraph, and
used by the drawing code)
Diffstat (limited to 'source')
59 files changed, 5886 insertions, 32 deletions
diff --git a/source/blender/CMakeLists.txt b/source/blender/CMakeLists.txt index 6f2b78e0845..47ebed8f791 100644 --- a/source/blender/CMakeLists.txt +++ b/source/blender/CMakeLists.txt @@ -100,6 +100,7 @@ add_subdirectory(windowmanager) add_subdirectory(blenkernel) add_subdirectory(blenlib) add_subdirectory(bmesh) +add_subdirectory(draw) add_subdirectory(render) add_subdirectory(blenfont) add_subdirectory(blentranslation) diff --git a/source/blender/blenkernel/BKE_layer.h b/source/blender/blenkernel/BKE_layer.h index 850c63f535f..de8a577d272 100644 --- a/source/blender/blenkernel/BKE_layer.h +++ b/source/blender/blenkernel/BKE_layer.h @@ -39,13 +39,17 @@ extern "C" { #define TODO_LAYER_CONTEXT /* get/set current (context) SceneLayer */ #define TODO_LAYER_BASE /* BaseLegacy to Base related TODO */ #define TODO_LAYER_OPERATORS /* collection mamanger and property panel operators */ +#define TODO_LAYER_DEPSGRAPH /* placeholder for real Depsgraph fix */ #define TODO_LAYER /* generic todo */ -struct Base; -struct ID; +struct CollectionEngineSettings; struct LayerCollection; +struct ID; +struct ListBase; struct Main; struct Object; +struct Base; +struct RenderEngine; struct Scene; struct SceneCollection; struct SceneLayer; @@ -66,6 +70,9 @@ void BKE_scene_layer_base_deselect_all(struct SceneLayer *sl); void BKE_scene_layer_base_select(struct SceneLayer *sl, struct Base *selbase); void BKE_scene_layer_base_flag_recalculate(struct SceneLayer *sl); +void BKE_scene_layer_engine_settings_recalculate(struct SceneLayer *sl); +void BKE_scene_layer_engine_settings_update(struct SceneLayer *sl); + void BKE_layer_collection_free(struct SceneLayer *sl, struct LayerCollection *lc); struct LayerCollection *BKE_layer_collection_active(struct SceneLayer *sl); @@ -91,6 +98,24 @@ void BKE_layer_sync_object_unlink(struct Scene *scene, struct SceneCollection *s void BKE_collection_override_datablock_add(struct LayerCollection *lc, const char *data_path, struct ID *id); +/* engine settings */ +typedef void (*CollectionEngineSettingsCB)(struct RenderEngine *engine, struct CollectionEngineSettings *ces); +struct CollectionEngineSettings *BKE_layer_collection_engine_get(struct LayerCollection *lc, const char *engine_name); +void BKE_layer_collection_engine_settings_callback_register(struct Main *bmain, const char *engine_name, CollectionEngineSettingsCB func); +void BKE_layer_collection_engine_settings_callback_free(void); +void BKE_layer_collection_engine_settings_create(struct ListBase *lb, const char *engine_name); +void BKE_layer_collection_engine_settings_free(struct ListBase *lb); + +void BKE_collection_engine_property_add_float(struct CollectionEngineSettings *ces, const char *name, float value); +void BKE_collection_engine_property_add_int(struct CollectionEngineSettings *ces, const char *name, int value); +struct CollectionEngineProperty *BKE_collection_engine_property_get(struct CollectionEngineSettings *ces, const char *name); +int BKE_collection_engine_property_value_get_int(struct CollectionEngineSettings *ces, const char *name); +float BKE_collection_engine_property_value_get_float(struct CollectionEngineSettings *ces, const char *name); +void BKE_collection_engine_property_value_set_int(struct CollectionEngineSettings *ces, const char *name, int value); +void BKE_collection_engine_property_value_set_float(struct CollectionEngineSettings *ces, const char *name, float value); +bool BKE_collection_engine_property_use_get(struct CollectionEngineSettings *ces, const char *name); +void BKE_collection_engine_property_use_set(struct CollectionEngineSettings *ces, const char *name, bool value); + /* iterators */ void BKE_selected_objects_Iterator_begin(Iterator *iter, void *data_in); @@ -172,6 +197,9 @@ void BKE_visible_bases_Iterator_end(Iterator *iter); /* temporary hacky solution waiting for final depsgraph evaluation */ #define DEG_OBJECT_ITER(sl_, ob_) \ { \ + /* temporary solution, waiting for depsgraph update */ \ + BKE_scene_layer_engine_settings_update(sl); \ + \ /* flush all the data to objects*/ \ Base *base_; \ for (base_ = sl->object_bases.first; base_; base_ = base_->next) { \ diff --git a/source/blender/blenkernel/intern/layer.c b/source/blender/blenkernel/intern/layer.c index cec1d70463f..28c5e9aff5d 100644 --- a/source/blender/blenkernel/intern/layer.c +++ b/source/blender/blenkernel/intern/layer.c @@ -45,9 +45,12 @@ #include "MEM_guardedalloc.h" /* prototype */ +struct CollectionEngineSettingsCB_Type; static void layer_collection_free(SceneLayer *sl, LayerCollection *lc); static LayerCollection *layer_collection_add(SceneLayer *sl, ListBase *lb, SceneCollection *sc); static LayerCollection *find_layer_collection_by_scene_collection(LayerCollection *lc, const SceneCollection *sc); +static void collection_engine_settings_create(ListBase *lb, struct CollectionEngineSettingsCB_Type *ces_type); +static void layer_collection_create_engine_settings(LayerCollection *lc); static void object_bases_Iterator_next(Iterator *iter, const int flag); /* RenderLayer */ @@ -254,6 +257,35 @@ void BKE_scene_layer_base_flag_recalculate(SceneLayer *sl) base->flag &= ~BASE_SELECTED; } } + + BKE_scene_layer_engine_settings_recalculate(sl); +} + +/** + * Tag Scene Layer to recalculation + * + * Temporary function, waiting for real depsgraph + */ +void BKE_scene_layer_engine_settings_recalculate(struct SceneLayer *sl) +{ + sl->flag |= SCENE_LAYER_ENGINE_DIRTY; +} + +/** + * Re-calculate the engine settings for all the objects in SceneLayer + * + * Temporary function, waiting for real depsgraph + */ +void BKE_scene_layer_engine_settings_update(struct SceneLayer *sl) +{ + if ((sl->flag & SCENE_LAYER_ENGINE_DIRTY) == 0) { + return; + } + + /* do the complete settings update */ + TODO_LAYER_DEPSGRAPH; + + sl->flag &= ~SCENE_LAYER_ENGINE_DIRTY; } /** @@ -292,10 +324,12 @@ static void layer_collection_free(SceneLayer *sl, LayerCollection *lc) BLI_freelistN(&lc->object_bases); BLI_freelistN(&lc->overrides); + BKE_layer_collection_engine_settings_free(&lc->engine_settings); for (LayerCollection *nlc = lc->layer_collections.first; nlc; nlc = nlc->next) { layer_collection_free(sl, nlc); } + BLI_freelistN(&lc->layer_collections); } @@ -467,6 +501,7 @@ static LayerCollection *layer_collection_add(SceneLayer *sl, ListBase *lb, Scene lc->scene_collection = sc; lc->flag = COLLECTION_VISIBLE + COLLECTION_SELECTABLE + COLLECTION_FOLDED; + layer_collection_create_engine_settings(lc); layer_collection_populate(sl, lc, sc); return lc; } @@ -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; +} + +float BKE_collection_engine_property_value_get_float(CollectionEngineSettings *ces, const char *name) +{ + CollectionEnginePropertyFloat *prop; + prop = (CollectionEnginePropertyFloat *)BLI_findstring(&ces->properties, name, offsetof(CollectionEngineProperty, name)); + return prop->value; +} + +void BKE_collection_engine_property_value_set_int(CollectionEngineSettings *ces, const char *name, int value) +{ + CollectionEnginePropertyInt *prop; + prop = (CollectionEnginePropertyInt *)BLI_findstring(&ces->properties, name, offsetof(CollectionEngineProperty, name)); + prop->value = value; + prop->data.flag |= COLLECTION_PROP_USE; +} + +void BKE_collection_engine_property_value_set_float(CollectionEngineSettings *ces, const char *name, float value) +{ + CollectionEnginePropertyFloat *prop; + prop = (CollectionEnginePropertyFloat *)BLI_findstring(&ces->properties, name, offsetof(CollectionEngineProperty, name)); + prop->value = value; + prop->data.flag |= COLLECTION_PROP_USE; +} + +bool BKE_collection_engine_property_use_get(CollectionEngineSettings *ces, const char *name) +{ + CollectionEngineProperty *prop; + prop = (CollectionEngineProperty *)BLI_findstring(&ces->properties, name, offsetof(CollectionEngineProperty, name)); + return ((prop->flag & COLLECTION_PROP_USE) != 0); +} + +void BKE_collection_engine_property_use_set(CollectionEngineSettings *ces, const char *name, bool value) +{ + CollectionEngineProperty *prop; + prop = (CollectionEngineProperty *)BLI_findstring(&ces->properties, name, offsetof(CollectionEngineProperty, name)); + + if (value) { + prop->flag |= COLLECTION_PROP_USE; + } + else { + prop->flag &= ~COLLECTION_PROP_USE; + } +} + +/* ---------------------------------------------------------------------- */ /* Iterators */ 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 d47982f96eb..1ce4bf8f9eb 100644 --- a/source/blender/blenkernel/intern/scene.c +++ b/source/blender/blenkernel/intern/scene.c @@ -109,6 +109,7 @@ const char *RE_engine_id_BLENDER_RENDER = "BLENDER_RENDER"; const char *RE_engine_id_BLENDER_GAME = "BLENDER_GAME"; +const char *RE_engine_id_BLENDER_CLAY = "BLENDER_CLAY"; const char *RE_engine_id_CYCLES = "CYCLES"; void free_avicodecdata(AviCodecData *acd) @@ -566,6 +567,13 @@ void BKE_scene_free(Scene *sce) BKE_collection_master_free(sce); MEM_freeN(sce->collection); sce->collection = NULL; + + /* Runtime Engine Data */ + for (RenderEngineSettings *res = sce->engines_settings.first; res; res = res->next) { + if (res->data) + MEM_freeN(res->data); + } + BLI_freelistN(&sce->engines_settings); } void BKE_scene_init(Scene *sce) diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c index e669bf3b4a6..da0650d02f5 100644 --- a/source/blender/blenloader/intern/readfile.c +++ b/source/blender/blenloader/intern/readfile.c @@ -3970,6 +3970,7 @@ static void lib_link_material(FileData *fd, Main *main) static void direct_link_material(FileData *fd, Material *ma) { int a; + MaterialEngineSettings *mes; ma->adt = newdataadr(fd, ma->adt); direct_link_animdata(fd, ma->adt); @@ -3990,6 +3991,11 @@ static void direct_link_material(FileData *fd, Material *ma) ma->preview = direct_link_preview_image(fd, ma->preview); BLI_listbase_clear(&ma->gpumaterial); + + link_list(fd, &ma->engines_settings); + for (mes = ma->engines_settings.first; mes; mes = mes->next) { + mes->data = newdataadr(fd, mes->data); + } } /* ************ READ PARTICLE SETTINGS ***************** */ @@ -5552,6 +5558,7 @@ static void direct_link_object(FileData *fd, Object *ob) ob->bb = NULL; ob->derivedDeform = NULL; ob->derivedFinal = NULL; + ob->collection_settings = NULL; BLI_listbase_clear(&ob->gpulamp); link_list(fd, &ob->pc_ids); @@ -5924,6 +5931,14 @@ static void direct_link_scene_collection(FileData *fd, SceneCollection *sc) } } +static void direct_link_engine_settings(FileData *fd, ListBase *lb) +{ + link_list(fd, lb); + for (CollectionEngineSettings *ces = lb->first; ces; ces = ces->next) { + link_list(fd, &ces->properties); + } +} + static void direct_link_layer_collections(FileData *fd, ListBase *lb) { link_list(fd, lb); @@ -5938,6 +5953,8 @@ static void direct_link_layer_collections(FileData *fd, ListBase *lb) link_list(fd, &lc->overrides); + direct_link_engine_settings(fd, &lc->engine_settings); + direct_link_layer_collections(fd, &lc->layer_collections); } } @@ -5950,6 +5967,7 @@ static void direct_link_scene(FileData *fd, Scene *sce) RigidBodyWorld *rbw; SceneLayer *sl; SceneRenderLayer *srl; + RenderEngineSettings *res; sce->theDag = NULL; sce->depsgraph = NULL; @@ -6212,6 +6230,11 @@ static void direct_link_scene(FileData *fd, Scene *sce) sl->basact = newdataadr(fd, sl->basact); direct_link_layer_collections(fd, &sl->layer_collections); } + + link_list(fd, &sce->engines_settings); + for (res = sce->engines_settings.first; res; res = res->next) { + res->data = newdataadr(fd, res->data); + } } /* ************ READ WM ***************** */ diff --git a/source/blender/blenloader/intern/versioning_280.c b/source/blender/blenloader/intern/versioning_280.c index a4e69c9d514..89ee05ee3e7 100644 --- a/source/blender/blenloader/intern/versioning_280.c +++ b/source/blender/blenloader/intern/versioning_280.c @@ -30,6 +30,7 @@ #include "DNA_object_types.h" #include "DNA_layer_types.h" +#include "DNA_material_types.h" #include "DNA_scene_types.h" #include "DNA_genfile.h" diff --git a/source/blender/blenloader/intern/writefile.c b/source/blender/blenloader/intern/writefile.c index 4ddf83d306b..0ad879b9aa6 100644 --- a/source/blender/blenloader/intern/writefile.c +++ b/source/blender/blenloader/intern/writefile.c @@ -1894,6 +1894,8 @@ static void write_objects(WriteData *wd, ListBase *idbase) writelist(wd, DATA, LinkData, &ob->pc_ids); writelist(wd, DATA, LodLevel, &ob->lodlevels); + + ob->collection_settings = NULL; } write_previews(wd, ob->preview); @@ -2469,6 +2471,21 @@ static void write_textures(WriteData *wd, ListBase *idbase) mywrite_flush(wd); } +static void write_material_engines_settings(WriteData *wd, ListBase *lb) +{ + for (MaterialEngineSettings *res = lb->first; res; res = res->next) { + writestruct(wd, DATA, MaterialEngineSettings, 1, res); + + if (STREQ(res->name, RE_engine_id_BLENDER_CLAY)) { + writestruct(wd, DATA, MaterialEngineSettingsClay, 1, res->data); + } + else { + /* No engine matched */ + /* error: don't know how to write this file */ + } + } +} + static void write_materials(WriteData *wd, ListBase *idbase) { Material *ma; @@ -2505,6 +2522,8 @@ static void write_materials(WriteData *wd, ListBase *idbase) } write_previews(wd, ma->preview); + + write_material_engines_settings(wd, &ma->engines_settings); } ma = ma->id.next; } @@ -2639,6 +2658,26 @@ static void write_scene_collection(WriteData *wd, SceneCollection *sc) } } +static void write_collection_engine_settings(WriteData *wd, ListBase *lb) +{ + for (CollectionEngineSettings *ces = lb->first; ces; ces = ces->next) { + writestruct(wd, DATA, CollectionEngineSettings, 1, ces); + + for (CollectionEngineProperty *prop = ces->properties.first; prop; prop = prop->next) { + switch (prop->type) { + case COLLECTION_PROP_TYPE_FLOAT: + writestruct(wd, DATA, CollectionEnginePropertyFloat, 1, prop); + break; + case COLLECTION_PROP_TYPE_INT: + writestruct(wd, DATA, CollectionEnginePropertyInt, 1, prop); + break; + default: + ; /* error: don't know how to write this file */ + } + } + } +} + static void write_layer_collections(WriteData *wd, ListBase *lb) { for (LayerCollection *lc = lb->first; lc; lc = lc->next) { @@ -2647,10 +2686,27 @@ static void write_layer_collections(WriteData *wd, ListBase *lb) writelist(wd, DATA, LinkData, &lc->object_bases); writelist(wd, DATA, CollectionOverride, &lc->overrides); + write_collection_engine_settings(wd, &lc->engine_settings); + write_layer_collections(wd, &lc->layer_collections); } } +static void write_render_engines_settings(WriteData *wd, ListBase *lb) +{ + for (RenderEngineSettings *res = lb->first; res; res = res->next) { + writestruct(wd, DATA, RenderEngineSettings, 1, res); + + if (STREQ(res->name, RE_engine_id_BLENDER_CLAY)) { + writestruct(wd, DATA, RenderEngineSettingsClay, 1, res->data); + } + else { + /* No engine matched */ + /* error: don't know how to write this file */ + } + } +} + static void write_scenes(WriteData *wd, ListBase *scebase) { Scene *sce; @@ -2880,6 +2936,8 @@ static void write_scenes(WriteData *wd, ListBase *scebase) write_layer_collections(wd, &sl->layer_collections); } + write_render_engines_settings(wd, &sce->engines_settings); + sce = sce->id.next; } diff --git a/source/blender/draw/CMakeLists.txt b/source/blender/draw/CMakeLists.txt index 60449ebc600..d5b54e8a746 100644 --- a/source/blender/draw/CMakeLists.txt +++ b/source/blender/draw/CMakeLists.txt @@ -26,37 +26,53 @@ set(INC . intern - nodes - operations + engines/clay + ../blenkernel ../blenlib ../blentranslation ../imbuf + ../depsgraph ../makesdna ../makesrna - ../windowmanager - ../nodes - ../nodes/composite - ../nodes/intern + ../gpu + ../editors/include + ../editors/space_view3d ../render/extern/include ../render/intern/include - ../../../extern/clew/include + + ../../../intern/glew-mx ../../../intern/guardedalloc - ../../../intern/atomic ) set(INC_SYS - + ${GLEW_INCLUDE_PATH} ) set(SRC - DRW_defines.h + intern/draw_manager.c + intern/draw_mode_pass.c + intern/draw_cache.c + engines/clay/clay.c -) + intern/DRW_render.h + intern/draw_mode_pass.h + intern/draw_cache.h + engines/clay/clay.h -list(APPEND INC + ./DRW_engine.h ) +if(WITH_CLAY_ENGINE) + add_definitions(-DWITH_CLAY_ENGINE) endif() +data_to_c_simple(engines/clay/shaders/clay_frag.glsl SRC) +data_to_c_simple(engines/clay/shaders/clay_vert.glsl SRC) +data_to_c_simple(engines/clay/shaders/ssao_alchemy.glsl SRC) +data_to_c_simple(engines/clay/shaders/ssao_groundtruth.glsl SRC) + +list(APPEND INC +) + blender_add_lib(bf_draw "${SRC}" "${INC}" "${INC_SYS}") diff --git a/source/blender/draw/DRW_engine.h b/source/blender/draw/DRW_engine.h new file mode 100644 index 00000000000..4f86e3fcd91 --- /dev/null +++ b/source/blender/draw/DRW_engine.h @@ -0,0 +1,45 @@ +/* + * Copyright 2016, Blender Foundation. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Contributor(s): Blender Institute + * + */ + +/** \file DRW_engine.h + * \ingroup draw + */ + +#ifndef __DRW_ENGINE_H__ +#define __DRW_ENGINE_H__ + +//#define WITH_VIEWPORT_CACHE_TEST + +struct DRWPass; +struct Material; +struct Scene; + +void DRW_engines_init(void); +void DRW_engines_free(void); + +/* This is here because GPUViewport needs it */ +void DRW_pass_free(struct DRWPass *pass); + +/* Settings */ +void *DRW_material_settings_get(struct Material *ma, const char *engine_name); +void *DRW_render_settings_get(struct Scene *scene, const char *engine_name); + +#endif /* __DRW_ENGINE_H__ */
\ No newline at end of file diff --git a/source/blender/draw/DRW_engines.h b/source/blender/draw/DRW_engines.h deleted file mode 100644 index e69de29bb2d..00000000000 --- a/source/blender/draw/DRW_engines.h +++ /dev/null diff --git a/source/blender/draw/engines/clay/clay.c b/source/blender/draw/engines/clay/clay.c new file mode 100644 index 00000000000..f443606f11d --- /dev/null +++ b/source/blender/draw/engines/clay/clay.c @@ -0,0 +1,722 @@ +/* + * Copyright 2016, Blender Foundation. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Contributor(s): Blender Institute + * + */ + +#include "DRW_render.h" + +#include "BKE_icons.h" +#include "BKE_main.h" + +#include "BLI_dynstr.h" +#include "BLI_rand.h" + +#include "IMB_imbuf.h" +#include "IMB_imbuf_types.h" + +#include "UI_resources.h" +#include "UI_interface_icons.h" + +#include "clay.h" +#ifdef WITH_CLAY_ENGINE +/* Shaders */ + +extern char datatoc_clay_frag_glsl[]; +extern char datatoc_clay_vert_glsl[]; +extern char datatoc_ssao_alchemy_glsl[]; +extern char datatoc_ssao_groundtruth_glsl[]; + +/* Storage */ + +/* UBOs data needs to be 16 byte aligned (size of vec4) */ +/* Reminder : float, int, bool are 4 bytes */ +typedef struct CLAY_UBO_Material { + float ssao_params_var[4]; + /* - 16 -*/ + float matcap_hsv[3]; + float matcap_id; /* even float encoding have enough precision */ + /* - 16 -*/ + float matcap_rot[2]; + float pad[2]; /* ensure 16 bytes alignement */ +} CLAY_UBO_Material; /* 48 bytes */ + +typedef struct CLAY_UBO_Storage { + CLAY_UBO_Material materials[512]; /* 512 = 9 bit material id */ +} CLAY_UBO_Storage; + +static struct CLAY_data { + /* Depth Pre Pass */ + struct GPUShader *depth_sh; + /* Shading Pass */ + struct GPUShader *clay_sh; + + /* Materials Parameter UBO */ + struct GPUUniformBuffer *mat_ubo; + CLAY_UBO_Storage mat_storage; + short ubo_flag; + + /* Matcap textures */ + struct GPUTexture *matcap_array; + float matcap_colors[24][3]; + + /* Ssao */ + float winmat[4][4]; + float viewvecs[3][4]; + float ssao_params[4]; + struct GPUTexture *jitter_tx; + struct GPUTexture *sampling_tx; +} data = {NULL}; + +/* CLAY_data.ubo_flag */ +enum { + CLAY_UBO_CLEAR = (1 << 0), + CLAY_UBO_REFRESH = (1 << 1), +}; + +/* keep it under MAX_BUFFERS */ +typedef struct CLAY_FramebufferList{ + /* default */ + struct GPUFrameBuffer *default_fb; + /* engine specific */ + struct GPUFrameBuffer *downsample_depth; +} CLAY_FramebufferList; + +/* keep it under MAX_TEXTURES */ +typedef struct CLAY_TextureList{ + /* default */ + struct GPUTexture *color; + struct GPUTexture *depth; + /* engine specific */ + struct GPUTexture *depth_low; +} CLAY_TextureList; + +/* for clarity follow the same layout as CLAY_TextureList */ +enum { + SCENE_COLOR, + SCENE_DEPTH, + SCENE_DEPTH_LOW, +}; + +/* keep it under MAX_PASSES */ +typedef struct CLAY_PassList{ + /* default */ + struct DRWPass *non_meshes_pass; + struct DRWPass *ob_center_pass; + /* engine specific */ + struct DRWPass *depth_pass; + struct DRWPass *clay_pass; + struct DRWPass *wire_overlay_pass; + struct DRWPass *wire_outline_pass; +} CLAY_PassList; + +//#define GTAO + +/* Functions */ + +static void add_icon_to_rect(PreviewImage *prv, float *final_rect, int layer) +{ + int image_size = prv->w[0] * prv->h[0]; + float *new_rect = &final_rect[image_size * 4 * layer]; + + IMB_buffer_float_from_byte(new_rect, (unsigned char *)prv->rect[0], IB_PROFILE_SRGB, IB_PROFILE_SRGB, + false, prv->w[0], prv->h[0], prv->w[0], prv->w[0]); + + /* Find overall color */ + for (int y = 0; y < 4; ++y) { + for (int x = 0; x < 4; ++x) { + data.matcap_colors[layer][0] += new_rect[y * 512 * 128 * 4 + x * 128 * 4 + 0]; + data.matcap_colors[layer][1] += new_rect[y * 512 * 128 * 4 + x * 128 * 4 + 1]; + data.matcap_colors[layer][2] += new_rect[y * 512 * 128 * 4 + x * 128 * 4 + 2]; + } + } + + data.matcap_colors[layer][0] /= 16.0f * 2.0f; /* the * 2 is to darken for shadows */ + data.matcap_colors[layer][1] /= 16.0f * 2.0f; + data.matcap_colors[layer][2] /= 16.0f * 2.0f; +} + +static struct GPUTexture *load_matcaps(PreviewImage *prv[24], int nbr) +{ + struct GPUTexture *tex; + int w = prv[0]->w[0]; + int h = prv[0]->h[0]; + float *final_rect = MEM_callocN(sizeof(float) * 4 * w * h * nbr, "Clay Matcap array rect"); + + for (int i = 0; i < nbr; ++i) { + add_icon_to_rect(prv[i], final_rect, i); + BKE_previewimg_free(&prv[i]); + } + + tex = DRW_texture_create_2D_array(w, h, nbr, DRW_TEX_RGBA_8, DRW_TEX_FILTER, final_rect); + MEM_freeN(final_rect); + + return tex; +} + +static int matcap_to_index(int matcap) +{ + if (matcap == ICON_MATCAP_02) return 1; + else if (matcap == ICON_MATCAP_03) return 2; + else if (matcap == ICON_MATCAP_04) return 3; + else if (matcap == ICON_MATCAP_05) return 4; + else if (matcap == ICON_MATCAP_06) return 5; + else if (matcap == ICON_MATCAP_07) return 6; + else if (matcap == ICON_MATCAP_08) return 7; + else if (matcap == ICON_MATCAP_09) return 8; + else if (matcap == ICON_MATCAP_10) return 9; + else if (matcap == ICON_MATCAP_11) return 10; + else if (matcap == ICON_MATCAP_12) return 11; + else if (matcap == ICON_MATCAP_13) return 12; + else if (matcap == ICON_MATCAP_14) return 13; + else if (matcap == ICON_MATCAP_15) return 14; + else if (matcap == ICON_MATCAP_16) return 15; + else if (matcap == ICON_MATCAP_17) return 16; + else if (matcap == ICON_MATCAP_18) return 17; + else if (matcap == ICON_MATCAP_19) return 18; + else if (matcap == ICON_MATCAP_20) return 19; + else if (matcap == ICON_MATCAP_21) return 20; + else if (matcap == ICON_MATCAP_22) return 21; + else if (matcap == ICON_MATCAP_23) return 22; + else if (matcap == ICON_MATCAP_24) return 23; + return 0; +} + +static struct GPUTexture *create_spiral_sample_texture(int numsaples) +{ + struct GPUTexture *tex; + float (*texels)[2] = MEM_mallocN(sizeof(float[2]) * numsaples, "concentric_tex"); + const float numsaples_inv = 1.0f / numsaples; + int i; + /* arbitrary number to ensure we don't get conciding samples every circle */ + const float spirals = 7.357; + + for (i = 0; i < numsaples; i++) { + float r = (i + 0.5f) * numsaples_inv; + float phi = r * spirals * (float)(2.0 * M_PI); + texels[i][0] = r * cosf(phi); + texels[i][1] = r * sinf(phi); + } + + tex = DRW_texture_create_1D(numsaples, DRW_TEX_RG_16, 0, (float *)texels); + + MEM_freeN(texels); + return tex; +} + +static struct GPUTexture *create_jitter_texture(void) +{ + float jitter[64 * 64][2]; + int i; + + /* TODO replace by something more evenly distributed like blue noise */ + for (i = 0; i < 64 * 64; i++) { +#ifdef GTAO + jitter[i][0] = BLI_frand(); + jitter[i][1] = BLI_frand(); +#else + jitter[i][0] = 2.0f * BLI_frand() - 1.0f; + jitter[i][1] = 2.0f * BLI_frand() - 1.0f; + normalize_v2(jitter[i]); +#endif + } + + return DRW_texture_create_2D(64, 64, DRW_TEX_RG_16, DRW_TEX_FILTER | DRW_TEX_WRAP, &jitter[0][0]); +} + +static void clay_material_settings_init(MaterialEngineSettingsClay *ma) +{ + ma->matcap_icon = ICON_MATCAP_01; + ma->matcap_rot = 0.0f; + ma->matcap_hue = 0.5f; + ma->matcap_sat = 0.5f; + ma->matcap_val = 0.5f; + ma->ssao_distance = 0.2; + ma->ssao_attenuation = 1.0f; + ma->ssao_factor_cavity = 1.0f; + ma->ssao_factor_edge = 1.0f; +} + +RenderEngineSettings *CLAY_render_settings_create(void) +{ + RenderEngineSettingsClay *settings = MEM_callocN(sizeof(RenderEngineSettingsClay), "RenderEngineSettingsClay"); + + clay_material_settings_init((MaterialEngineSettingsClay *)settings); + + settings->ssao_samples = 32; + + return (RenderEngineSettings *)settings; +} + +MaterialEngineSettings *CLAY_material_settings_create(void) +{ + MaterialEngineSettingsClay *settings = MEM_callocN(sizeof(MaterialEngineSettingsClay), "MaterialEngineSettingsClay"); + + clay_material_settings_init(settings); + + return (MaterialEngineSettings *)settings; +} + +static void CLAY_engine_init(const bContext *C) +{ + Main *bmain = CTX_data_main(C); + + /* Create Texture Array */ + if (!data.matcap_array) { + PreviewImage *prv[24]; /* For now use all of the 24 internal matcaps */ + + /* TODO only load used matcaps */ + prv[0] = UI_icon_to_preview(ICON_MATCAP_01); + prv[1] = UI_icon_to_preview(ICON_MATCAP_02); + prv[2] = UI_icon_to_preview(ICON_MATCAP_03); + prv[3] = UI_icon_to_preview(ICON_MATCAP_04); + prv[4] = UI_icon_to_preview(ICON_MATCAP_05); + prv[5] = UI_icon_to_preview(ICON_MATCAP_06); + prv[6] = UI_icon_to_preview(ICON_MATCAP_07); + prv[7] = UI_icon_to_preview(ICON_MATCAP_08); + prv[8] = UI_icon_to_preview(ICON_MATCAP_09); + prv[9] = UI_icon_to_preview(ICON_MATCAP_10); + prv[10] = UI_icon_to_preview(ICON_MATCAP_11); + prv[11] = UI_icon_to_preview(ICON_MATCAP_12); + prv[12] = UI_icon_to_preview(ICON_MATCAP_13); + prv[13] = UI_icon_to_preview(ICON_MATCAP_14); + prv[14] = UI_icon_to_preview(ICON_MATCAP_15); + prv[15] = UI_icon_to_preview(ICON_MATCAP_16); + prv[16] = UI_icon_to_preview(ICON_MATCAP_17); + prv[17] = UI_icon_to_preview(ICON_MATCAP_18); + prv[18] = UI_icon_to_preview(ICON_MATCAP_19); + prv[19] = UI_icon_to_preview(ICON_MATCAP_20); + prv[20] = UI_icon_to_preview(ICON_MATCAP_21); + prv[21] = UI_icon_to_preview(ICON_MATCAP_22); + prv[22] = UI_icon_to_preview(ICON_MATCAP_23); + prv[23] = UI_icon_to_preview(ICON_MATCAP_24); + + data.matcap_array = load_matcaps(prv, 24); + } + + /* AO Jitter */ + if (!data.jitter_tx) { + data.jitter_tx = create_jitter_texture(); + } + + /* AO Samples */ + /* TODO use hammersley sequence */ + if (!data.sampling_tx) { + data.sampling_tx = create_spiral_sample_texture(500); + } + + /* Depth prepass */ + if (!data.depth_sh) { + data.depth_sh = DRW_shader_create_3D_depth_only(); + } + + if (!data.mat_ubo) { + data.mat_ubo = DRW_uniformbuffer_create(sizeof(CLAY_UBO_Storage), NULL); + } + + /* Shading pass */ + if (!data.clay_sh) { + DynStr *ds = BLI_dynstr_new(); + const char *max_mat = + "#define MAX_MATERIAL 512\n" + "#define USE_ROTATION\n" + "#define USE_AO\n" + "#define USE_HSV\n"; + char *matcap_with_ao; + + BLI_dynstr_append(ds, datatoc_clay_frag_glsl); +#ifdef GTAO + BLI_dynstr_append(ds, datatoc_ssao_groundtruth_glsl); +#else + BLI_dynstr_append(ds, datatoc_ssao_alchemy_glsl); +#endif + + matcap_with_ao = BLI_dynstr_get_cstring(ds); + + data.clay_sh = DRW_shader_create(datatoc_clay_vert_glsl, NULL, matcap_with_ao, max_mat); + + BLI_dynstr_free(ds); + MEM_freeN(matcap_with_ao); + } + + /* Cleanup all runtime data loaded from file */ + for (Scene *sce = bmain->scene.first; sce; sce = sce->id.next) { + /* Using render settings as material settings */ + MaterialEngineSettingsClay *res = DRW_render_settings_get(sce, RE_engine_id_BLENDER_CLAY); + res->flag = CLAY_OUTDATED; + res->ubo_index = -1; + + /* Update Collections Materials */ + for (SceneLayer *sl = sce->render_layers.first; sl; sl = sl->next) { + for (LayerCollection *lc = sl->layer_collections.first; lc; lc = lc->next) { + CollectionEngineSettings *ces; + ces = BKE_layer_collection_engine_get(lc, RE_engine_id_BLENDER_CLAY); + if (ces) { /* May not exists */ + BKE_collection_engine_property_value_set_int(ces, "flag", CLAY_OUTDATED); + BKE_collection_engine_property_value_set_int(ces, "ubo_index", -1); + } + } + } + } + + data.ubo_flag |= CLAY_UBO_REFRESH; +} + +static void CLAY_ssao_setup(void) +{ + float invproj[4][4]; + float dfdyfacs[2]; + bool is_persp = DRW_viewport_is_persp_get(); + /* view vectors for the corners of the view frustum. Can be used to recreate the world space position easily */ + float viewvecs[3][4] = { + {-1.0f, -1.0f, -1.0f, 1.0f}, + {1.0f, -1.0f, -1.0f, 1.0f}, + {-1.0f, 1.0f, -1.0f, 1.0f} + }; + int i; + float *size = DRW_viewport_size_get(); + RenderEngineSettingsClay *settings = DRW_render_settings_get(NULL, RE_engine_id_BLENDER_CLAY); + + DRW_get_dfdy_factors(dfdyfacs); + + data.ssao_params[0] = settings->ssao_samples; + data.ssao_params[1] = size[0] / 64.0; + data.ssao_params[2] = size[1] / 64.0; + data.ssao_params[3] = dfdyfacs[1]; /* dfdy sign for offscreen */ + + /* invert the view matrix */ + DRW_viewport_matrix_get(data.winmat, DRW_MAT_WIN); + invert_m4_m4(invproj, data.winmat); + + /* convert the view vectors to view space */ + for (i = 0; i < 3; i++) { + mul_m4_v4(invproj, viewvecs[i]); + /* normalized trick see http://www.derschmale.com/2014/01/26/reconstructing-positions-from-the-depth-buffer */ + mul_v3_fl(viewvecs[i], 1.0f / viewvecs[i][3]); + if (is_persp) + mul_v3_fl(viewvecs[i], 1.0f / viewvecs[i][2]); + viewvecs[i][3] = 1.0; + + copy_v4_v4(data.viewvecs[i], viewvecs[i]); + } + + /* we need to store the differences */ + data.viewvecs[1][0] -= data.viewvecs[0][0]; + data.viewvecs[1][1] = data.viewvecs[2][1] - data.viewvecs[0][1]; + + /* calculate a depth offset as well */ + if (!is_persp) { + float vec_far[] = {-1.0f, -1.0f, 1.0f, 1.0f}; + mul_m4_v4(invproj, vec_far); + mul_v3_fl(vec_far, 1.0f / vec_far[3]); + data.viewvecs[1][2] = vec_far[2] - data.viewvecs[0][2]; + } +} + +static DRWShadingGroup *CLAY_shgroup_create(DRWPass *pass, int *UNUSED(material_id)) +{ + const int depthloc = 0, matcaploc = 1, jitterloc = 2, sampleloc = 3; + + //CLAY_UBO_Material *mat = &data.mat_storage.materials[0]; + DRWShadingGroup *grp = DRW_shgroup_create(data.clay_sh, pass); + + DRW_shgroup_uniform_vec2(grp, "screenres", DRW_viewport_size_get(), 1); + DRW_shgroup_uniform_buffer(grp, "depthtex", SCENE_DEPTH, depthloc); + DRW_shgroup_uniform_texture(grp, "matcaps", data.matcap_array, matcaploc); + DRW_shgroup_uniform_mat4(grp, "WinMatrix", (float *)data.winmat); + DRW_shgroup_uniform_vec4(grp, "viewvecs", (float *)data.viewvecs, 3); + DRW_shgroup_uniform_vec4(grp, "ssao_params", data.ssao_params, 1); + DRW_shgroup_uniform_vec3(grp, "matcaps_color", (float *)data.matcap_colors, 24); + + //DRW_shgroup_uniform_int(grp, "material_id", material_id, 1); + +#ifndef GTAO + DRW_shgroup_uniform_texture(grp, "ssao_jitter", data.jitter_tx, jitterloc); + DRW_shgroup_uniform_texture(grp, "ssao_samples", data.sampling_tx, sampleloc); +#endif + + return grp; +} + +static void update_ubo_storage(float matcap_rot, float matcap_hue, float matcap_sat, float matcap_val, + float ssao_distance, float ssao_factor_cavity, float ssao_factor_edge, + float ssao_attenuation, int matcap_icon, unsigned int current_id) +{ + CLAY_UBO_Material *ubo = &data.mat_storage.materials[current_id]; + + ubo->matcap_rot[0] = cosf(matcap_rot * 3.14159f * 2.0f); + ubo->matcap_rot[1] = sinf(matcap_rot * 3.14159f * 2.0f); + + ubo->matcap_hsv[0] = matcap_hue + 0.5f; + ubo->matcap_hsv[1] = matcap_sat * 2.0f; + ubo->matcap_hsv[2] = matcap_val * 2.0f; + + ubo->ssao_params_var[0] = ssao_distance; + ubo->ssao_params_var[1] = ssao_factor_cavity; + ubo->ssao_params_var[2] = ssao_factor_edge; + ubo->ssao_params_var[3] = ssao_attenuation; + + + ubo->matcap_id = matcap_to_index(matcap_icon); +} + +static void CLAY_update_material_ubo(const struct bContext *C) +{ + Main *bmain = CTX_data_main(C); + + /* Update Default materials */ + for (Scene *sce = bmain->scene.first; sce; sce = sce->id.next) { + /* Using render settings as material settings */ + MaterialEngineSettingsClay *res = DRW_render_settings_get(sce, RE_engine_id_BLENDER_CLAY); + + if (res->flag & CLAY_OUTDATED) + data.ubo_flag |= CLAY_UBO_REFRESH; + + if (res->matcap_icon < ICON_MATCAP_01 || + res->matcap_icon > ICON_MATCAP_24) + { + res->matcap_icon = ICON_MATCAP_01; + } + + res->flag &= ~CLAY_OUTDATED; + + + /* Update Collections Materials */ + for (SceneLayer *sl = sce->render_layers.first; sl; sl = sl->next) { + for (LayerCollection *lc = sl->layer_collections.first; lc; lc = lc->next) { + CollectionEngineSettings *ces; + ces = BKE_layer_collection_engine_get(lc, RE_engine_id_BLENDER_CLAY); + + BKE_collection_engine_property_value_set_int(ces, "flag", 0); + BKE_collection_engine_property_value_set_int(ces, "ubo_index", 0); + } + } + } + + if (data.ubo_flag & CLAY_UBO_REFRESH) { + int current_id = 0; + + + /* Default materials */ + for (Scene *sce = bmain->scene.first; sce; sce = sce->id.next) { + MaterialEngineSettingsClay *res = DRW_render_settings_get(sce, RE_engine_id_BLENDER_CLAY); + + update_ubo_storage(res->matcap_rot, res->matcap_hue, res->matcap_sat, res->matcap_val, + res->ssao_distance, res->ssao_factor_cavity, res->ssao_factor_edge, + res->ssao_attenuation, res->matcap_icon, current_id); + current_id++; + + for (SceneLayer *sl = sce->render_layers.first; sl; sl = sl->next) { + for (LayerCollection *lc = sl->layer_collections.first; lc; lc = lc->next) { + /* TODO */ + current_id++; + } + } + current_id++; + } + + + DRW_uniformbuffer_update(data.mat_ubo, &data.mat_storage); + } + + data.ubo_flag = 0; +} + +static void CLAY_create_cache(CLAY_PassList *passes, const struct bContext *C) +{ + SceneLayer *sl = CTX_data_scene_layer(C); + DRWShadingGroup *default_shgrp, *depthbatch; + + /* Depth Pass */ + { + passes->depth_pass = DRW_pass_create("Depth Pass", DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS); + + depthbatch = DRW_shgroup_create(data.depth_sh, passes->depth_pass); + } + + /* Clay Pass */ + { + MaterialEngineSettingsClay *settings = DRW_render_settings_get(NULL, RE_engine_id_BLENDER_CLAY); + + passes->clay_pass = DRW_pass_create("Clay Pass", DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS); + + default_shgrp = CLAY_shgroup_create(passes->clay_pass, &settings->ubo_index); + DRW_shgroup_uniform_block(default_shgrp, "material_block", data.mat_ubo, 0); + } + + /* Object Mode */ + { + DRW_pass_setup_common(&passes->wire_overlay_pass, + &passes->wire_outline_pass, + &passes->non_meshes_pass, + &passes->ob_center_pass); + } + + /* TODO Create hash table of batch based on material id*/ + Object *ob; + DEG_OBJECT_ITER(sl, ob) + { + if ((ob->base_flag & BASE_VISIBLED) == 0) { + continue; + } + + struct Batch *geom; + //bool do_outlines; + + switch (ob->type) { + case OB_MESH: + geom = DRW_cache_surface_get(ob); + + /* Add everything for now */ + DRW_shgroup_call_add(depthbatch, geom, ob->obmat); + DRW_shgroup_call_add(default_shgrp, geom, ob->obmat); + + //DRW_shgroup_wire_overlay(passes->wire_overlay_pass, ob); + + //do_outlines = ((ob->base_flag & BASE_SELECTED) != 0); + //DRW_shgroup_wire_outline(passes->wire_outline_pass, ob, false, false, do_outlines); + + /* When encountering a new material : + * - Create new Batch + * - Initialize Batch + * - Push it to the hash table + * - The pass takes care of inserting it + * next to the same shader calls */ + + /* Free hash table */ + break; + case OB_LAMP: + case OB_CAMERA: + case OB_EMPTY: + default: + DRW_shgroup_non_meshes(passes->non_meshes_pass, ob); + break; + } + + DRW_shgroup_object_center(passes->ob_center_pass, ob); + DRW_shgroup_relationship_lines(passes->non_meshes_pass, ob); + } + DEG_OBJECT_ITER_END +} + +static void CLAY_view_draw(RenderEngine *UNUSED(engine), const bContext *context) +{ + /* This function may run for multiple viewports + * so get the current viewport buffers */ + CLAY_FramebufferList *buffers = NULL; + CLAY_TextureList *textures = NULL; + CLAY_PassList *passes = NULL; + + DRW_viewport_init(context, (void **)&buffers, (void **)&textures, (void **)&passes); + + CLAY_engine_init(context); + + CLAY_update_material_ubo(context); + + /* TODO : tag to refresh by the deps graph */ + /* ideally only refresh when objects are added/removed */ + /* or render properties / materials change */ +#ifdef WITH_VIEWPORT_CACHE_TEST + static bool once = false; +#endif + if (DRW_viewport_cache_is_dirty() +#ifdef WITH_VIEWPORT_CACHE_TEST + && !once +#endif + ) { +#ifdef WITH_VIEWPORT_CACHE_TEST + once = true; +#endif + CLAY_create_cache(passes, context); + } + + /* Start Drawing */ + DRW_draw_background(); + + /* Pass 1 : Depth pre-pass */ + DRW_draw_pass(passes->depth_pass); + + /* Pass 2 (Optionnal) : Separated Downsampled AO */ + DRW_framebuffer_texture_detach(textures->depth); + /* TODO */ + + /* Pass 3 : Shading */ + CLAY_ssao_setup(); + DRW_draw_pass(passes->clay_pass); + + /* Pass 4 : Overlays */ + DRW_framebuffer_texture_attach(buffers->default_fb, textures->depth, 0); + //DRW_draw_pass(passes->wire_overlay_pass); + //DRW_draw_pass(passes->wire_outline_pass); + DRW_draw_pass(passes->non_meshes_pass); + DRW_draw_pass(passes->ob_center_pass); + + /* Always finish by this */ + DRW_state_reset(); +} + +static void CLAY_collection_settings_create(RenderEngine *UNUSED(engine), CollectionEngineSettings *ces) +{ + BLI_assert(ces); + BKE_collection_engine_property_add_int(ces, "matcap_icon", ICON_MATCAP_01); + BKE_collection_engine_property_add_int(ces, "type", CLAY_MATCAP_NONE); + BKE_collection_engine_property_add_float(ces, "matcap_rotation", 0.0f); + BKE_collection_engine_property_add_float(ces, "matcap_hue", 0.5f); + BKE_collection_engine_property_add_float(ces, "matcap_saturation", 0.5f); + BKE_collection_engine_property_add_float(ces, "matcap_value", 0.5f); + BKE_collection_engine_property_add_float(ces, "ssao_distance", 0.2f); + BKE_collection_engine_property_add_float(ces, "ssao_attenuation", 1.0f); + BKE_collection_engine_property_add_float(ces, "ssao_factor_cavity", 1.0f); + BKE_collection_engine_property_add_float(ces, "ssao_factor_edge", 1.0f); + + /* Runtime data (not display in settings) */ + BKE_collection_engine_property_add_int(ces, "ubo_index", -1); + BKE_collection_engine_property_add_int(ces, "flag", CLAY_OUTDATED); +} + +void clay_engine_free(void) +{ + /* data.depth_sh Is builtin so it's automaticaly freed */ + if (data.clay_sh) { + DRW_shader_free(data.clay_sh); + } + + if (data.matcap_array) { + DRW_texture_free(data.matcap_array); + } + + if (data.jitter_tx) { + DRW_texture_free(data.jitter_tx); + } + + if (data.sampling_tx) { + DRW_texture_free(data.sampling_tx); + } + + if (data.mat_ubo) { + DRW_uniformbuffer_free(data.mat_ubo); + } +} + +RenderEngineType viewport_clay_type = { + NULL, NULL, + "BLENDER_CLAY", N_("Clay"), RE_INTERNAL | RE_USE_OGL_PIPELINE, + NULL, NULL, NULL, NULL, &CLAY_view_draw, NULL, &CLAY_collection_settings_create, + {NULL, NULL, NULL} +}; +#endif
\ No newline at end of file diff --git a/source/blender/draw/DRW_defines.h b/source/blender/draw/engines/clay/clay.h index 212c39e203b..404924be2a1 100644 --- a/source/blender/draw/DRW_defines.h +++ b/source/blender/draw/engines/clay/clay.h @@ -19,7 +19,18 @@ * */ -#ifndef __DRW_DEFINES_H__ -#define __DRW_DEFINES_H__ +/** \file clay.h + * \ingroup DNA + */ + +#ifndef __ENGINE_CLAY_H__ +#define __ENGINE_CLAY_H__ + +extern RenderEngineType viewport_clay_type; + +struct RenderEngineSettings *CLAY_render_settings_create(void); +struct MaterialEngineSettings *CLAY_material_settings_create(void); + +void clay_engine_free(void); -#endif /* __DRW_DEFINES_H__ */ +#endif /* __ENGINE_CLAY_H__ */
\ No newline at end of file diff --git a/source/blender/draw/engines/clay/shaders/clay_frag.glsl b/source/blender/draw/engines/clay/shaders/clay_frag.glsl new file mode 100644 index 00000000000..d9b372b652a --- /dev/null +++ b/source/blender/draw/engines/clay/shaders/clay_frag.glsl @@ -0,0 +1,207 @@ +uniform vec2 screenres; +uniform sampler2D depthtex; +uniform mat4 WinMatrix; + +/* Matcap */ +uniform sampler2DArray matcaps; +uniform vec3 matcaps_color[24]; + +/* Screen Space Occlusion */ +/* store the view space vectors for the corners of the view frustum here. + * It helps to quickly reconstruct view space vectors by using uv coordinates, + * see http://www.derschmale.com/2014/01/26/reconstructing-positions-from-the-depth-buffer */ +uniform vec4 viewvecs[3]; +uniform vec4 ssao_params; + +uniform sampler2D ssao_jitter; +uniform sampler1D ssao_samples; + +/* Material Parameters packed in an UBO */ +struct Material { + vec4 ssao_params_var; + vec4 matcap_hsv_id; + vec4 matcap_rot; /* vec4 to ensure 16 bytes alignement (don't trust compiler) */ +}; + +layout(std140) uniform material_block { + Material matcaps_param[MAX_MATERIAL]; +}; + +int mat_id; + +/* Aliases */ +#define ssao_samples_num ssao_params.x +#define jitter_tilling ssao_params.yz +#define dfdy_sign ssao_params.w + +#define matcap_hsv matcaps_param[mat_id].matcap_hsv_id.xyz +#define matcap_index matcaps_param[mat_id].matcap_hsv_id.w +#define matcap_rotation matcaps_param[mat_id].matcap_rot.xy + +in vec3 normal; +out vec4 fragColor; + +/* TODO Move this to SSAO modules */ +/* simple depth reconstruction, see http://www.derschmale.com/2014/01/26/reconstructing-positions-from-the-depth-buffer + * we change the factors from the article to fit the OpennGL model. */ +vec3 get_view_space_from_depth(in vec2 uvcoords, in float depth) +{ + if (WinMatrix[3][3] == 0.0) { + /* Perspective */ + float d = 2.0 * depth - 1.0; + + float zview = -WinMatrix[3][2] / (d + WinMatrix[2][2]); + + return zview * (viewvecs[0].xyz + vec3(uvcoords, 0.0) * viewvecs[1].xyz); + } + else { + /* Orthographic */ + vec3 offset = vec3(uvcoords, depth); + + return viewvecs[0].xyz + offset * viewvecs[1].xyz; + } +} + +/* TODO remove this when switching to geometric normals */ +vec3 calculate_view_space_normal(in vec3 viewposition) +{ + vec3 normal = cross(normalize(dFdx(viewposition)), dfdy_sign * normalize(dFdy(viewposition))); + return normalize(normal); +} + +#ifdef USE_HSV +void rgb_to_hsv(vec3 rgb, out vec3 outcol) +{ + float cmax, cmin, h, s, v, cdelta; + vec3 c; + + cmax = max(rgb[0], max(rgb[1], rgb[2])); + cmin = min(rgb[0], min(rgb[1], rgb[2])); + cdelta = cmax - cmin; + + v = cmax; + if (cmax != 0.0) + s = cdelta / cmax; + else { + s = 0.0; + h = 0.0; + } + + if (s == 0.0) { + h = 0.0; + } + else { + c = (vec3(cmax, cmax, cmax) - rgb.xyz) / cdelta; + + if (rgb.x == cmax) h = c[2] - c[1]; + else if (rgb.y == cmax) h = 2.0 + c[0] - c[2]; + else h = 4.0 + c[1] - c[0]; + + h /= 6.0; + + if (h < 0.0) + h += 1.0; + } + + outcol = vec3(h, s, v); +} + +void hsv_to_rgb(vec3 hsv, out vec3 outcol) +{ + float i, f, p, q, t, h, s, v; + vec3 rgb; + + h = hsv[0]; + s = hsv[1]; + v = hsv[2]; + + if (s == 0.0) { + rgb = vec3(v, v, v); + } + else { + if (h == 1.0) + h = 0.0; + + h *= 6.0; + i = floor(h); + f = h - i; + rgb = vec3(f, f, f); + p = v * (1.0 - s); + q = v * (1.0 - (s * f)); + t = v * (1.0 - (s * (1.0 - f))); + + if (i == 0.0) rgb = vec3(v, t, p); + else if (i == 1.0) rgb = vec3(q, v, p); + else if (i == 2.0) rgb = vec3(p, v, t); + else if (i == 3.0) rgb = vec3(p, q, v); + else if (i == 4.0) rgb = vec3(t, p, v); + else rgb = vec3(v, p, q); + } + + outcol = rgb; +} + +void hue_sat(float hue, float sat, float value, inout vec3 col) +{ + vec3 hsv; + + rgb_to_hsv(col, hsv); + + hsv.x += hue; + hsv.x -= floor(hsv.x); + hsv.y *= sat; + hsv.y = clamp(hsv.y, 0.0, 1.0); + hsv.z *= value; + hsv.z = clamp(hsv.z, 0.0, 1.0); + + hsv_to_rgb(hsv, col); +} +#endif + +#ifdef USE_AO +/* Prototype */ +void ssao_factors(in float depth, in vec3 normal, in vec3 position, in vec2 screenco, out float cavities, out float edges); +#endif + +void main() { + vec2 screenco = vec2(gl_FragCoord.xy) / screenres; + float depth = texture(depthtex, screenco).r; + + vec3 position = get_view_space_from_depth(screenco, depth); + vec3 normal = calculate_view_space_normal(position); + + //mat_id = int(screenco.x*3.0); + + /* Manual Depth test */ + /* Doing this test earlier gives problem with dfdx calculations + * TODO move this before when we have proper geometric normals */ + if (gl_FragCoord.z > depth + 1e-5) + discard; + +#ifdef USE_ROTATION + /* Rotate texture coordinates */ + vec2 rotY = vec2(-matcap_rotation.y, matcap_rotation.x); + vec2 texco = abs(vec2(dot(normal.xy, matcap_rotation), dot(normal.xy, rotY)) * .49 + 0.5); +#else + vec2 texco = abs(normal.xy * .49 + 0.5); +#endif + vec3 col = texture(matcaps, vec3(texco, matcap_index)).rgb; + +#ifdef USE_AO + float cavity, edges; + ssao_factors(depth, normal, position, screenco, cavity, edges); + + col *= mix(vec3(1.0), matcaps_color[int(matcap_index)], cavity); +#endif + +#ifdef USE_HSV + hue_sat(matcap_hsv.x, matcap_hsv.y, matcap_hsv.z, col); +#endif + +#ifdef USE_AO + /* Apply highlights after hue shift */ + col *= edges + 1.0; +#endif + + fragColor = vec4(col, 1.0); +} diff --git a/source/blender/draw/engines/clay/shaders/clay_vert.glsl b/source/blender/draw/engines/clay/shaders/clay_vert.glsl new file mode 100644 index 00000000000..0b598ea0291 --- /dev/null +++ b/source/blender/draw/engines/clay/shaders/clay_vert.glsl @@ -0,0 +1,20 @@ +uniform mat4 ModelViewProjectionMatrix; +uniform mat3 NormalMatrix; + +#if __VERSION__ == 120 +attribute vec3 pos; +attribute vec3 nor; +varying vec3 normal; +#else +in vec3 pos; +in vec3 nor; +out vec3 normal; +#endif + + +void main() +{ + normal = normalize(NormalMatrix * nor); + gl_Position = ModelViewProjectionMatrix * vec4(pos, 1.0); +} + diff --git a/source/blender/draw/engines/clay/shaders/ssao_alchemy.glsl b/source/blender/draw/engines/clay/shaders/ssao_alchemy.glsl new file mode 100644 index 00000000000..d032fb91c01 --- /dev/null +++ b/source/blender/draw/engines/clay/shaders/ssao_alchemy.glsl @@ -0,0 +1,73 @@ +#define ssao_distance matcaps_param[mat_id].ssao_params_var.x +#define ssao_factor_cavity matcaps_param[mat_id].ssao_params_var.y +#define ssao_factor_edge matcaps_param[mat_id].ssao_params_var.z +#define ssao_attenuation matcaps_param[mat_id].ssao_params_var.w + +/* from The Alchemy screen-space ambient obscurance algorithm + * http://graphics.cs.williams.edu/papers/AlchemyHPG11/VV11AlchemyAO.pdf */ + +void ssao_factors(in float depth, in vec3 normal, in vec3 position, in vec2 screenco, out float cavities, out float edges) +{ + /* take the normalized ray direction here */ + vec2 rotX = texture2D(ssao_jitter, screenco.xy * jitter_tilling).rg; + vec2 rotY = vec2(-rotX.y, rotX.x); + + /* find the offset in screen space by multiplying a point + * in camera space at the depth of the point by the projection matrix. */ + vec2 offset; + float homcoord = WinMatrix[2][3] * position.z + WinMatrix[3][3]; + offset.x = WinMatrix[0][0] * ssao_distance / homcoord; + offset.y = WinMatrix[1][1] * ssao_distance / homcoord; + /* convert from -1.0...1.0 range to 0.0..1.0 for easy use with texture coordinates */ + offset *= 0.5; + + cavities = edges = 0.0; + int x; + int num_samples = int(ssao_samples_num); + + for (x = 0; x < num_samples; x++) { + /* TODO : optimisation replace by constant */ + vec2 dir_sample = texture1D(ssao_samples, (float(x) + 0.5) / ssao_samples_num).rg; + + /* rotate with random direction to get jittered result */ + vec2 dir_jittered = vec2(dot(dir_sample, rotX), dot(dir_sample, rotY)); + + vec2 uvcoords = screenco.xy + dir_jittered * offset; + + if (uvcoords.x > 1.0 || uvcoords.x < 0.0 || uvcoords.y > 1.0 || uvcoords.y < 0.0) + continue; + + float depth_new = texture2D(depthtex, uvcoords).r; + + /* Handle Background case */ + bool is_background = (depth_new == 1.0); + + /* This trick provide good edge effect even if no neighboor is found. */ + vec3 pos_new = get_view_space_from_depth(uvcoords, (is_background) ? depth : depth_new); + + if (is_background) + pos_new.z -= ssao_distance; + + vec3 dir = pos_new - position; + float len = length(dir); + float f_cavities = dot(dir, normal); + float f_edge = -f_cavities; + float f_bias = 0.05 * len + 0.0001; + + float attenuation = 1.0 / (len * (1.0 + len * len * ssao_attenuation)); + + /* use minor bias here to avoid self shadowing */ + if (f_cavities > -f_bias) + cavities += f_cavities * attenuation; + + if (f_edge > f_bias) + edges += f_edge * attenuation; + } + + cavities /= ssao_samples_num; + edges /= ssao_samples_num; + + /* don't let cavity wash out the surface appearance */ + cavities = clamp(cavities * ssao_factor_cavity, 0.0, 1.0); + edges = edges * ssao_factor_edge; +} diff --git a/source/blender/draw/engines/clay/shaders/ssao_groundtruth.glsl b/source/blender/draw/engines/clay/shaders/ssao_groundtruth.glsl new file mode 100644 index 00000000000..2f29624824e --- /dev/null +++ b/source/blender/draw/engines/clay/shaders/ssao_groundtruth.glsl @@ -0,0 +1,120 @@ +#define ssao_distance matcaps_param[mat_id].ssao_params_var.x +#define ssao_factor_cavity matcaps_param[mat_id].ssao_params_var.y +#define ssao_factor_edge matcaps_param[mat_id].ssao_params_var.z +#define ssao_attenuation matcaps_param[mat_id].ssao_params_var.w + +/* Based on Practical Realtime Strategies for Accurate Indirect Occlusion + * http://blog.selfshadow.com/publications/s2016-shading-course/activision/s2016_pbs_activision_occlusion.pdf + * http://blog.selfshadow.com/publications/s2016-shading-course/activision/s2016_pbs_activision_occlusion.pptx */ + +#define COSINE_WEIGHTING + +float integrate_arc(in float h1, in float h2, in float gamma, in float n_proj_len) +{ + float a = 0.0; +#ifdef COSINE_WEIGHTING + float cos_gamma = cos(gamma); + float sin_gamma_2 = 2.0 * sin(gamma); + a += -cos(2.0 * h1 - gamma) + cos_gamma + h1 * sin_gamma_2; + a += -cos(2.0 * h2 - gamma) + cos_gamma + h2 * sin_gamma_2; + a *= 0.25; /* 1/4 */ + a *= n_proj_len; +#else + /* Uniform weighting (slide 59) */ + a += 1 - cos(h1); + a += 1 - cos(h2); +#endif + return a; +} + +float get_max_horizon(in vec2 co, in vec3 x, in vec3 omega_o, in float h) +{ + if (co.x > 1.0 || co.x < 0.0 || co.y > 1.0 || co.y < 0.0) + return h; + + float depth = texture2D(depthtex, co).r; + + /* Background case */ + if (depth == 1.0) + return h; + + vec3 s = get_view_space_from_depth(co, depth); /* s View coordinate */ + vec3 omega_s = s - x; + float len = length(omega_s); + + if (len < ssao_distance) { + omega_s /= len; + h = max(h, dot(omega_s, omega_o)); + } + return h; +} + +void ssao_factors(in float depth, in vec3 normal, in vec3 position, in vec2 screenco, out float cavities, out float edges) +{ + /* Renaming */ + vec3 omega_o = -normalize(position); /* viewvec */ + vec2 x_ = screenco; /* x^ Screen coordinate */ + vec3 x = position; /* x view space coordinate */ + +#ifdef SPATIAL_DENOISE + float noise_dir = (1.0 / 16.0) * float(((int(gl_FragCoord.x + gl_FragCoord.y) & 0x3) << 2) + (int(gl_FragCoord.x) & 0x3)); + float noise_offset = (1.0 / 4.0) * float(int(gl_FragCoord.y - gl_FragCoord.x) & 0x3); +#else + float noise_dir = (1.0 / 16.0) * float(((int(gl_FragCoord.x + gl_FragCoord.y) & 0x3) << 2) + (int(gl_FragCoord.x) & 0x3)); + float noise_offset = (0.5 / 16.0) + (1.0 / 16.0) * float(((int(gl_FragCoord.x - gl_FragCoord.y) & 0x3) << 2) + (int(gl_FragCoord.x) & 0x3)); +#endif + + const float phi_step = 16.0; + const float theta_step = 16.0; + const float m_pi = 3.14159265358979323846; + vec2 pixel_ratio = vec2(screenres.y / screenres.x, 1.0); + vec2 pixel_size = vec2(1.0) / screenres.xy; + float min_stride = length(pixel_size); + float homcco = WinMatrix[2][3] * position.z + WinMatrix[3][3]; + float n = max(min_stride * theta_step, ssao_distance / homcco); /* Search distance */ + + /* Integral over PI */ + float A = 0.0; + for (float i = 0.0; i < phi_step; i++) { + float phi = m_pi * ((noise_dir + i) / phi_step); + + vec2 t_phi = vec2(cos(phi), sin(phi)); /* Screen space direction */ + + /* Search maximum horizon angles Theta1 and Theta2 */ + float theta1 = -1.0, theta2 = -1.0; /* init at cos(pi) */ + for (float j = 0.0; j < theta_step; j++) { + vec2 s_ = t_phi * pixel_ratio * n * ((j + noise_offset)/ theta_step); /* s^ Screen coordinate */ + vec2 co; + + co = x_ + s_; + theta1 = get_max_horizon(co, x, omega_o, theta1); + + co = x_ - s_; + theta2 = get_max_horizon(co, x, omega_o, theta2); + } + + /* (Slide 54) */ + theta1 = -acos(theta1); + theta2 = acos(theta2); + + /* Projecting Normal to Plane P defined by t_phi and omega_o */ + vec3 h = normalize(cross(vec3(t_phi, 0.0), omega_o)); /* Normal vector to Integration plane */ + vec3 t = cross(h, omega_o); /* Normal vector to plane */ + vec3 n_proj = normal - h * dot(normal, h); + float n_proj_len = length(n_proj); + vec3 n_proj_norm = normalize(n_proj); + + /* Clamping thetas (slide 58) */ + float gamma = sign(dot(n_proj_norm, t)) * acos(dot(normal, omega_o)); /* Angle between view vec and normal */ + theta1 = gamma + max(theta1 - gamma, -m_pi * 0.5); + theta2 = gamma + min(theta2 - gamma, m_pi * 0.5); + + /* Solving inner integral */ + A += integrate_arc(theta1, theta2, gamma, n_proj_len); + } + + A /= phi_step; + + cavities = 1.0 - A; + edges = 0.0; +}
\ No newline at end of file diff --git a/source/blender/draw/intern/DRW_render.h b/source/blender/draw/intern/DRW_render.h new file mode 100644 index 00000000000..90412e65a51 --- /dev/null +++ b/source/blender/draw/intern/DRW_render.h @@ -0,0 +1,221 @@ +/* + * Copyright 2016, Blender Foundation. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Contributor(s): Blender Institute + * + */ + +/** \file DRW_render.h + * \ingroup draw + */ + +/* This is the Render Functions used by Realtime engines to draw with OpenGL */ + +#ifndef __DRW_RENDER_H__ +#define __DRW_RENDER_H__ + +#include "BKE_context.h" +#include "BKE_layer.h" +#include "BKE_scene.h" + +#include "BLI_listbase.h" +#include "BLI_math_matrix.h" +#include "BLI_math_vector.h" +#include "BLI_string.h" + +#include "BLT_translation.h" + +#include "DNA_object_types.h" +#include "DNA_lamp_types.h" +#include "DNA_material_types.h" +#include "DNA_scene_types.h" + +#include "draw_mode_pass.h" +#include "draw_cache.h" + +#include "MEM_guardedalloc.h" + +#include "RE_engine.h" + +//#define WITH_VIEWPORT_CACHE_TEST + +struct GPUFrameBuffer; +struct GPUShader; +struct GPUTexture; +struct GPUUniformBuffer; +struct Object; +struct Batch; + +typedef struct DRWUniform DRWUniform; +typedef struct DRWInterface DRWInterface; +typedef struct DRWPass DRWPass; +typedef struct DRWShadingGroup DRWShadingGroup; + +/* Textures */ + +typedef enum { + DRW_TEX_RGBA_8, + DRW_TEX_RGBA_16, + DRW_TEX_RGBA_32, + DRW_TEX_RGB_8, + DRW_TEX_RGB_16, + DRW_TEX_RGB_32, + DRW_TEX_RG_8, + DRW_TEX_RG_16, + DRW_TEX_RG_32, + DRW_TEX_R_8, + DRW_TEX_R_16, + DRW_TEX_R_32, + DRW_TEX_DEPTH_16, + DRW_TEX_DEPTH_24, + DRW_TEX_DEPTH_32, +} DRWTextureFormat; + +typedef enum { + DRW_TEX_FILTER = (1 << 0), + DRW_TEX_WRAP = (1 << 1), + DRW_TEX_COMPARE = (1 << 2), +} DRWTextureFlag; + +struct GPUTexture *DRW_texture_create_1D( + int w, DRWTextureFormat format, DRWTextureFlag flags, const float *fpixels); +struct GPUTexture *DRW_texture_create_2D( + int w, int h, DRWTextureFormat format, DRWTextureFlag flags, const float *fpixels); +struct GPUTexture *DRW_texture_create_2D_array( + int w, int h, int d, DRWTextureFormat UNUSED(format), DRWTextureFlag flags, const float *fpixels); +void DRW_texture_free(struct GPUTexture *tex); + +/* UBOs */ +struct GPUUniformBuffer *DRW_uniformbuffer_create(int size, const void *data); +void DRW_uniformbuffer_update(struct GPUUniformBuffer *ubo, const void *data); +void DRW_uniformbuffer_free(struct GPUUniformBuffer *ubo); + +/* Buffers */ + +/* DRWFboTexture->format */ +#define DRW_BUF_DEPTH_16 1 +#define DRW_BUF_DEPTH_24 2 +#define DRW_BUF_R_8 3 +#define DRW_BUF_R_16 4 +#define DRW_BUF_R_32 5 +#define DRW_BUF_RG_8 6 +#define DRW_BUF_RG_16 7 +#define DRW_BUF_RG_32 8 +#define DRW_BUF_RGB_8 9 +#define DRW_BUF_RGB_16 10 +#define DRW_BUF_RGB_32 11 +#define DRW_BUF_RGBA_8 12 +#define DRW_BUF_RGBA_16 13 +#define DRW_BUF_RGBA_32 14 + +#define MAX_FBO_TEX 5 + +typedef struct DRWFboTexture { + struct GPUTexture **tex; + int format; +} DRWFboTexture; + +void DRW_framebuffer_init(struct GPUFrameBuffer **fb, int width, int height, DRWFboTexture textures[MAX_FBO_TEX], int texnbr); +void DRW_framebuffer_bind(struct GPUFrameBuffer *fb); +void DRW_framebuffer_texture_attach(struct GPUFrameBuffer *fb, struct GPUTexture *tex, int slot); +void DRW_framebuffer_texture_detach(struct GPUTexture *tex); +/* Shaders */ +struct GPUShader *DRW_shader_create(const char *vert, const char *geom, const char *frag, const char *defines); +struct GPUShader *DRW_shader_create_2D(const char *frag, const char *defines); +struct GPUShader *DRW_shader_create_3D(const char *frag, const char *defines); +struct GPUShader *DRW_shader_create_3D_depth_only(void); +void DRW_shader_free(struct GPUShader *shader); + +/* Batches */ + +typedef enum { + DRW_STATE_WRITE_DEPTH = (1 << 0), + DRW_STATE_WRITE_COLOR = (1 << 1), + DRW_STATE_DEPTH_LESS = (1 << 2), + DRW_STATE_DEPTH_EQUAL = (1 << 3), + DRW_STATE_CULL_BACK = (1 << 4), + DRW_STATE_CULL_FRONT = (1 << 5), + DRW_STATE_WIRE = (1 << 6), + DRW_STATE_WIRE_LARGE = (1 << 7), + DRW_STATE_POINT = (1 << 8), + DRW_STATE_STIPPLE_2 = (1 << 9), + DRW_STATE_STIPPLE_3 = (1 << 10), + DRW_STATE_STIPPLE_4 = (1 << 11), + DRW_STATE_BLEND = (1 << 12), +} DRWState; + +/* Used by DRWShadingGroup.dyntype */ +#define DRW_DYN_POINTS 1 +#define DRW_DYN_LINES 2 +#define DRW_DYN_INSTANCE 3 + +DRWShadingGroup *DRW_shgroup_create(struct GPUShader *shader, DRWPass *pass); +void DRW_shgroup_free(struct DRWShadingGroup *shgroup); +void DRW_shgroup_call_add(DRWShadingGroup *shgroup, struct Batch *geom, float (*obmat)[4]); +void DRW_shgroup_state_set(DRWShadingGroup *shgroup, DRWState state); +void DRW_shgroup_dyntype_set(DRWShadingGroup *shgroup, int type); + +void DRW_shgroup_uniform_texture(DRWShadingGroup *shgroup, const char *name, const struct GPUTexture *tex, int loc); +void DRW_shgroup_uniform_block(DRWShadingGroup *shgroup, const char *name, const struct GPUUniformBuffer *ubo, int loc); +void DRW_shgroup_uniform_buffer(DRWShadingGroup *shgroup, const char *name, const int value, int loc); +void DRW_shgroup_uniform_bool(DRWShadingGroup *shgroup, const char *name, const bool *value, int arraysize); +void DRW_shgroup_uniform_float(DRWShadingGroup *shgroup, const char *name, const float *value, int arraysize); +void DRW_shgroup_uniform_vec2(DRWShadingGroup *shgroup, const char *name, const float *value, int arraysize); +void DRW_shgroup_uniform_vec3(DRWShadingGroup *shgroup, const char *name, const float *value, int arraysize); +void DRW_shgroup_uniform_vec4(DRWShadingGroup *shgroup, const char *name, const float *value, int arraysize); +void DRW_shgroup_uniform_int(DRWShadingGroup *shgroup, const char *name, const int *value, int arraysize); +void DRW_shgroup_uniform_ivec2(DRWShadingGroup *shgroup, const char *name, const int *value, int arraysize); +void DRW_shgroup_uniform_ivec3(DRWShadingGroup *shgroup, const char *name, const int *value, int arraysize); +void DRW_shgroup_uniform_mat3(DRWShadingGroup *shgroup, const char *name, const float *value); +void DRW_shgroup_uniform_mat4(DRWShadingGroup *shgroup, const char *name, const float *value); + +/* Passes */ +DRWPass *DRW_pass_create(const char *name, DRWState state); +DRWShadingGroup *DRW_pass_nth_shgroup_get(DRWPass *pass, int n); + +/* Viewport */ +typedef enum { + DRW_MAT_PERS, + DRW_MAT_WIEW, + DRW_MAT_WIN, +} DRWViewportMatrixType; + +void DRW_viewport_init(const bContext *C, void **buffers, void **textures, void **passes); +void DRW_viewport_matrix_get(float mat[4][4], DRWViewportMatrixType type); +float *DRW_viewport_size_get(void); +float *DRW_viewport_screenvecs_get(void); +float *DRW_viewport_pixelsize_get(void); +bool DRW_viewport_is_persp_get(void); +bool DRW_viewport_cache_is_dirty(void); + +/* Settings */ +#ifndef __DRW_ENGINE_H__ +void *DRW_material_settings_get(Material *ma, const char *engine_name); +void *DRW_render_settings_get(Scene *scene, const char *engine_name); +#endif /* __DRW_ENGINE_H__ */ + +/* Draw commands */ +void DRW_draw_background(void); +void DRW_centercircle(const float co[3]); +void DRW_draw_pass(DRWPass *pass); + +void DRW_state_reset(void); + +/* Other */ +void DRW_get_dfdy_factors(float dfdyfac[2]); + +#endif /* __DRW_RENDER_H__ */
\ No newline at end of file diff --git a/source/blender/draw/intern/draw_cache.c b/source/blender/draw/intern/draw_cache.c new file mode 100644 index 00000000000..1255a083b82 --- /dev/null +++ b/source/blender/draw/intern/draw_cache.c @@ -0,0 +1,543 @@ +/* + * Copyright 2016, Blender Foundation. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Contributor(s): Blender Institute + * + */ + +/** \file draw_cache.c + * \ingroup draw + */ + + +#include "DNA_scene_types.h" +#include "DNA_mesh_types.h" +#include "DNA_object_types.h" + +#include "BLI_utildefines.h" +#include "BLI_math.h" + +#include "BKE_mesh_render.h" + +#include "GPU_batch.h" + +#include "draw_cache.h" + +static struct DRWShapeCache{ + Batch *drw_single_vertice; + Batch *drw_fullscreen_quad; + Batch *drw_plain_axes; + Batch *drw_single_arrow; + Batch *drw_single_arrow_line; + Batch *drw_cube; + Batch *drw_circle; + Batch *drw_empty_sphere; + Batch *drw_empty_cone; + Batch *drw_arrows; + Batch *drw_lamp; + Batch *drw_lamp_sunrays; +} SHC = {NULL}; + +void DRW_shape_cache_free(void) +{ + if (SHC.drw_single_vertice) + Batch_discard_all(SHC.drw_single_vertice); + if (SHC.drw_fullscreen_quad) + Batch_discard_all(SHC.drw_fullscreen_quad); + if (SHC.drw_plain_axes) + Batch_discard_all(SHC.drw_plain_axes); + if (SHC.drw_single_arrow) + Batch_discard_all(SHC.drw_single_arrow); + if (SHC.drw_single_arrow_line) + Batch_discard_all(SHC.drw_single_arrow_line); + if (SHC.drw_cube) + Batch_discard_all(SHC.drw_cube); + if (SHC.drw_circle) + Batch_discard_all(SHC.drw_circle); + if (SHC.drw_empty_sphere) + Batch_discard_all(SHC.drw_empty_sphere); + if (SHC.drw_empty_cone) + Batch_discard_all(SHC.drw_empty_cone); + if (SHC.drw_arrows) + Batch_discard_all(SHC.drw_arrows); + if (SHC.drw_lamp) + Batch_discard_all(SHC.drw_lamp); + if (SHC.drw_lamp_sunrays) + Batch_discard_all(SHC.drw_lamp_sunrays); +} + +/* Quads */ +Batch *DRW_cache_fullscreen_quad_get(void) +{ + if (!SHC.drw_fullscreen_quad) { + float v1[2] = {-1.0f, -1.0f}; + float v2[2] = { 1.0f, -1.0f}; + float v3[2] = {-1.0f, 1.0f}; + float v4[2] = { 1.0f, 1.0f}; + + /* Position Only 3D format */ + static VertexFormat format = { 0 }; + static unsigned pos_id; + if (format.attrib_ct == 0) { + pos_id = add_attrib(&format, "pos", GL_FLOAT, 3, KEEP_FLOAT); + } + + VertexBuffer *vbo = VertexBuffer_create_with_format(&format); + VertexBuffer_allocate_data(vbo, 6); + + setAttrib(vbo, pos_id, 0, v1); + setAttrib(vbo, pos_id, 1, v2); + setAttrib(vbo, pos_id, 2, v3); + + setAttrib(vbo, pos_id, 3, v2); + setAttrib(vbo, pos_id, 4, v3); + setAttrib(vbo, pos_id, 5, v4); + + SHC.drw_fullscreen_quad = Batch_create(GL_TRIANGLES, vbo, NULL); + } + return SHC.drw_fullscreen_quad; +} + +/* Common */ + +Batch *DRW_cache_cube_get(void) +{ + if (!SHC.drw_cube) { + const GLfloat verts[8][3] = { + {-1.0f, -1.0f, -1.0f}, + {-1.0f, -1.0f, 1.0f}, + {-1.0f, 1.0f, -1.0f}, + {-1.0f, 1.0f, 1.0f}, + { 1.0f, -1.0f, -1.0f}, + { 1.0f, -1.0f, 1.0f}, + { 1.0f, 1.0f, -1.0f}, + { 1.0f, 1.0f, 1.0f} + }; + + const GLubyte indices[24] = {0,1,1,3,3,2,2,0,0,4,4,5,5,7,7,6,6,4,1,5,3,7,2,6}; + + /* Position Only 3D format */ + static VertexFormat format = { 0 }; + static unsigned pos_id; + if (format.attrib_ct == 0) { + pos_id = add_attrib(&format, "pos", GL_FLOAT, 3, KEEP_FLOAT); + } + + VertexBuffer *vbo = VertexBuffer_create_with_format(&format); + VertexBuffer_allocate_data(vbo, 24); + + for (int i = 0; i < 24; ++i) { + setAttrib(vbo, pos_id, i, verts[indices[i]]); + } + + SHC.drw_cube = Batch_create(GL_LINES, vbo, NULL); + } + return SHC.drw_cube; +} + + +Batch *DRW_cache_circle_get(void) +{ +#define CIRCLE_RESOL 32 + if (!SHC.drw_circle) { + float v[3] = {0.0f, 0.0f, 0.0f}; + + /* Position Only 3D format */ + static VertexFormat format = { 0 }; + static unsigned pos_id; + if (format.attrib_ct == 0) { + pos_id = add_attrib(&format, "pos", GL_FLOAT, 3, KEEP_FLOAT); + } + + VertexBuffer *vbo = VertexBuffer_create_with_format(&format); + VertexBuffer_allocate_data(vbo, CIRCLE_RESOL * 2); + + for (int a = 0; a < CIRCLE_RESOL; a++) { + v[0] = sinf((2.0f * M_PI * a) / ((float)CIRCLE_RESOL)); + v[1] = cosf((2.0f * M_PI * a) / ((float)CIRCLE_RESOL)); + v[2] = 0.0f; + setAttrib(vbo, pos_id, a * 2, v); + + v[0] = sinf((2.0f * M_PI * (a + 1)) / ((float)CIRCLE_RESOL)); + v[1] = cosf((2.0f * M_PI * (a + 1)) / ((float)CIRCLE_RESOL)); + v[2] = 0.0f; + setAttrib(vbo, pos_id, a * 2 + 1, v); + } + + SHC.drw_circle = Batch_create(GL_LINES, vbo, NULL); + } + return SHC.drw_circle; +#undef CIRCLE_RESOL +} + +/* Empties */ +Batch *DRW_cache_plain_axes_get(void) +{ + if (!SHC.drw_plain_axes) { + int axis; + float v1[3] = {0.0f, 0.0f, 0.0f}; + float v2[3] = {0.0f, 0.0f, 0.0f}; + + /* Position Only 3D format */ + static VertexFormat format = { 0 }; + static unsigned pos_id; + if (format.attrib_ct == 0) { + pos_id = add_attrib(&format, "pos", GL_FLOAT, 3, KEEP_FLOAT); + } + + VertexBuffer *vbo = VertexBuffer_create_with_format(&format); + VertexBuffer_allocate_data(vbo, 6); + + for (axis = 0; axis < 3; axis++) { + v1[axis] = 1.0f; + v2[axis] = -1.0f; + + setAttrib(vbo, pos_id, axis * 2, v1); + setAttrib(vbo, pos_id, axis * 2 + 1, v2); + + /* reset v1 & v2 to zero for next axis */ + v1[axis] = v2[axis] = 0.0f; + } + + SHC.drw_plain_axes = Batch_create(GL_LINES, vbo, NULL); + } + return SHC.drw_plain_axes; +} + +Batch *DRW_cache_single_arrow_get(Batch **line) +{ + if (!SHC.drw_single_arrow_line || !SHC.drw_single_arrow) { + float v1[3] = {0.0f, 0.0f, 0.0f}, v2[3], v3[3]; + + /* Position Only 3D format */ + static VertexFormat format = { 0 }; + static unsigned pos_id; + if (format.attrib_ct == 0) { + pos_id = add_attrib(&format, "pos", GL_FLOAT, 3, KEEP_FLOAT); + } + + /* Line */ + VertexBuffer *vbo = VertexBuffer_create_with_format(&format); + VertexBuffer_allocate_data(vbo, 2); + + setAttrib(vbo, pos_id, 0, v1); + v1[2] = 1.0f; + setAttrib(vbo, pos_id, 1, v1); + + SHC.drw_single_arrow_line = Batch_create(GL_LINES, vbo, NULL); + + /* Square Pyramid */ + vbo = VertexBuffer_create_with_format(&format); + VertexBuffer_allocate_data(vbo, 12); + + v2[0] = 0.035f; v2[1] = 0.035f; + v3[0] = -0.035f; v3[1] = 0.035f; + v2[2] = v3[2] = 0.75f; + + for (int sides = 0; sides < 4; sides++) { + if (sides % 2 == 1) { + v2[0] = -v2[0]; + v3[1] = -v3[1]; + } + else { + v2[1] = -v2[1]; + v3[0] = -v3[0]; + } + + setAttrib(vbo, pos_id, sides * 3 + 0, v1); + setAttrib(vbo, pos_id, sides * 3 + 1, v2); + setAttrib(vbo, pos_id, sides * 3 + 2, v3); + } + + SHC.drw_single_arrow = Batch_create(GL_TRIANGLES, vbo, NULL); + } + *line = SHC.drw_single_arrow_line; + return SHC.drw_single_arrow; +} + +Batch *DRW_cache_empty_sphere_get(void) +{ +#define NSEGMENTS 16 + if (!SHC.drw_empty_sphere) { + /* a single ring of vertices */ + float p[NSEGMENTS][2]; + for (int i = 0; i < NSEGMENTS; ++i) { + float angle = 2 * M_PI * ((float)i / (float)NSEGMENTS); + p[i][0] = cosf(angle); + p[i][1] = sinf(angle); + } + + /* Position Only 3D format */ + static VertexFormat format = { 0 }; + static unsigned pos_id; + if (format.attrib_ct == 0) { + pos_id = add_attrib(&format, "pos", GL_FLOAT, 3, KEEP_FLOAT); + } + + VertexBuffer *vbo = VertexBuffer_create_with_format(&format); + VertexBuffer_allocate_data(vbo, NSEGMENTS * 2 * 3); + + for (int axis = 0; axis < 3; ++axis) { + for (int i = 0; i < NSEGMENTS; ++i) { + for (int j = 0; j < 2; ++j) { + float cv[2], v[3]; + + cv[0] = p[(i+j) % NSEGMENTS][0]; + cv[1] = p[(i+j) % NSEGMENTS][1]; + + if (axis == 0) + v[0] = cv[0], v[1] = cv[1], v[2] = 0.0f; + else if (axis == 1) + v[0] = cv[0], v[1] = 0.0f, v[2] = cv[1]; + else + v[0] = 0.0f, v[1] = cv[0], v[2] = cv[1]; + + setAttrib(vbo, pos_id, i*2 + j + (NSEGMENTS * 2 * axis), v); + } + } + } + + SHC.drw_empty_sphere = Batch_create(GL_LINES, vbo, NULL); + } + return SHC.drw_empty_sphere; +#undef NSEGMENTS +} + +Batch *DRW_cache_empty_cone_get(void) +{ +#define NSEGMENTS 8 + if (!SHC.drw_empty_cone) { + /* a single ring of vertices */ + float p[NSEGMENTS][2]; + for (int i = 0; i < NSEGMENTS; ++i) { + float angle = 2 * M_PI * ((float)i / (float)NSEGMENTS); + p[i][0] = cosf(angle); + p[i][1] = sinf(angle); + } + + /* Position Only 3D format */ + static VertexFormat format = { 0 }; + static unsigned pos_id; + if (format.attrib_ct == 0) { + pos_id = add_attrib(&format, "pos", GL_FLOAT, 3, KEEP_FLOAT); + } + + VertexBuffer *vbo = VertexBuffer_create_with_format(&format); + VertexBuffer_allocate_data(vbo, NSEGMENTS * 4); + + for (int i = 0; i < NSEGMENTS; ++i) { + float cv[2], v[3]; + cv[0] = p[(i) % NSEGMENTS][0]; + cv[1] = p[(i) % NSEGMENTS][1]; + + /* cone sides */ + v[0] = cv[0], v[1] = 0.0f, v[2] = cv[1]; + setAttrib(vbo, pos_id, i*4, v); + v[0] = 0.0f, v[1] = 2.0f, v[2] = 0.0f; + setAttrib(vbo, pos_id, i*4 + 1, v); + + /* end ring */ + v[0] = cv[0], v[1] = 0.0f, v[2] = cv[1]; + setAttrib(vbo, pos_id, i*4 + 2, v); + cv[0] = p[(i+1) % NSEGMENTS][0]; + cv[1] = p[(i+1) % NSEGMENTS][1]; + v[0] = cv[0], v[1] = 0.0f, v[2] = cv[1]; + setAttrib(vbo, pos_id, i*4 + 3, v); + } + + SHC.drw_empty_cone = Batch_create(GL_LINES, vbo, NULL); + } + return SHC.drw_empty_cone; +#undef NSEGMENTS +} + +Batch *DRW_cache_arrows_get(void) +{ + if (!SHC.drw_arrows) { + float v1[3] = {0.0, 0.0, 0.0}; + float v2[3] = {0.0, 0.0, 0.0}; + + /* Position Only 3D format */ + static VertexFormat format = { 0 }; + static unsigned pos_id; + if (format.attrib_ct == 0) { + pos_id = add_attrib(&format, "pos", GL_FLOAT, 3, KEEP_FLOAT); + } + + /* Line */ + VertexBuffer *vbo = VertexBuffer_create_with_format(&format); + VertexBuffer_allocate_data(vbo, 6 * 3); + + for (int axis = 0; axis < 3; axis++) { + const int arrow_axis = (axis == 0) ? 1 : 0; + + v2[axis] = 1.0f; + setAttrib(vbo, pos_id, axis * 6 + 0, v1); + setAttrib(vbo, pos_id, axis * 6 + 1, v2); + + v1[axis] = 0.85f; + v1[arrow_axis] = -0.08f; + setAttrib(vbo, pos_id, axis * 6 + 2, v1); + setAttrib(vbo, pos_id, axis * 6 + 3, v2); + + v1[arrow_axis] = 0.08f; + setAttrib(vbo, pos_id, axis * 6 + 4, v1); + setAttrib(vbo, pos_id, axis * 6 + 5, v2); + + /* reset v1 & v2 to zero */ + v1[arrow_axis] = v1[axis] = v2[axis] = 0.0f; + } + + SHC.drw_arrows = Batch_create(GL_LINES, vbo, NULL); + } + return SHC.drw_arrows; +} + +/* Lamps */ +Batch *DRW_cache_lamp_get(void) +{ +#define NSEGMENTS 8 + if (!SHC.drw_lamp) { + float v[2]; + + /* Position Only 3D format */ + static VertexFormat format = { 0 }; + static unsigned pos_id; + if (format.attrib_ct == 0) { + pos_id = add_attrib(&format, "pos", GL_FLOAT, 2, KEEP_FLOAT); + } + + VertexBuffer *vbo = VertexBuffer_create_with_format(&format); + VertexBuffer_allocate_data(vbo, NSEGMENTS * 2); + + for (int a = 0; a < NSEGMENTS; a++) { + v[0] = sinf((2.0f * M_PI * a) / ((float)NSEGMENTS)); + v[1] = cosf((2.0f * M_PI * a) / ((float)NSEGMENTS)); + setAttrib(vbo, pos_id, a * 2, v); + + v[0] = sinf((2.0f * M_PI * (a + 1)) / ((float)NSEGMENTS)); + v[1] = cosf((2.0f * M_PI * (a + 1)) / ((float)NSEGMENTS)); + setAttrib(vbo, pos_id, a * 2 + 1, v); + } + + SHC.drw_lamp = Batch_create(GL_LINES, vbo, NULL); + } + return SHC.drw_lamp; +#undef NSEGMENTS +} + +Batch *DRW_cache_lamp_sunrays_get(void) +{ + if (!SHC.drw_lamp_sunrays) { + float v[2], v1[2], v2[2]; + + /* Position Only 3D format */ + static VertexFormat format = { 0 }; + static unsigned pos_id; + if (format.attrib_ct == 0) { + pos_id = add_attrib(&format, "pos", GL_FLOAT, 2, KEEP_FLOAT); + } + + VertexBuffer *vbo = VertexBuffer_create_with_format(&format); + VertexBuffer_allocate_data(vbo, 16); + + for (int a = 0; a < 8; a++) { + v[0] = sinf((2.0f * M_PI * a) / 8.0f); + v[1] = cosf((2.0f * M_PI * a) / 8.0f); + + mul_v2_v2fl(v1, v, 1.2f); + mul_v2_v2fl(v2, v, 2.5f); + + setAttrib(vbo, pos_id, a * 2, v1); + setAttrib(vbo, pos_id, a * 2 + 1, v2); + } + + SHC.drw_lamp_sunrays = Batch_create(GL_LINES, vbo, NULL); + } + return SHC.drw_lamp_sunrays; +} + + +/* Object Center */ +Batch *DRW_cache_single_vert_get(void) +{ + if (!SHC.drw_single_vertice) { + float v1[3] = {0.0f, 0.0f, 0.0f}; + + /* Position Only 3D format */ + static VertexFormat format = { 0 }; + static unsigned pos_id; + if (format.attrib_ct == 0) { + pos_id = add_attrib(&format, "pos", GL_FLOAT, 3, KEEP_FLOAT); + } + + VertexBuffer *vbo = VertexBuffer_create_with_format(&format); + VertexBuffer_allocate_data(vbo, 1); + + setAttrib(vbo, pos_id, 0, v1); + + SHC.drw_single_vertice = Batch_create(GL_POINTS, vbo, NULL); + } + return SHC.drw_single_vertice; +} + +/* Meshes */ +Batch *DRW_cache_wire_overlay_get(Object *ob) +{ + Batch *overlay_wire = NULL; + + BLI_assert(ob->type == OB_MESH); + + Mesh *me = ob->data; +#if 1 /* new version not working */ + overlay_wire = BKE_mesh_batch_cache_get_overlay_edges(me); +#else + overlay_wire = BKE_mesh_batch_cache_get_all_edges(me); +#endif + return overlay_wire; +} + +Batch *DRW_cache_wire_outline_get(Object *ob) +{ + Batch *fancy_wire = NULL; + + BLI_assert(ob->type == OB_MESH); + + Mesh *me = ob->data; + fancy_wire = BKE_mesh_batch_cache_get_fancy_edges(me); + + return fancy_wire; +} + +Batch *DRW_cache_surface_get(Object *ob) +{ + Batch *surface = NULL; + + BLI_assert(ob->type == OB_MESH); + + Mesh *me = ob->data; + surface = BKE_mesh_batch_cache_get_all_triangles(me); + + return surface; +} + +#if 0 /* TODO */ +struct Batch *DRW_cache_surface_material_get(Object *ob, int nr) { + /* TODO */ + return NULL; +} +#endif
\ No newline at end of file diff --git a/source/blender/draw/intern/draw_cache.h b/source/blender/draw/intern/draw_cache.h new file mode 100644 index 00000000000..c53f3d88af3 --- /dev/null +++ b/source/blender/draw/intern/draw_cache.h @@ -0,0 +1,56 @@ +/* + * Copyright 2016, Blender Foundation. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Contributor(s): Blender Institute + * + */ + +/** \file draw_cache.h + * \ingroup draw + */ + +#ifndef __DRAW_CACHE_H__ +#define __DRAW_CACHE_H__ + +struct Batch; +struct Object; + +void DRW_shape_cache_free(void); + +/* Common Shapes */ +struct Batch *DRW_cache_fullscreen_quad_get(void); +struct Batch *DRW_cache_single_vert_get(void); + +/* Empties */ +struct Batch *DRW_cache_plain_axes_get(void); +struct Batch *DRW_cache_single_arrow_get(struct Batch **line); +struct Batch *DRW_cache_cube_get(void); +struct Batch *DRW_cache_circle_get(void); +struct Batch *DRW_cache_empty_sphere_get(void); +struct Batch *DRW_cache_empty_cone_get(void); +struct Batch *DRW_cache_arrows_get(void); + +/* Lamps */ +struct Batch *DRW_cache_lamp_get(void); +struct Batch *DRW_cache_lamp_sunrays_get(void); + +/* Meshes */ +struct Batch *DRW_cache_wire_overlay_get(struct Object *ob); +struct Batch *DRW_cache_wire_outline_get(struct Object *ob); +struct Batch *DRW_cache_surface_get(struct Object *ob); + +#endif /* __DRAW_CACHE_H__ */
\ No newline at end of file diff --git a/source/blender/draw/intern/draw_manager.c b/source/blender/draw/intern/draw_manager.c new file mode 100644 index 00000000000..a7ce65060e6 --- /dev/null +++ b/source/blender/draw/intern/draw_manager.c @@ -0,0 +1,1148 @@ +/* + * Copyright 2016, Blender Foundation. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Contributor(s): Blender Institute + * + */ + +/** \file blender/draw/draw_manager.c + * \ingroup draw + */ + +#include <stdio.h> + +#include "BLI_listbase.h" +#include "BLI_rect.h" +#include "BLI_string.h" + +#include "BIF_glutil.h" + +#include "BKE_global.h" + +#include "BLT_translation.h" + +#include "DRW_engine.h" +#include "DRW_render.h" + +#include "DNA_view3d_types.h" + +#include "GPU_basic_shader.h" +#include "GPU_batch.h" +#include "GPU_draw.h" +#include "GPU_extensions.h" +#include "GPU_framebuffer.h" +#include "GPU_immediate.h" +#include "GPU_matrix.h" +#include "GPU_shader.h" +#include "GPU_texture.h" +#include "GPU_uniformbuffer.h" +#include "GPU_viewport.h" + +#include "RE_engine.h" + +#include "UI_resources.h" + +#include "clay.h" + +extern char datatoc_gpu_shader_2D_vert_glsl[]; +extern char datatoc_gpu_shader_3D_vert_glsl[]; +extern char datatoc_gpu_shader_basic_vert_glsl[]; + +/* Structures */ +typedef enum { + DRW_UNIFORM_BOOL, + DRW_UNIFORM_INT, + DRW_UNIFORM_FLOAT, + DRW_UNIFORM_TEXTURE, + DRW_UNIFORM_BUFFER, + DRW_UNIFORM_MAT3, + DRW_UNIFORM_MAT4, + DRW_UNIFORM_BLOCK +} DRWUniformType; + +struct DRWUniform { + struct DRWUniform *next, *prev; + DRWUniformType type; + int location; + int length; + int arraysize; + int bindloc; + const void *value; +}; + +struct DRWInterface { + ListBase uniforms; + /* matrices locations */ + int modelview; + int projection; + int modelviewprojection; + int viewprojection; + int normal; + int eye; +}; + +struct DRWPass { + ListBase shgroups; + DRWState state; + float state_param; /* Line / Point width */ +}; + +typedef struct DRWCall { + struct DRWCall *next, *prev; + Batch *geometry; + float(*obmat)[4]; +} DRWCall; + +struct DRWShadingGroup { + struct DRWShadingGroup *next, *prev; + struct GPUShader *shader; /* Shader to bind */ + struct DRWInterface *interface; /* Uniforms pointers */ + ListBase calls; /* List with all geometry and transforms */ + int state; /* State changes for this batch only */ + short dyntype; /* Dynamic Batch type, 0 is normal */ + Batch *dyngeom; /* Dynamic batch */ + GLuint instance_vbo; /* Dynamic batch VBO storing Model Matrices */ + int instance_count; /* Dynamic batch Number of instance to render */ +}; + +/* Render State */ +static struct DRWGlobalState{ + GPUShader *shader; + struct GPUFrameBuffer *default_framebuffer; + FramebufferList *current_fbl; + TextureList *current_txl; + PassList *current_psl; + ListBase bound_texs; + int tex_bind_id; + float size[2]; + float screenvecs[2][3]; + float pixsize; + /* Current rendering context set by DRW_viewport_init */ + const struct bContext *context; +} DST = {NULL}; + +/* ***************************************** TEXTURES ******************************************/ +static void drw_texture_get_format(DRWTextureFormat format, GPUTextureFormat *data_type, int *channels) +{ + switch (format) { + case DRW_TEX_RGBA_8: *data_type = GPU_RGBA8; break; + case DRW_TEX_RGBA_16: *data_type = GPU_RGBA16F; break; + case DRW_TEX_RG_16: *data_type = GPU_RG16F; break; + case DRW_TEX_RG_32: *data_type = GPU_RG32F; break; + case DRW_TEX_R_8: *data_type = GPU_R8; break; +#if 0 + case DRW_TEX_RGBA_32: *data_type = GPU_RGBA32F; break; + case DRW_TEX_RGB_8: *data_type = GPU_RGB8; break; + case DRW_TEX_RGB_16: *data_type = GPU_RGB16F; break; + case DRW_TEX_RGB_32: *data_type = GPU_RGB32F; break; + case DRW_TEX_RG_8: *data_type = GPU_RG8; break; + case DRW_TEX_R_16: *data_type = GPU_R16F; break; + case DRW_TEX_R_32: *data_type = GPU_R32F; break; +#endif + case DRW_TEX_DEPTH_16: *data_type = GPU_DEPTH_COMPONENT16; break; + case DRW_TEX_DEPTH_24: *data_type = GPU_DEPTH_COMPONENT24; break; + case DRW_TEX_DEPTH_32: *data_type = GPU_DEPTH_COMPONENT32F; break; + default : + /* file type not supported you must uncomment it from above */ + BLI_assert(false); + break; + } + + switch (format) { + case DRW_TEX_RGBA_8: + case DRW_TEX_RGBA_16: + case DRW_TEX_RGBA_32: + *channels = 4; + break; + case DRW_TEX_RGB_8: + case DRW_TEX_RGB_16: + case DRW_TEX_RGB_32: + *channels = 3; + break; + case DRW_TEX_RG_8: + case DRW_TEX_RG_16: + case DRW_TEX_RG_32: + *channels = 2; + break; + default: + *channels = 1; + break; + } +} + +static void drw_texture_set_parameters(GPUTexture *tex, DRWTextureFlag flags) +{ + GPU_texture_bind(tex, 0); + GPU_texture_filter_mode(tex, flags & DRW_TEX_FILTER); + GPU_texture_wrap_mode(tex, flags & DRW_TEX_WRAP); + GPU_texture_compare_mode(tex, flags & DRW_TEX_COMPARE); + GPU_texture_unbind(tex); +} + +GPUTexture *DRW_texture_create_1D(int w, DRWTextureFormat format, DRWTextureFlag flags, const float *fpixels) +{ + GPUTexture *tex; + GPUTextureFormat data_type; + int channels; + + drw_texture_get_format(format, &data_type, &channels); + tex = GPU_texture_create_1D_custom(w, channels, data_type, fpixels, NULL); + drw_texture_set_parameters(tex, flags); + + return tex; +} + +GPUTexture *DRW_texture_create_2D(int w, int h, DRWTextureFormat format, DRWTextureFlag flags, const float *fpixels) +{ + GPUTexture *tex; + GPUTextureFormat data_type; + int channels; + + drw_texture_get_format(format, &data_type, &channels); + tex = GPU_texture_create_2D_custom(w, h, channels, data_type, fpixels, NULL); + drw_texture_set_parameters(tex, flags); + + return tex; +} + +/* TODO make use of format */ +GPUTexture *DRW_texture_create_2D_array(int w, int h, int d, DRWTextureFormat UNUSED(format), DRWTextureFlag flags, const float *fpixels) +{ + GPUTexture *tex; + + tex = GPU_texture_create_2D_array(w, h, d, fpixels, NULL); + drw_texture_set_parameters(tex, flags); + + return tex; +} + +void DRW_texture_free(GPUTexture *tex) +{ + GPU_texture_free(tex); +} + + +/* ************************************ UNIFORM BUFFER OBJECT **********************************/ + +GPUUniformBuffer *DRW_uniformbuffer_create(int size, const void *data) +{ + return GPU_uniformbuffer_create(size, data, NULL); +} + +void DRW_uniformbuffer_update(GPUUniformBuffer *ubo, const void *data) +{ + GPU_uniformbuffer_update(ubo, data); +} + +void DRW_uniformbuffer_free(GPUUniformBuffer *ubo) +{ + GPU_uniformbuffer_free(ubo); +} + +/* ****************************************** SHADERS ******************************************/ + +GPUShader *DRW_shader_create(const char *vert, const char *geom, const char *frag, const char *defines) +{ + return GPU_shader_create(vert, frag, geom, NULL, defines, 0, 0, 0); +} + +GPUShader *DRW_shader_create_2D(const char *frag, const char *defines) +{ + return GPU_shader_create(datatoc_gpu_shader_2D_vert_glsl, frag, NULL, NULL, defines, 0, 0, 0); +} + +GPUShader *DRW_shader_create_3D(const char *frag, const char *defines) +{ + return GPU_shader_create(datatoc_gpu_shader_3D_vert_glsl, frag, NULL, NULL, defines, 0, 0, 0); +} + +GPUShader *DRW_shader_create_3D_depth_only(void) +{ + return GPU_shader_get_builtin_shader(GPU_SHADER_3D_DEPTH_ONLY); +} + +void DRW_shader_free(GPUShader *shader) +{ + GPU_shader_free(shader); +} + +/* ***************************************** INTERFACE ******************************************/ + +static DRWInterface *DRW_interface_create(GPUShader *shader) +{ + DRWInterface *interface = MEM_mallocN(sizeof(DRWInterface), "DRWInterface"); + + interface->modelview = GPU_shader_get_uniform(shader, "ModelViewMatrix"); + interface->projection = GPU_shader_get_uniform(shader, "ProjectionMatrix"); + interface->viewprojection = GPU_shader_get_uniform(shader, "ViewProjectionMatrix"); + interface->modelviewprojection = GPU_shader_get_uniform(shader, "ModelViewProjectionMatrix"); + interface->normal = GPU_shader_get_uniform(shader, "NormalMatrix"); + interface->eye = GPU_shader_get_uniform(shader, "eye"); + + BLI_listbase_clear(&interface->uniforms); + + return interface; +} + +static void DRW_interface_uniform(DRWShadingGroup *shgroup, const char *name, + DRWUniformType type, const void *value, int length, int arraysize, int bindloc) +{ + DRWUniform *uni = MEM_mallocN(sizeof(DRWUniform), "DRWUniform"); + + if (type == DRW_UNIFORM_BLOCK) { + uni->location = GPU_shader_get_uniform_block(shgroup->shader, name); + } + else { + uni->location = GPU_shader_get_uniform(shgroup->shader, name); + } + + uni->type = type; + uni->value = value; + uni->length = length; + uni->arraysize = arraysize; + uni->bindloc = bindloc; /* for textures */ + + if (uni->location == -1) { + if (G.debug & G_DEBUG) + fprintf(stderr, "Uniform '%s' not found!\n", name); + + MEM_freeN(uni); + return; + } + + BLI_addtail(&shgroup->interface->uniforms, uni); +} + +void DRW_get_dfdy_factors(float dfdyfac[2]) +{ + GPU_get_dfdy_factors(dfdyfac); +} + +/* ***************************************** SHADING GROUP ******************************************/ + +DRWShadingGroup *DRW_shgroup_create(struct GPUShader *shader, DRWPass *pass) +{ + DRWShadingGroup *shgroup = MEM_callocN(sizeof(DRWShadingGroup), "DRWShadingGroup"); + + shgroup->shader = shader; + shgroup->interface = DRW_interface_create(shader); + shgroup->state = 0; + shgroup->dyntype = 0; + shgroup->dyngeom = NULL; + + BLI_addtail(&pass->shgroups, shgroup); + + return shgroup; +} + +void DRW_shgroup_free(struct DRWShadingGroup *shgroup) +{ + BLI_freelistN(&shgroup->calls); + BLI_freelistN(&shgroup->interface->uniforms); + MEM_freeN(shgroup->interface); + + if (shgroup->dyngeom) + Batch_discard_all(shgroup->dyngeom); +} + +/* Later use VBO */ +void DRW_shgroup_call_add(DRWShadingGroup *shgroup, Batch *geom, float (*obmat)[4]) +{ + if (geom) { + DRWCall *call = MEM_callocN(sizeof(DRWCall), "DRWCall"); + + call->obmat = obmat; + call->geometry = geom; + + BLI_addtail(&shgroup->calls, call); + } +} + +/* Make sure you know what you do when using this, + * State is not revert back at the end of the shgroup */ +void DRW_shgroup_state_set(DRWShadingGroup *shgroup, DRWState state) +{ + shgroup->state = state; +} + +void DRW_shgroup_dyntype_set(DRWShadingGroup *shgroup, int type) +{ + shgroup->dyntype = type; +} + +void DRW_shgroup_uniform_texture(DRWShadingGroup *shgroup, const char *name, const GPUTexture *tex, int loc) +{ + DRW_interface_uniform(shgroup, name, DRW_UNIFORM_TEXTURE, tex, 0, 0, loc); +} + +void DRW_shgroup_uniform_block(DRWShadingGroup *shgroup, const char *name, const GPUUniformBuffer *ubo, int loc) +{ + DRW_interface_uniform(shgroup, name, DRW_UNIFORM_BLOCK, ubo, 0, 0, loc); +} + +void DRW_shgroup_uniform_buffer(DRWShadingGroup *shgroup, const char *name, const int value, int loc) +{ + /* we abuse the lenght attrib to store the buffer index */ + DRW_interface_uniform(shgroup, name, DRW_UNIFORM_BUFFER, NULL, value, 0, loc); +} + +void DRW_shgroup_uniform_bool(DRWShadingGroup *shgroup, const char *name, const bool *value, int arraysize) +{ + DRW_interface_uniform(shgroup, name, DRW_UNIFORM_BOOL, value, 1, arraysize, 0); +} + +void DRW_shgroup_uniform_float(DRWShadingGroup *shgroup, const char *name, const float *value, int arraysize) +{ + DRW_interface_uniform(shgroup, name, DRW_UNIFORM_FLOAT, value, 1, arraysize, 0); +} + +void DRW_shgroup_uniform_vec2(DRWShadingGroup *shgroup, const char *name, const float *value, int arraysize) +{ + DRW_interface_uniform(shgroup, name, DRW_UNIFORM_FLOAT, value, 2, arraysize, 0); +} + +void DRW_shgroup_uniform_vec3(DRWShadingGroup *shgroup, const char *name, const float *value, int arraysize) +{ + DRW_interface_uniform(shgroup, name, DRW_UNIFORM_FLOAT, value, 3, arraysize, 0); +} + +void DRW_shgroup_uniform_vec4(DRWShadingGroup *shgroup, const char *name, const float *value, int arraysize) +{ + DRW_interface_uniform(shgroup, name, DRW_UNIFORM_FLOAT, value, 4, arraysize, 0); +} + +void DRW_shgroup_uniform_int(DRWShadingGroup *shgroup, const char *name, const int *value, int arraysize) +{ + DRW_interface_uniform(shgroup, name, DRW_UNIFORM_INT, value, 1, arraysize, 0); +} + +void DRW_shgroup_uniform_ivec2(DRWShadingGroup *shgroup, const char *name, const int *value, int arraysize) +{ + DRW_interface_uniform(shgroup, name, DRW_UNIFORM_INT, value, 2, arraysize, 0); +} + +void DRW_shgroup_uniform_ivec3(DRWShadingGroup *shgroup, const char *name, const int *value, int arraysize) +{ + DRW_interface_uniform(shgroup, name, DRW_UNIFORM_INT, value, 3, arraysize, 0); +} + +void DRW_shgroup_uniform_mat3(DRWShadingGroup *shgroup, const char *name, const float *value) +{ + DRW_interface_uniform(shgroup, name, DRW_UNIFORM_MAT3, value, 9, 1, 0); +} + +void DRW_shgroup_uniform_mat4(DRWShadingGroup *shgroup, const char *name, const float *value) +{ + DRW_interface_uniform(shgroup, name, DRW_UNIFORM_MAT4, value, 16, 1, 0); +} + +/* Creates OGL primitives based on DRWCall.obmat position list */ +static void shgroup_dynamic_batch_primitives(DRWShadingGroup *shgroup) +{ + int i = 0; + int nbr = BLI_listbase_count(&shgroup->calls); + GLenum type; + + if (nbr == 0) { + if (shgroup->dyngeom) { + Batch_discard(shgroup->dyngeom); + shgroup->dyngeom = NULL; + } + return; + } + + /* Gather Data */ + float *data = MEM_mallocN(sizeof(float) * 3 * nbr , "Object Center Batch data"); + + for (DRWCall *call = shgroup->calls.first; call; call = call->next, i++) { + copy_v3_v3(&data[i*3], call->obmat[3]); + } + + /* Upload Data */ + static VertexFormat format = { 0 }; + static unsigned pos_id; + if (format.attrib_ct == 0) { + pos_id = add_attrib(&format, "pos", GL_FLOAT, 3, KEEP_FLOAT); + } + + VertexBuffer *vbo = VertexBuffer_create_with_format(&format); + VertexBuffer_allocate_data(vbo, nbr); + + fillAttrib(vbo, pos_id, data); + + if (shgroup->dyntype == DRW_DYN_POINTS) + type = GL_POINTS; + else + type = GL_LINES; + + /* TODO make the batch dynamic instead of freeing it every times */ + if (shgroup->dyngeom) + Batch_discard_all(shgroup->dyngeom); + + shgroup->dyngeom = Batch_create(type, vbo, NULL); + + MEM_freeN(data); +} + +static void shgroup_dynamic_batch_instance(DRWShadingGroup *shgroup) +{ + int i = 0; + int nbr = BLI_listbase_count(&shgroup->calls); + + shgroup->instance_count = nbr; + + if (nbr == 0) { + if (shgroup->instance_vbo) { + glDeleteBuffers(1, &shgroup->instance_vbo); + shgroup->instance_vbo = 0; + } + return; + } + + /* Gather Data */ + float *data = MEM_mallocN(sizeof(float) * 4 * 4 * nbr , "Instance Model Matrix"); + + for (DRWCall *call = shgroup->calls.first; call; call = call->next, i++) { + copy_m4_m4((float (*)[4])&data[i*16], call->obmat); + } + + /* TODO poke mike to add this to gawain */ + if (shgroup->instance_vbo) { + glDeleteBuffers(1, &shgroup->instance_vbo); + shgroup->instance_vbo = 0; + } + + glGenBuffers(1, &shgroup->instance_vbo); + glBindBuffer(GL_ARRAY_BUFFER, shgroup->instance_vbo); + glBufferData(GL_ARRAY_BUFFER, sizeof(float) * 4 * 4 * nbr, data, GL_STATIC_DRAW); + + MEM_freeN(data); +} + +static void shgroup_dynamic_batch_from_calls(DRWShadingGroup *shgroup) +{ +#ifdef WITH_VIEWPORT_CACHE_TEST + if (shgroup->dyngeom) return; +#endif + if (shgroup->dyntype == DRW_DYN_INSTANCE) { + shgroup_dynamic_batch_instance(shgroup); + } + else { + shgroup_dynamic_batch_primitives(shgroup); + } +} + +/* ***************************************** PASSES ******************************************/ + +DRWPass *DRW_pass_create(const char *name, DRWState state) +{ + DRWPass *pass = MEM_callocN(sizeof(DRWPass), name); + pass->state = state; + + BLI_listbase_clear(&pass->shgroups); + + return pass; +} + +void DRW_pass_free(DRWPass *pass) +{ + for (DRWShadingGroup *shgroup = pass->shgroups.first; shgroup; shgroup = shgroup->next) { + DRW_shgroup_free(shgroup); + } + BLI_freelistN(&pass->shgroups); +} + +/* TODO this is slow we should not have to use this (better store shgroup pointer somewhere) */ +DRWShadingGroup *DRW_pass_nth_shgroup_get(DRWPass *pass, int n) +{ + int i = 0; + for (DRWShadingGroup *shgroup = pass->shgroups.first; shgroup; shgroup = shgroup->next) { + if (i == n) + return shgroup; + i++; + } + + return NULL; +} + +/* ****************************************** DRAW ******************************************/ + +void DRW_draw_background(void) +{ + /* Just to make sure */ + glDepthMask(GL_TRUE); + glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); + + if (UI_GetThemeValue(TH_SHOW_BACK_GRAD)) { + /* Gradient background Color */ + gpuMatrixBegin3D(); /* TODO: finish 2D API */ + + glClear(GL_DEPTH_BUFFER_BIT); + + VertexFormat *format = immVertexFormat(); + unsigned pos = add_attrib(format, "pos", COMP_F32, 2, KEEP_FLOAT); + unsigned color = add_attrib(format, "color", COMP_U8, 3, NORMALIZE_INT_TO_FLOAT); + unsigned char col_hi[3], col_lo[3]; + + immBindBuiltinProgram(GPU_SHADER_2D_SMOOTH_COLOR); + + UI_GetThemeColor3ubv(TH_LOW_GRAD, col_lo); + UI_GetThemeColor3ubv(TH_HIGH_GRAD, col_hi); + + immBegin(GL_QUADS, 4); + immAttrib3ubv(color, col_lo); + immVertex2f(pos, -1.0f, -1.0f); + immVertex2f(pos, 1.0f, -1.0f); + + immAttrib3ubv(color, col_hi); + immVertex2f(pos, 1.0f, 1.0f); + immVertex2f(pos, -1.0f, 1.0f); + immEnd(); + + immUnbindProgram(); + + gpuMatrixEnd(); + } + else { + /* Solid background Color */ + UI_ThemeClearColorAlpha(TH_HIGH_GRAD, 1.0f); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + } +} +#ifdef WITH_CLAY_ENGINE +/* Only alter the state (does not reset it like set_state() ) */ +static void shgroup_set_state(DRWShadingGroup *shgroup) +{ + if (shgroup->state) { + /* Blend */ + if (shgroup->state & DRW_STATE_BLEND) { + glEnable(GL_BLEND); + } + + /* Wire width */ + if (shgroup->state & DRW_STATE_WIRE) { + glLineWidth(1.0f); + } + else if (shgroup->state & DRW_STATE_WIRE_LARGE) { + glLineWidth(UI_GetThemeValuef(TH_OUTLINE_WIDTH) * 2.0f); + } + + /* Line Stipple */ + if (shgroup->state & DRW_STATE_STIPPLE_2) { + setlinestyle(2); + } + else if (shgroup->state & DRW_STATE_STIPPLE_3) { + setlinestyle(3); + } + else if (shgroup->state & DRW_STATE_STIPPLE_4) { + setlinestyle(4); + } + + if (shgroup->state & DRW_STATE_POINT) { + GPU_enable_program_point_size(); + glPointSize(5.0f); + } + } +} + +typedef struct DRWBoundTexture { + struct DRWBoundTexture *next, *prev; + GPUTexture *tex; +} DRWBoundTexture; + +static void draw_geometry(DRWShadingGroup *shgroup, DRWInterface *interface, Batch *geom, + unsigned int instance_vbo, int instance_count, const float (*obmat)[4]) +{ + RegionView3D *rv3d = CTX_wm_region_view3d(DST.context); + + float mvp[4][4], mv[4][4], n[3][3]; + float eye[3] = { 0.0f, 0.0f, 1.0f }; /* looking into the screen */ + + bool do_mvp = (interface->modelviewprojection != -1); + bool do_mv = (interface->modelview != -1); + bool do_n = (interface->normal != -1); + bool do_eye = (interface->eye != -1); + + if (do_mvp) { + mul_m4_m4m4(mvp, rv3d->persmat, obmat); + } + if (do_mv || do_n || do_eye) { + mul_m4_m4m4(mv, rv3d->viewmat, obmat); + } + if (do_n || do_eye) { + copy_m3_m4(n, mv); + invert_m3(n); + transpose_m3(n); + } + if (do_eye) { + /* Used by orthographic wires */ + float tmp[3][3]; + invert_m3_m3(tmp, n); + /* set eye vector, transformed to object coords */ + mul_m3_v3(tmp, eye); + } + + /* Should be really simple */ + /* step 1 : bind object dependent matrices */ + if (interface->modelviewprojection != -1) { + GPU_shader_uniform_vector(shgroup->shader, interface->modelviewprojection, 16, 1, (float *)mvp); + } + if (interface->viewprojection != -1) { + GPU_shader_uniform_vector(shgroup->shader, interface->viewprojection, 16, 1, (float *)rv3d->persmat); + } + if (interface->projection != -1) { + GPU_shader_uniform_vector(shgroup->shader, interface->projection, 16, 1, (float *)rv3d->winmat); + } + if (interface->modelview != -1) { + GPU_shader_uniform_vector(shgroup->shader, interface->modelview, 16, 1, (float *)mv); + } + if (interface->normal != -1) { + GPU_shader_uniform_vector(shgroup->shader, interface->normal, 9, 1, (float *)n); + } + if (interface->eye != -1) { + GPU_shader_uniform_vector(shgroup->shader, interface->eye, 3, 1, (float *)eye); + } + + /* step 2 : bind vertex array & draw */ + Batch_set_program(geom, GPU_shader_get_program(shgroup->shader)); + if (instance_vbo) { + Batch_draw_stupid_instanced(geom, instance_vbo, instance_count); + } + else { + Batch_draw_stupid(geom); + } +} + +static void draw_shgroup(DRWShadingGroup *shgroup) +{ + BLI_assert(shgroup->shader); + BLI_assert(shgroup->interface); + + DRWInterface *interface = shgroup->interface; + + if (DST.shader != shgroup->shader) { + if (DST.shader) GPU_shader_unbind(); + GPU_shader_bind(shgroup->shader); + DST.shader = shgroup->shader; + } + + if (shgroup->dyntype != 0) { + shgroup_dynamic_batch_from_calls(shgroup); + } + + shgroup_set_state(shgroup); + + /* Binding Uniform */ + /* Don't check anything, Interface should already contain the least uniform as possible */ + for (DRWUniform *uni = interface->uniforms.first; uni; uni = uni->next) { + DRWBoundTexture *bound_tex; + + switch (uni->type) { + case DRW_UNIFORM_BOOL: + case DRW_UNIFORM_INT: + GPU_shader_uniform_vector_int(shgroup->shader, uni->location, uni->length, uni->arraysize, (int *)uni->value); + break; + case DRW_UNIFORM_FLOAT: + case DRW_UNIFORM_MAT3: + case DRW_UNIFORM_MAT4: + GPU_shader_uniform_vector(shgroup->shader, uni->location, uni->length, uni->arraysize, (float *)uni->value); + break; + case DRW_UNIFORM_TEXTURE: + GPU_texture_bind((GPUTexture *)uni->value, uni->bindloc); + + bound_tex = MEM_callocN(sizeof(DRWBoundTexture), "DRWBoundTexture"); + bound_tex->tex = (GPUTexture *)uni->value; + BLI_addtail(&DST.bound_texs, bound_tex); + + GPU_shader_uniform_texture(shgroup->shader, uni->location, (GPUTexture *)uni->value); + break; + case DRW_UNIFORM_BUFFER: + /* restore index from lenght we abused */ + GPU_texture_bind(DST.current_txl->textures[uni->length], uni->bindloc); + GPU_texture_compare_mode(DST.current_txl->textures[uni->length], false); + GPU_texture_filter_mode(DST.current_txl->textures[uni->length], false); + + bound_tex = MEM_callocN(sizeof(DRWBoundTexture), "DRWBoundTexture"); + bound_tex->tex = DST.current_txl->textures[uni->length]; + BLI_addtail(&DST.bound_texs, bound_tex); + + GPU_shader_uniform_texture(shgroup->shader, uni->location, DST.current_txl->textures[uni->length]); + break; + case DRW_UNIFORM_BLOCK: + GPU_uniformbuffer_bind((GPUUniformBuffer *)uni->value, uni->bindloc); + GPU_shader_uniform_buffer(shgroup->shader, uni->location, (GPUUniformBuffer *)uni->value); + break; + } + } + + /* Rendering Calls */ + if (shgroup->dyntype != 0) { + /* Replacing multiple calls with only one */ + float obmat[4][4]; + unit_m4(obmat); + + if (shgroup->dyntype == DRW_DYN_INSTANCE && shgroup->instance_count > 0) { + DRWCall *call = shgroup->calls.first; + draw_geometry(shgroup, interface, call->geometry, shgroup->instance_vbo, shgroup->instance_count, obmat); + } + else { + /* Some dynamic batch can have no geom (no call to aggregate) */ + if (shgroup->dyngeom) { + draw_geometry(shgroup, interface, shgroup->dyngeom, 0, 1, obmat); + } + } + } + else { + for (DRWCall *call = shgroup->calls.first; call; call = call->next) { + draw_geometry(shgroup, interface, call->geometry, 0, 1, call->obmat); + } + } +} + +static void set_state(short flag) +{ + /* TODO Keep track of the state and only revert what is needed */ + + /* Depth Write */ + if (flag & DRW_STATE_WRITE_DEPTH) + glDepthMask(GL_TRUE); + else + glDepthMask(GL_FALSE); + + /* Color Write */ + if (flag & DRW_STATE_WRITE_COLOR) + glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); + else + glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); + + /* Backface Culling */ + if (flag & DRW_STATE_CULL_BACK || + flag & DRW_STATE_CULL_FRONT) { + + glEnable(GL_CULL_FACE); + + if (flag & DRW_STATE_CULL_BACK) + glCullFace(GL_BACK); + else if (flag & DRW_STATE_CULL_FRONT) + glCullFace(GL_FRONT); + } + else { + glDisable(GL_CULL_FACE); + } + + /* Depht Test */ + if (flag & DRW_STATE_DEPTH_LESS || + flag & DRW_STATE_DEPTH_EQUAL) { + + glEnable(GL_DEPTH_TEST); + + if (flag & DRW_STATE_DEPTH_LESS) + glDepthFunc(GL_LEQUAL); + else if (flag & DRW_STATE_DEPTH_EQUAL) + glDepthFunc(GL_EQUAL); + } + else { + glDisable(GL_DEPTH_TEST); + } + + /* Wire Width */ + if (flag & DRW_STATE_WIRE) { + glLineWidth(1.0f); + } + else if (flag & DRW_STATE_WIRE_LARGE) { + glLineWidth(UI_GetThemeValuef(TH_OUTLINE_WIDTH) * 2.0f); + } + + /* Points Size */ + if (flag & DRW_STATE_POINT) { + GPU_enable_program_point_size(); + glPointSize(5.0f); + } + else { + GPU_disable_program_point_size(); + } + + /* Blending (all buffer) */ + if (flag & DRW_STATE_BLEND) { + glEnable(GL_BLEND); + } + else { + glDisable(GL_BLEND); + } + + /* Line Stipple */ + if (flag & DRW_STATE_STIPPLE_2) { + setlinestyle(2); + } + else if (flag & DRW_STATE_STIPPLE_3) { + setlinestyle(3); + } + else if (flag & DRW_STATE_STIPPLE_4) { + setlinestyle(4); + } + else { + setlinestyle(0); + } +} + +void DRW_draw_pass(DRWPass *pass) +{ + /* Start fresh */ + DST.shader = NULL; + DST.tex_bind_id = 0; + + set_state(pass->state); + BLI_listbase_clear(&DST.bound_texs); + + for (DRWShadingGroup *shgroup = pass->shgroups.first; shgroup; shgroup = shgroup->next) { + draw_shgroup(shgroup); + } + + /* Clear Bound textures */ + for (DRWBoundTexture *bound_tex = DST.bound_texs.first; bound_tex; bound_tex = bound_tex->next) { + GPU_texture_unbind(bound_tex->tex); + } + DST.tex_bind_id = 0; + BLI_freelistN(&DST.bound_texs); + + if (DST.shader) { + GPU_shader_unbind(); + DST.shader = NULL; + } +} + +/* Reset state to not interfer with other UI drawcall */ +void DRW_state_reset(void) +{ + DRWState state = 0; + state |= DRW_STATE_WRITE_DEPTH; + state |= DRW_STATE_WRITE_COLOR; + state |= DRW_STATE_DEPTH_LESS; + set_state(state); +} +#endif +/* ****************************************** Settings ******************************************/ +void *DRW_material_settings_get(Material *ma, const char *engine_name) +{ + MaterialEngineSettings *ms = NULL; + + ms = BLI_findstring(&ma->engines_settings, engine_name, offsetof(MaterialEngineSettings, name)); + +#ifdef WITH_CLAY_ENGINE + /* If the settings does not exists yet, create it */ + if (ms == NULL) { + ms = MEM_callocN(sizeof(RenderEngineSettings), "RenderEngineSettings"); + + BLI_strncpy(ms->name, engine_name, 32); + + /* TODO make render_settings_create a polymorphic function */ + if (STREQ(engine_name, RE_engine_id_BLENDER_CLAY)) { + ms->data = CLAY_material_settings_create(); + } + else { + /* No engine matched */ + BLI_assert(false); + } + + BLI_addtail(&ma->engines_settings, ms); + } +#else + return NULL; +#endif + + return ms->data; +} + +/* If scene is NULL, use context scene */ +void *DRW_render_settings_get(Scene *scene, const char *engine_name) +{ + RenderEngineSettings *rs = NULL; + + if (scene == NULL) + scene = CTX_data_scene(DST.context); + + rs = BLI_findstring(&scene->engines_settings, engine_name, offsetof(RenderEngineSettings, name)); + +#ifdef WITH_CLAY_ENGINE + /* If the settings does not exists yet, create it */ + if (rs == NULL) { + rs = MEM_callocN(sizeof(RenderEngineSettings), "RenderEngineSettings"); + + BLI_strncpy(rs->name, engine_name, 32); + + /* TODO make render_settings_create a polymorphic function */ + if (STREQ(engine_name, RE_engine_id_BLENDER_CLAY)) { + rs->data = CLAY_render_settings_create(); + } + else { + /* No engine matched */ + BLI_assert(false); + } + + BLI_addtail(&scene->engines_settings, rs); + } +#else + return NULL; +#endif + + return rs->data; +} +/* ****************************************** Framebuffers ******************************************/ + +void DRW_framebuffer_init(struct GPUFrameBuffer **fb, int width, int height, DRWFboTexture textures[MAX_FBO_TEX], + int texnbr) +{ + if (!*fb) { + int color_attachment = -1; + *fb = GPU_framebuffer_create(); + + for (int i = 0; i < texnbr; ++i) + { + DRWFboTexture fbotex = textures[i]; + + if (!*fbotex.tex) { + /* TODO refine to opengl formats */ + if (fbotex.format == DRW_BUF_DEPTH_16 || + fbotex.format == DRW_BUF_DEPTH_24) { + *fbotex.tex = GPU_texture_create_depth(width, height, NULL); + GPU_texture_compare_mode(*fbotex.tex, false); + GPU_texture_filter_mode(*fbotex.tex, false); + } + else { + *fbotex.tex = GPU_texture_create_2D(width, height, NULL, NULL); + ++color_attachment; + } + } + + GPU_framebuffer_texture_attach(*fb, *fbotex.tex, color_attachment); + } + + if (!GPU_framebuffer_check_valid(*fb, NULL)) { + printf("Error invalid framebuffer\n"); + } + + GPU_framebuffer_bind(DST.default_framebuffer); + } +} + +void DRW_framebuffer_bind(struct GPUFrameBuffer *fb) +{ + GPU_framebuffer_bind(fb); +} + +void DRW_framebuffer_texture_attach(struct GPUFrameBuffer *fb, GPUTexture *tex, int slot) +{ + GPU_framebuffer_texture_attach(fb, tex, slot); +} + +void DRW_framebuffer_texture_detach(GPUTexture *tex) +{ + GPU_framebuffer_texture_detach(tex); +} + +/* ****************************************** Viewport ******************************************/ + +float *DRW_viewport_size_get(void) +{ + return &DST.size[0]; +} + +float *DRW_viewport_screenvecs_get(void) +{ + return &DST.screenvecs[0][0]; +} + +float *DRW_viewport_pixelsize_get(void) +{ + return &DST.pixsize; +} + +void DRW_viewport_init(const bContext *C, void **buffers, void **textures, void **passes) +{ + RegionView3D *rv3d = CTX_wm_region_view3d(C); + GPUViewport *viewport = rv3d->viewport; + + GPU_viewport_get_engine_data(viewport, buffers, textures, passes); + + /* Refresh DST.size */ + DefaultTextureList *txl = (DefaultTextureList *)*textures; + DST.size[0] = (float)GPU_texture_width(txl->color); + DST.size[1] = (float)GPU_texture_height(txl->color); + + DefaultFramebufferList *fbl = (DefaultFramebufferList *)*buffers; + DST.default_framebuffer = fbl->default_fb; + + DST.current_txl = (TextureList *)*textures; + DST.current_fbl = (FramebufferList *)*buffers; + DST.current_psl = (PassList *)*passes; + + /* Refresh DST.screenvecs */ + copy_v3_v3(DST.screenvecs[0], rv3d->viewinv[0]); + copy_v3_v3(DST.screenvecs[1], rv3d->viewinv[1]); + normalize_v3(DST.screenvecs[0]); + normalize_v3(DST.screenvecs[1]); + + /* Refresh DST.pixelsize */ + DST.pixsize = rv3d->pixsize; + + /* Save context for all later needs */ + DST.context = C; +} + +void DRW_viewport_matrix_get(float mat[4][4], DRWViewportMatrixType type) +{ + RegionView3D *rv3d = CTX_wm_region_view3d(DST.context); + + if (type == DRW_MAT_PERS) + copy_m4_m4(mat, rv3d->persmat); + else if (type == DRW_MAT_WIEW) + copy_m4_m4(mat, rv3d->viewmat); + else if (type == DRW_MAT_WIN) + copy_m4_m4(mat, rv3d->winmat); +} + +bool DRW_viewport_is_persp_get(void) +{ + RegionView3D *rv3d = CTX_wm_region_view3d(DST.context); + return rv3d->is_persp; +} + +bool DRW_viewport_cache_is_dirty(void) +{ + /* TODO Use a dirty flag */ + return (DST.current_psl->passes[0] == NULL); +} + +/* ****************************************** INIT ******************************************/ + +void DRW_engines_init(void) +{ +#ifdef WITH_CLAY_ENGINE + RE_engines_register(NULL, &viewport_clay_type); +#endif +} + +void DRW_engines_free(void) +{ +#ifdef WITH_CLAY_ENGINE + clay_engine_free(); + + DRW_shape_cache_free(); + + BLI_remlink(&R_engines, &viewport_clay_type); +#endif +}
\ No newline at end of file diff --git a/source/blender/draw/intern/draw_mode_pass.c b/source/blender/draw/intern/draw_mode_pass.c new file mode 100644 index 00000000000..507872a4fee --- /dev/null +++ b/source/blender/draw/intern/draw_mode_pass.c @@ -0,0 +1,787 @@ +/* + * Copyright 2016, Blender Foundation. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Contributor(s): Blender Institute + * + */ + +/** \file blender/draw/draw_mode_pass.c + * \ingroup draw + */ + +#include "DNA_userdef_types.h" + +#include "GPU_shader.h" + +#include "UI_resources.h" + +#include "BKE_global.h" + +#include "draw_mode_pass.h" + +/* ************************** OBJECT MODE ******************************* */ + +/* Store list of shading group for easy access*/ + +/* Empties */ +static DRWShadingGroup *plain_axes_wire; +static DRWShadingGroup *plain_axes_active; +static DRWShadingGroup *plain_axes_select; +static DRWShadingGroup *plain_axes_transform; +static DRWShadingGroup *plain_axes_group; +static DRWShadingGroup *plain_axes_group_active; + +static DRWShadingGroup *cube_wire; +static DRWShadingGroup *cube_active; +static DRWShadingGroup *cube_select; +static DRWShadingGroup *cube_transform; +static DRWShadingGroup *cube_group; +static DRWShadingGroup *cube_group_active; + +static DRWShadingGroup *circle_wire; +static DRWShadingGroup *circle_active; +static DRWShadingGroup *circle_select; +static DRWShadingGroup *circle_transform; +static DRWShadingGroup *circle_group; +static DRWShadingGroup *circle_group_active; + +static DRWShadingGroup *sphere_wire; +static DRWShadingGroup *sphere_active; +static DRWShadingGroup *sphere_select; +static DRWShadingGroup *sphere_transform; +static DRWShadingGroup *sphere_group; +static DRWShadingGroup *sphere_group_active; + +static DRWShadingGroup *cone_wire; +static DRWShadingGroup *cone_active; +static DRWShadingGroup *cone_select; +static DRWShadingGroup *cone_transform; +static DRWShadingGroup *cone_group; +static DRWShadingGroup *cone_group_active; + +static DRWShadingGroup *single_arrow_wire; +static DRWShadingGroup *single_arrow_active; +static DRWShadingGroup *single_arrow_select; +static DRWShadingGroup *single_arrow_transform; +static DRWShadingGroup *single_arrow_group; +static DRWShadingGroup *single_arrow_group_active; + +static DRWShadingGroup *single_arrow_line_wire; +static DRWShadingGroup *single_arrow_line_active; +static DRWShadingGroup *single_arrow_line_select; +static DRWShadingGroup *single_arrow_line_transform; +static DRWShadingGroup *single_arrow_line_group; +static DRWShadingGroup *single_arrow_line_group_active; + +static DRWShadingGroup *arrows_wire; +static DRWShadingGroup *arrows_active; +static DRWShadingGroup *arrows_select; +static DRWShadingGroup *arrows_transform; +static DRWShadingGroup *arrows_group; +static DRWShadingGroup *arrows_group_active; + +/* Lamps */ +static DRWShadingGroup *lamp_center; +static DRWShadingGroup *lamp_center_group; +static DRWShadingGroup *lamp_groundpoint; +static DRWShadingGroup *lamp_groundline; +static DRWShadingGroup *lamp_circle; +static DRWShadingGroup *lamp_circle_active; +static DRWShadingGroup *lamp_circle_select; +static DRWShadingGroup *lamp_circle_transform; +static DRWShadingGroup *lamp_circle_group; +static DRWShadingGroup *lamp_circle_group_active; +static DRWShadingGroup *lamp_circle_shadow; +static DRWShadingGroup *lamp_circle_shadow_active; +static DRWShadingGroup *lamp_circle_shadow_select; +static DRWShadingGroup *lamp_circle_shadow_transform; +static DRWShadingGroup *lamp_circle_shadow_group; +static DRWShadingGroup *lamp_circle_shadow_group_active; +static DRWShadingGroup *lamp_sunrays; +static DRWShadingGroup *lamp_sunrays_active; +static DRWShadingGroup *lamp_sunrays_select; +static DRWShadingGroup *lamp_sunrays_transform; +static DRWShadingGroup *lamp_sunrays_group; +static DRWShadingGroup *lamp_sunrays_group_active; + +/* Helpers */ +static DRWShadingGroup *relationship_lines; + +/* Objects Centers */ +static DRWShadingGroup *center_active; +static DRWShadingGroup *center_selected; +static DRWShadingGroup *center_deselected; + +static DRWShadingGroup *shgroup_instance_uniform_color(DRWPass *pass, float color[4]) +{ + GPUShader *sh_inst = GPU_shader_get_builtin_shader(GPU_SHADER_3D_UNIFORM_COLOR_INSTANCE); + + DRWShadingGroup *grp = DRW_shgroup_create(sh_inst, pass); + DRW_shgroup_uniform_vec4(grp, "color", color, 1); + DRW_shgroup_dyntype_set(grp, DRW_DYN_INSTANCE); + + return grp; +} + +static DRWShadingGroup *shgroup_dynlines_uniform_color(DRWPass *pass, float color[4]) +{ + GPUShader *sh = GPU_shader_get_builtin_shader(GPU_SHADER_3D_UNIFORM_COLOR); + + DRWShadingGroup *grp = DRW_shgroup_create(sh, pass); + DRW_shgroup_uniform_vec4(grp, "color", color, 1); + DRW_shgroup_dyntype_set(grp, DRW_DYN_LINES); + + return grp; +} + +static DRWShadingGroup *shgroup_dynpoints_uniform_color(DRWPass *pass, float color[4], float *size) +{ + GPUShader *sh = GPU_shader_get_builtin_shader(GPU_SHADER_3D_POINT_UNIFORM_SIZE_UNIFORM_COLOR_SMOOTH); + + DRWShadingGroup *grp = DRW_shgroup_create(sh, pass); + DRW_shgroup_uniform_vec4(grp, "color", color, 1); + DRW_shgroup_uniform_float(grp, "size", size, 1); + DRW_shgroup_dyntype_set(grp, DRW_DYN_POINTS); + DRW_shgroup_state_set(grp, DRW_STATE_POINT); + + return grp; +} + +static DRWShadingGroup *shgroup_groundlines_uniform_color(DRWPass *pass, float color[4]) +{ + GPUShader *sh = GPU_shader_get_builtin_shader(GPU_SHADER_3D_GROUNDLINE); + + DRWShadingGroup *grp = DRW_shgroup_create(sh, pass); + DRW_shgroup_uniform_vec4(grp, "color", color, 1); + DRW_shgroup_dyntype_set(grp, DRW_DYN_POINTS); + + return grp; +} + +static DRWShadingGroup *shgroup_groundpoints_uniform_color(DRWPass *pass, float color[4]) +{ + GPUShader *sh = GPU_shader_get_builtin_shader(GPU_SHADER_3D_GROUNDPOINT); + + DRWShadingGroup *grp = DRW_shgroup_create(sh, pass); + DRW_shgroup_uniform_vec4(grp, "color", color, 1); + DRW_shgroup_dyntype_set(grp, DRW_DYN_POINTS); + DRW_shgroup_state_set(grp, DRW_STATE_POINT); + return grp; +} + +static DRWShadingGroup *shgroup_lamp(DRWPass *pass, float color[4], float *size) +{ + GPUShader *sh = GPU_shader_get_builtin_shader(GPU_SHADER_3D_LAMP_COMMON); + + DRWShadingGroup *grp = DRW_shgroup_create(sh, pass); + DRW_shgroup_uniform_vec4(grp, "color", color, 1); + DRW_shgroup_uniform_float(grp, "size", size, 1); + DRW_shgroup_uniform_float(grp, "pixel_size", DRW_viewport_pixelsize_get(), 1); + DRW_shgroup_uniform_vec3(grp, "screen_vecs", DRW_viewport_screenvecs_get(), 2); + DRW_shgroup_dyntype_set(grp, DRW_DYN_INSTANCE); + DRW_shgroup_state_set(grp, DRW_STATE_STIPPLE_3); + return grp; +} + +/* This Function setup the passes needed for the mode rendering. + * The passes are populated by the rendering engine using the DRW_shgroup_* functions. */ +void DRW_pass_setup_common(DRWPass **wire_overlay, DRWPass **wire_outline, DRWPass **non_meshes, DRWPass **ob_center) +{ + /* Theses are defined for the whole application so make sure they rely on global settings */ + static float colorWire[4], colorWireEdit[4]; + static float colorActive[4], colorSelect[4], colorTransform[4], colorGroup[4], colorGroupActive[4]; + static float colorEmpty[4], colorLamp[4], colorCamera[4], colorSpeaker[4]; + static float lampCenterSize, lampCircleRad, lampCircleShadowRad, colorLampNoAlpha[4]; + + UI_GetThemeColor4fv(TH_WIRE, colorWire); + UI_GetThemeColor4fv(TH_WIRE_EDIT, colorWireEdit); + UI_GetThemeColor4fv(TH_ACTIVE, colorActive); + UI_GetThemeColor4fv(TH_SELECT, colorSelect); + UI_GetThemeColor4fv(TH_TRANSFORM, colorTransform); + UI_GetThemeColor4fv(TH_GROUP_ACTIVE, colorGroupActive); + UI_GetThemeColor4fv(TH_GROUP, colorGroup); + UI_GetThemeColor4fv(TH_LAMP, colorLamp); + UI_GetThemeColor4fv(TH_LAMP, colorLampNoAlpha); + UI_GetThemeColor4fv(TH_SPEAKER, colorSpeaker); + UI_GetThemeColor4fv(TH_CAMERA, colorCamera); + UI_GetThemeColor4fv(TH_EMPTY, colorEmpty); + + colorLampNoAlpha[3] = 1.0f; + + if (wire_overlay) { + /* This pass can draw mesh edges top of Shaded Meshes without any Z fighting */ + DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_BLEND; + *wire_overlay = DRW_pass_create("Wire Overlays Pass", state); + } + + if (wire_outline) { + /* This pass can draw mesh outlines and/or fancy wireframe */ + /* Fancy wireframes are not meant to be occluded (without Z offset) */ + /* Outlines and Fancy Wires use the same VBO */ + DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS | DRW_STATE_BLEND; + *wire_outline = DRW_pass_create("Wire + Outlines Pass", state); + } + + if (non_meshes) { + /* Non Meshes Pass (Camera, empties, lamps ...) */ + DRWShadingGroup *grp; + + DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS | DRW_STATE_BLEND; + state |= DRW_STATE_WIRE; + *non_meshes = DRW_pass_create("Non Meshes Pass", state); + + GPUShader *sh = GPU_shader_get_builtin_shader(GPU_SHADER_3D_UNIFORM_COLOR); + + /* Empties */ + plain_axes_wire = shgroup_instance_uniform_color(*non_meshes, colorEmpty); + plain_axes_active = shgroup_instance_uniform_color(*non_meshes, colorActive); + plain_axes_select = shgroup_instance_uniform_color(*non_meshes, colorSelect); + plain_axes_transform = shgroup_instance_uniform_color(*non_meshes, colorTransform); + plain_axes_group = shgroup_instance_uniform_color(*non_meshes, colorGroup); + plain_axes_group_active = shgroup_instance_uniform_color(*non_meshes, colorGroupActive); + + cube_wire = shgroup_instance_uniform_color(*non_meshes, colorEmpty); + cube_active = shgroup_instance_uniform_color(*non_meshes, colorActive); + cube_select = shgroup_instance_uniform_color(*non_meshes, colorSelect); + cube_transform = shgroup_instance_uniform_color(*non_meshes, colorTransform); + cube_group = shgroup_instance_uniform_color(*non_meshes, colorGroup); + cube_group_active = shgroup_instance_uniform_color(*non_meshes, colorGroupActive); + + circle_wire = shgroup_instance_uniform_color(*non_meshes, colorEmpty); + circle_active = shgroup_instance_uniform_color(*non_meshes, colorActive); + circle_select = shgroup_instance_uniform_color(*non_meshes, colorSelect); + circle_transform = shgroup_instance_uniform_color(*non_meshes, colorTransform); + circle_group = shgroup_instance_uniform_color(*non_meshes, colorGroup); + circle_group_active = shgroup_instance_uniform_color(*non_meshes, colorGroupActive); + + sphere_wire = shgroup_instance_uniform_color(*non_meshes, colorEmpty); + sphere_active = shgroup_instance_uniform_color(*non_meshes, colorActive); + sphere_select = shgroup_instance_uniform_color(*non_meshes, colorSelect); + sphere_transform = shgroup_instance_uniform_color(*non_meshes, colorTransform); + sphere_group = shgroup_instance_uniform_color(*non_meshes, colorGroup); + sphere_group_active = shgroup_instance_uniform_color(*non_meshes, colorGroupActive); + + cone_wire = shgroup_instance_uniform_color(*non_meshes, colorEmpty); + cone_active = shgroup_instance_uniform_color(*non_meshes, colorActive); + cone_select = shgroup_instance_uniform_color(*non_meshes, colorSelect); + cone_transform = shgroup_instance_uniform_color(*non_meshes, colorTransform); + cone_group = shgroup_instance_uniform_color(*non_meshes, colorGroup); + cone_group_active = shgroup_instance_uniform_color(*non_meshes, colorGroupActive); + + single_arrow_wire = shgroup_instance_uniform_color(*non_meshes, colorEmpty); + single_arrow_active = shgroup_instance_uniform_color(*non_meshes, colorActive); + single_arrow_select = shgroup_instance_uniform_color(*non_meshes, colorSelect); + single_arrow_transform = shgroup_instance_uniform_color(*non_meshes, colorTransform); + single_arrow_group = shgroup_instance_uniform_color(*non_meshes, colorGroup); + single_arrow_group_active = shgroup_instance_uniform_color(*non_meshes, colorGroupActive); + + single_arrow_line_wire = shgroup_instance_uniform_color(*non_meshes, colorEmpty); + single_arrow_line_active = shgroup_instance_uniform_color(*non_meshes, colorActive); + single_arrow_line_select = shgroup_instance_uniform_color(*non_meshes, colorSelect); + single_arrow_line_transform = shgroup_instance_uniform_color(*non_meshes, colorTransform); + single_arrow_line_group = shgroup_instance_uniform_color(*non_meshes, colorGroup); + single_arrow_line_group_active = shgroup_instance_uniform_color(*non_meshes, colorGroupActive); + + arrows_wire = shgroup_instance_uniform_color(*non_meshes, colorEmpty); + arrows_active = shgroup_instance_uniform_color(*non_meshes, colorActive); + arrows_select = shgroup_instance_uniform_color(*non_meshes, colorSelect); + arrows_transform = shgroup_instance_uniform_color(*non_meshes, colorTransform); + arrows_group = shgroup_instance_uniform_color(*non_meshes, colorGroup); + arrows_group_active = shgroup_instance_uniform_color(*non_meshes, colorGroupActive); + + /* Lamps */ + lampCenterSize = (U.obcenter_dia + 1.5f) * U.pixelsize; + lampCircleRad = U.pixelsize * 9.0f; + lampCircleShadowRad = lampCircleRad + U.pixelsize * 3.0f; + /* TODO + * for now we create 3 times the same VBO with only lamp center coordinates + * but ideally we would only create it once */ + lamp_center = shgroup_dynpoints_uniform_color(*non_meshes, colorLampNoAlpha, &lampCenterSize); + lamp_center_group = shgroup_dynpoints_uniform_color(*non_meshes, colorGroup, &lampCenterSize); + lamp_circle = shgroup_lamp(*non_meshes, colorLampNoAlpha, &lampCircleRad); + lamp_circle_active = shgroup_lamp(*non_meshes, colorActive, &lampCircleRad); + lamp_circle_select = shgroup_lamp(*non_meshes, colorSelect, &lampCircleRad); + lamp_circle_transform = shgroup_lamp(*non_meshes, colorTransform, &lampCircleRad); + lamp_circle_group = shgroup_lamp(*non_meshes, colorGroup, &lampCircleRad); + lamp_circle_group_active = shgroup_lamp(*non_meshes, colorGroupActive, &lampCircleRad); + lamp_circle_shadow = shgroup_lamp(*non_meshes, colorLampNoAlpha, &lampCircleShadowRad); + lamp_circle_shadow_active = shgroup_lamp(*non_meshes, colorActive, &lampCircleShadowRad); + lamp_circle_shadow_select = shgroup_lamp(*non_meshes, colorSelect, &lampCircleShadowRad); + lamp_circle_shadow_transform = shgroup_lamp(*non_meshes, colorTransform, &lampCircleShadowRad); + lamp_circle_shadow_group = shgroup_lamp(*non_meshes, colorGroup, &lampCircleShadowRad); + lamp_circle_shadow_group_active = shgroup_lamp(*non_meshes, colorGroupActive, &lampCircleShadowRad); + lamp_sunrays = shgroup_lamp(*non_meshes, colorLampNoAlpha, &lampCircleRad); + lamp_sunrays_active = shgroup_lamp(*non_meshes, colorActive, &lampCircleRad); + lamp_sunrays_select = shgroup_lamp(*non_meshes, colorSelect, &lampCircleRad); + lamp_sunrays_transform = shgroup_lamp(*non_meshes, colorTransform, &lampCircleRad); + lamp_sunrays_group = shgroup_lamp(*non_meshes, colorGroup, &lampCircleRad); + lamp_sunrays_group_active = shgroup_lamp(*non_meshes, colorGroupActive, &lampCircleRad); + lamp_groundline = shgroup_groundlines_uniform_color(*non_meshes, colorLamp); + lamp_groundpoint = shgroup_groundpoints_uniform_color(*non_meshes, colorLamp); + + /* Stipple Wires */ + grp = DRW_shgroup_create(sh, *non_meshes); + DRW_shgroup_state_set(grp, DRW_STATE_STIPPLE_2); + + grp = DRW_shgroup_create(sh, *non_meshes); + DRW_shgroup_state_set(grp, DRW_STATE_STIPPLE_3); + + grp = DRW_shgroup_create(sh, *non_meshes); + DRW_shgroup_state_set(grp, DRW_STATE_STIPPLE_4); + + /* Relationship Lines */ + relationship_lines = shgroup_dynlines_uniform_color(*non_meshes, colorWire); + DRW_shgroup_state_set(relationship_lines, DRW_STATE_STIPPLE_3); + } + + if (ob_center) { + /* Object Center pass grouped by State */ + DRWShadingGroup *grp; + static float colorDeselect[4], outlineColor[4]; + static float outlineWidth, size; + + DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND | DRW_STATE_POINT; + *ob_center = DRW_pass_create("Obj Center Pass", state); + + outlineWidth = 1.0f * U.pixelsize; + size = U.obcenter_dia * U.pixelsize + outlineWidth; + //UI_GetThemeColorShadeAlpha4fv(TH_ACTIVE, 0, -80, colorActive); + //UI_GetThemeColorShadeAlpha4fv(TH_SELECT, 0, -80, colorSelect); + UI_GetThemeColorShadeAlpha4fv(TH_TRANSFORM, 0, -80, colorDeselect); + UI_GetThemeColorShadeAlpha4fv(TH_WIRE, 0, -30, outlineColor); + + GPUShader *sh = GPU_shader_get_builtin_shader(GPU_SHADER_3D_POINT_UNIFORM_SIZE_UNIFORM_COLOR_OUTLINE_SMOOTH); + + /* Active */ + grp = DRW_shgroup_create(sh, *ob_center); + DRW_shgroup_dyntype_set(grp, DRW_DYN_POINTS); + DRW_shgroup_uniform_float(grp, "size", &size, 1); + DRW_shgroup_uniform_float(grp, "outlineWidth", &outlineWidth, 1); + DRW_shgroup_uniform_vec4(grp, "color", colorActive, 1); + DRW_shgroup_uniform_vec4(grp, "outlineColor", outlineColor, 1); + center_active = grp; + + /* Select */ + grp = DRW_shgroup_create(sh, *ob_center); + DRW_shgroup_dyntype_set(grp, DRW_DYN_POINTS); + DRW_shgroup_uniform_vec4(grp, "color", colorSelect, 1); + center_selected = grp; + + /* Deselect */ + grp = DRW_shgroup_create(sh, *ob_center); + DRW_shgroup_dyntype_set(grp, DRW_DYN_POINTS); + DRW_shgroup_uniform_vec4(grp, "color", colorDeselect, 1); + center_deselected = grp; + } +} + +/* ******************************************** WIRES *********************************************** */ + +/* TODO FINISH */ +static int draw_object_wire_theme(Object *ob) +{ + const bool is_edit = (ob->mode & OB_MODE_EDIT) != 0; + /* confusing logic here, there are 2 methods of setting the color + * 'colortab[colindex]' and 'theme_id', colindex overrides theme_id. + * + * note: no theme yet for 'colindex' */ + int theme_id = is_edit ? TH_WIRE_EDIT : TH_WIRE; + + if (//(scene->obedit == NULL) && + ((G.moving & G_TRANSFORM_OBJ) != 0) && + ((ob->base_flag & BASE_SELECTED) != 0)) + { + theme_id = TH_TRANSFORM; + } + else { + /* Sets the 'theme_id' or fallback to wire */ + if ((ob->flag & OB_FROMGROUP) != 0) { + if ((ob->base_flag & BASE_SELECTED) != 0) { + /* uses darker active color for non-active + selected */ + theme_id = TH_GROUP_ACTIVE; + + // if (scene->basact != base) { + // theme_shade = -16; + // } + } + else { + theme_id = TH_GROUP; + } + } + else { + if ((ob->base_flag & BASE_SELECTED) != 0) { + theme_id = //scene->basact == base ? TH_ACTIVE : + TH_SELECT; + } + else { + if (ob->type == OB_LAMP) theme_id = TH_LAMP; + else if (ob->type == OB_SPEAKER) theme_id = TH_SPEAKER; + else if (ob->type == OB_CAMERA) theme_id = TH_CAMERA; + else if (ob->type == OB_EMPTY) theme_id = TH_EMPTY; + /* fallback to TH_WIRE */ + } + } + } + + return theme_id; +} + +void DRW_shgroup_wire_overlay(DRWPass *wire_overlay, Object *ob) +{ +#if 1 + struct Batch *geom = DRW_cache_wire_overlay_get(ob); + GPUShader *sh = GPU_shader_get_builtin_shader(GPU_SHADER_EDGES_OVERLAY); + + DRWShadingGroup *grp = DRW_shgroup_create(sh, wire_overlay); + DRW_shgroup_uniform_vec2(grp, "viewportSize", DRW_viewport_size_get(), 1); + + DRW_shgroup_call_add(grp, geom, ob->obmat); +#else + static float col[4] = {0.0f, 0.0f, 0.0f, 1.0f}; + struct Batch *geom = DRW_cache_wire_overlay_get(ob); + GPUShader *sh = GPU_shader_get_builtin_shader(GPU_SHADER_3D_UNIFORM_COLOR); + + DRWShadingGroup *grp = DRW_shgroup_create(sh, wire_overlay); + DRW_shgroup_uniform_vec4(grp, "color", col, 1); + + DRW_shgroup_call_add(grp, geom, ob->obmat); +#endif +} + +void DRW_shgroup_wire_outline(DRWPass *wire_outline, Object *ob, + const bool do_front, const bool do_back, const bool do_outline) +{ + GPUShader *sh; + struct Batch *geom = DRW_cache_wire_outline_get(ob); + + /* Get color */ + /* TODO get the right color depending on ob state (Groups, overides etc..) */ + static float frontcol[4], backcol[4], color[4]; + UI_GetThemeColor4fv(TH_ACTIVE, color); + copy_v4_v4(frontcol, color); + copy_v4_v4(backcol, color); + backcol[3] = 0.333f; + frontcol[3] = 0.667f; + +#if 1 /* New wire */ + + bool is_perps = DRW_viewport_is_persp_get(); + static bool bTrue = true; + static bool bFalse = false; + + /* Note (TODO) : this requires cache to be discarded on ortho/perp switch + * It may be preferable (or not depending on performance implication) + * to introduce a shader uniform switch */ + if (is_perps) { + sh = GPU_shader_get_builtin_shader(GPU_SHADER_EDGES_FRONT_BACK_PERSP); + } + else { + sh = GPU_shader_get_builtin_shader(GPU_SHADER_EDGES_FRONT_BACK_ORTHO); + } + + if (do_front || do_back) { + bool *bFront = (do_front) ? &bTrue : &bFalse; + bool *bBack = (do_back) ? &bTrue : &bFalse; + + DRWShadingGroup *grp = DRW_shgroup_create(sh, wire_outline); + DRW_shgroup_state_set(grp, DRW_STATE_WIRE); + DRW_shgroup_uniform_vec4(grp, "frontColor", frontcol, 1); + DRW_shgroup_uniform_vec4(grp, "backColor", backcol, 1); + DRW_shgroup_uniform_bool(grp, "drawFront", bFront, 1); + DRW_shgroup_uniform_bool(grp, "drawBack", bBack, 1); + DRW_shgroup_uniform_bool(grp, "drawSilhouette", &bFalse, 1); + DRW_shgroup_call_add(grp, geom, ob->obmat); + } + + if (do_outline) { + DRWShadingGroup *grp = DRW_shgroup_create(sh, wire_outline); + DRW_shgroup_state_set(grp, DRW_STATE_WIRE_LARGE); + DRW_shgroup_uniform_vec4(grp, "silhouetteColor", color, 1); + DRW_shgroup_uniform_bool(grp, "drawFront", &bFalse, 1); + DRW_shgroup_uniform_bool(grp, "drawBack", &bFalse, 1); + DRW_shgroup_uniform_bool(grp, "drawSilhouette", &bTrue, 1); + + DRW_shgroup_call_add(grp, geom, ob->obmat); + } + +#else /* Old (flat) wire */ + + sh = GPU_shader_get_builtin_shader(GPU_SHADER_3D_UNIFORM_COLOR); + DRWShadingGroup *grp = DRW_shgroup_create(sh, wire_outline); + DRW_shgroup_state_set(grp, DRW_STATE_WIRE_LARGE); + DRW_shgroup_uniform_vec4(grp, "color", frontcol, 1); + + DRW_shgroup_call_add(grp, geom, ob->obmat); +#endif + +} + +/* ***************************** NON MESHES ********************** */ + +static void DRW_draw_lamp(Object *ob) +{ + struct Batch *center = DRW_cache_single_vert_get(); + struct Batch *lamp = DRW_cache_lamp_get(); + struct Batch *sunrays = DRW_cache_lamp_sunrays_get(); + Lamp *la = ob->data; + int theme_id = draw_object_wire_theme(ob); + + /* Don't draw the center if it's selected or active */ + if (theme_id == TH_GROUP) + DRW_shgroup_call_add(lamp_center_group, center, ob->obmat); + else if (theme_id == TH_LAMP) + DRW_shgroup_call_add(lamp_center, center, ob->obmat); + + /* First circle */ + if (theme_id == TH_ACTIVE) + DRW_shgroup_call_add(lamp_circle_active, lamp, ob->obmat); + else if (theme_id == TH_SELECT) + DRW_shgroup_call_add(lamp_circle_select, lamp, ob->obmat); + else if (theme_id == TH_GROUP) + DRW_shgroup_call_add(lamp_circle_group, lamp, ob->obmat); + else if (theme_id == TH_GROUP_ACTIVE) + DRW_shgroup_call_add(lamp_circle_group_active, lamp, ob->obmat); + else if (theme_id == TH_TRANSFORM) + DRW_shgroup_call_add(lamp_circle_transform, lamp, ob->obmat); + else + DRW_shgroup_call_add(lamp_circle, lamp, ob->obmat); + + /* draw dashed outer circle if shadow is on. remember some lamps can't have certain shadows! */ + if (la->type != LA_HEMI) { + if ((la->mode & LA_SHAD_RAY) || ((la->mode & LA_SHAD_BUF) && (la->type == LA_SPOT))) { + if (theme_id == TH_ACTIVE) + DRW_shgroup_call_add(lamp_circle_shadow_active, lamp, ob->obmat); + else if (theme_id == TH_SELECT) + DRW_shgroup_call_add(lamp_circle_shadow_select, lamp, ob->obmat); + else if (theme_id == TH_GROUP) + DRW_shgroup_call_add(lamp_circle_shadow_group, lamp, ob->obmat); + else if (theme_id == TH_GROUP_ACTIVE) + DRW_shgroup_call_add(lamp_circle_shadow_group_active, lamp, ob->obmat); + else if (theme_id == TH_TRANSFORM) + DRW_shgroup_call_add(lamp_circle_shadow_transform, lamp, ob->obmat); + else + DRW_shgroup_call_add(lamp_circle_shadow, lamp, ob->obmat); + } + } + + /* Sunrays */ + if (la->type == LA_SUN) { + if (theme_id == TH_ACTIVE) + DRW_shgroup_call_add(lamp_sunrays_active, sunrays, ob->obmat); + else if (theme_id == TH_SELECT) + DRW_shgroup_call_add(lamp_sunrays_select, sunrays, ob->obmat); + else if (theme_id == TH_GROUP) + DRW_shgroup_call_add(lamp_sunrays_group, sunrays, ob->obmat); + else if (theme_id == TH_GROUP_ACTIVE) + DRW_shgroup_call_add(lamp_sunrays_group_active, sunrays, ob->obmat); + else if (theme_id == TH_TRANSFORM) + DRW_shgroup_call_add(lamp_sunrays_transform, sunrays, ob->obmat); + else + DRW_shgroup_call_add(lamp_sunrays, sunrays, ob->obmat); + } + + /* Line and point going to the ground */ + DRW_shgroup_call_add(lamp_groundline, center, ob->obmat); + DRW_shgroup_call_add(lamp_groundpoint, center, ob->obmat); +} + +static void DRW_draw_empty(Object *ob) +{ + struct Batch *geom, *geom2; + DRWShadingGroup *grp, *grp2; + int theme_id = draw_object_wire_theme(ob); + + switch (ob->empty_drawtype) { + case OB_PLAINAXES: + if (theme_id == TH_ACTIVE) + grp = plain_axes_active; + else if (theme_id == TH_SELECT) + grp = plain_axes_select; + else if (theme_id == TH_GROUP_ACTIVE) + grp = plain_axes_group_active; + else if (theme_id == TH_GROUP) + grp = plain_axes_group; + else if (theme_id == TH_TRANSFORM) + grp = plain_axes_transform; + else + grp = plain_axes_wire; + + geom = DRW_cache_plain_axes_get(); + DRW_shgroup_call_add(grp, geom, ob->obmat); + break; + + case OB_SINGLE_ARROW: + if (theme_id == TH_ACTIVE) { + grp = single_arrow_active; + grp2 = single_arrow_line_active; + } + else if (theme_id == TH_SELECT) { + grp = single_arrow_select; + grp2 = single_arrow_line_select; + } + else if (theme_id == TH_GROUP_ACTIVE) { + grp = single_arrow_group_active; + grp2 = single_arrow_line_group_active; + } + else if (theme_id == TH_GROUP) { + grp = single_arrow_group; + grp2 = single_arrow_line_group; + } + else if (theme_id == TH_TRANSFORM) { + grp = single_arrow_transform; + grp2 = single_arrow_line_transform; + } + else { + grp = single_arrow_wire; + grp2 = single_arrow_line_wire; + } + + geom = DRW_cache_single_arrow_get(&geom2); + DRW_shgroup_call_add(grp, geom, ob->obmat); + DRW_shgroup_call_add(grp2, geom2, ob->obmat); + break; + + case OB_CUBE: + if (theme_id == TH_ACTIVE) + grp = cube_active; + else if (theme_id == TH_SELECT) + grp = cube_select; + else if (theme_id == TH_GROUP_ACTIVE) + grp = cube_group_active; + else if (theme_id == TH_GROUP) + grp = cube_group; + else if (theme_id == TH_TRANSFORM) + grp = cube_transform; + else + grp = cube_wire; + + geom = DRW_cache_cube_get(); + DRW_shgroup_call_add(grp, geom, ob->obmat); + break; + + case OB_CIRCLE: + if (theme_id == TH_ACTIVE) + grp = circle_active; + else if (theme_id == TH_SELECT) + grp = circle_select; + else if (theme_id == TH_GROUP_ACTIVE) + grp = circle_group_active; + else if (theme_id == TH_GROUP) + grp = circle_group; + else if (theme_id == TH_TRANSFORM) + grp = circle_transform; + else + grp = circle_wire; + + geom = DRW_cache_circle_get(); + DRW_shgroup_call_add(grp, geom, ob->obmat); + break; + + case OB_EMPTY_SPHERE: + if (theme_id == TH_ACTIVE) + grp = sphere_active; + else if (theme_id == TH_SELECT) + grp = sphere_select; + else if (theme_id == TH_GROUP_ACTIVE) + grp = sphere_group_active; + else if (theme_id == TH_GROUP) + grp = sphere_group; + else if (theme_id == TH_TRANSFORM) + grp = sphere_transform; + else + grp = sphere_wire; + + geom = DRW_cache_empty_sphere_get(); + DRW_shgroup_call_add(grp, geom, ob->obmat); + break; + + case OB_EMPTY_CONE: + if (theme_id == TH_ACTIVE) + grp = cone_active; + else if (theme_id == TH_SELECT) + grp = cone_select; + else if (theme_id == TH_GROUP_ACTIVE) + grp = cone_group_active; + else if (theme_id == TH_GROUP) + grp = cone_group; + else if (theme_id == TH_TRANSFORM) + grp = cone_transform; + else + grp = cone_wire; + + geom = DRW_cache_empty_cone_get(); + DRW_shgroup_call_add(grp, geom, ob->obmat); + break; + + case OB_ARROWS: + default: + if (theme_id == TH_ACTIVE) + grp = arrows_active; + else if (theme_id == TH_SELECT) + grp = arrows_select; + else if (theme_id == TH_GROUP_ACTIVE) + grp = arrows_group_active; + else if (theme_id == TH_GROUP) + grp = arrows_group; + else if (theme_id == TH_TRANSFORM) + grp = arrows_transform; + else + grp = arrows_wire; + + geom = DRW_cache_arrows_get(); + DRW_shgroup_call_add(grp, geom, ob->obmat); + /* TODO Missing axes names */ + break; + } +} + +void DRW_shgroup_non_meshes(DRWPass *UNUSED(non_meshes), Object *ob) +{ + switch (ob->type) { + case OB_LAMP: + DRW_draw_lamp(ob); + break; + case OB_CAMERA: + case OB_EMPTY: + DRW_draw_empty(ob); + default: + break; + } +} + +void DRW_shgroup_relationship_lines(DRWPass *UNUSED(non_meshes), Object *ob) +{ + if (ob->parent) { + struct Batch *geom = DRW_cache_single_vert_get(); + DRW_shgroup_call_add(relationship_lines, geom, ob->obmat); + DRW_shgroup_call_add(relationship_lines, geom, ob->parent->obmat); + } +} + +/* ***************************** COMMON **************************** */ + +void DRW_shgroup_object_center(DRWPass *UNUSED(ob_center), Object *ob) +{ + struct Batch *geom = DRW_cache_single_vert_get(); + + if ((ob->base_flag & BASE_SELECTED) != 0) { + DRW_shgroup_call_add(center_selected, geom, ob->obmat); + } + else if (0) { + DRW_shgroup_call_add(center_deselected, geom, ob->obmat); + } +} diff --git a/source/blender/draw/intern/draw_mode_pass.h b/source/blender/draw/intern/draw_mode_pass.h new file mode 100644 index 00000000000..d11213ec8a2 --- /dev/null +++ b/source/blender/draw/intern/draw_mode_pass.h @@ -0,0 +1,45 @@ +/* + * Copyright 2016, Blender Foundation. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Contributor(s): Blender Institute + * + */ + +/** \file draw_mode_pass.h + * \ingroup draw + */ + +#ifndef __DRAW_MODE_PASS_H__ +#define __DRAW_MODE_PASS_H__ + +#include "DRW_render.h" + +struct DRWPass; +struct Batch; +struct Object; + +void DRW_pass_setup_common(struct DRWPass **wire_overlay, struct DRWPass **wire_outline, struct DRWPass **non_meshes, struct DRWPass **ob_center); + +void DRW_shgroup_wire_overlay(struct DRWPass *wire_overlay, struct Object *ob); +void DRW_shgroup_wire_outline( + struct DRWPass *wire_outline, struct Object *ob, const bool do_front, const bool do_back, const bool do_outline); + +void DRW_shgroup_non_meshes(struct DRWPass *non_meshes, struct Object *ob); +void DRW_shgroup_relationship_lines(struct DRWPass *non_meshes, struct Object *ob); +void DRW_shgroup_object_center(struct DRWPass *ob_center, struct Object *ob); + +#endif /* __DRAW_MODE_PASS_H__ */
\ No newline at end of file diff --git a/source/blender/editors/space_view3d/space_view3d.c b/source/blender/editors/space_view3d/space_view3d.c index a3d4f6ef031..a48208b55f7 100644 --- a/source/blender/editors/space_view3d/space_view3d.c +++ b/source/blender/editors/space_view3d/space_view3d.c @@ -586,6 +586,7 @@ static void view3d_main_region_exit(wmWindowManager *wm, ARegion *ar) if (rv3d->viewport) { GPU_viewport_free(rv3d->viewport); + MEM_freeN(rv3d->viewport); rv3d->viewport = NULL; } } @@ -747,6 +748,7 @@ static void view3d_main_region_free(ARegion *ar) } if (rv3d->viewport) { GPU_viewport_free(rv3d->viewport); + MEM_freeN(rv3d->viewport); } MEM_freeN(rv3d); diff --git a/source/blender/editors/space_view3d/view3d_draw.c b/source/blender/editors/space_view3d/view3d_draw.c index b0faffcab3b..65966a67da8 100644 --- a/source/blender/editors/space_view3d/view3d_draw.c +++ b/source/blender/editors/space_view3d/view3d_draw.c @@ -2098,12 +2098,42 @@ static void view3d_draw_view(const bContext *C, ARegion *ar, DrawData *draw_data #endif } +static void view3d_render_pass(const bContext *C, ARegion *ar) +{ + Scene *scene = CTX_data_scene(C); + RenderEngineType *type = RE_engines_find(scene->r.engine); /* In the future we should get that from Layers */ + + if (type->flag & RE_USE_OGL_PIPELINE) { + type->view_draw(NULL, C); + } + else { + // Offline Render engine + } +} + +static void view3d_draw_view_new(const bContext *C, ARegion *ar, DrawData *UNUSED(draw_data)) +{ + + view3d_draw_setup_view(C, ar); + + /* Only 100% compliant on new spec goes bellow */ + view3d_render_pass(C, ar); + + view3d_draw_grid(C, ar); + view3d_draw_manipulator(C); + view3d_draw_region_info(C, ar); +} + + void view3d_main_region_draw(const bContext *C, ARegion *ar) { + Scene *scene = CTX_data_scene(C); View3D *v3d = CTX_wm_view3d(C); RegionView3D *rv3d = ar->regiondata; + /* TODO layers - In the future we should get RE from Layers */ + RenderEngineType *type = RE_engines_find(scene->r.engine); - if (IS_VIEWPORT_LEGACY(v3d)) { + if (IS_VIEWPORT_LEGACY(v3d) && ((type->flag & RE_USE_OGL_PIPELINE) == 0)) { view3d_main_region_draw_legacy(C, ar); return; } @@ -2111,12 +2141,20 @@ void view3d_main_region_draw(const bContext *C, ARegion *ar) if (!rv3d->viewport) rv3d->viewport = GPU_viewport_create(); + GPU_viewport_bind(rv3d->viewport, &ar->winrct); + /* TODO viewport - there is so much to be done, in fact a lot will need to happen in the space_view3d.c * before we even call the drawing routine, but let's move on for now (dfelinto) * but this is a provisory way to start seeing things in the viewport */ DrawData draw_data; view3d_draw_data_init(C, ar, rv3d, &draw_data); - view3d_draw_view(C, ar, &draw_data); + + if (type->flag & RE_USE_OGL_PIPELINE) + view3d_draw_view_new(C, ar, &draw_data); + else + view3d_draw_view(C, ar, &draw_data); + + GPU_viewport_unbind(rv3d->viewport); v3d->flag |= V3D_INVALID_BACKBUF; } diff --git a/source/blender/editors/space_view3d/view3d_intern.h b/source/blender/editors/space_view3d/view3d_intern.h index bed47354d89..f7346a378dc 100644 --- a/source/blender/editors/space_view3d/view3d_intern.h +++ b/source/blender/editors/space_view3d/view3d_intern.h @@ -38,6 +38,7 @@ struct ARegion; struct ARegionType; struct BoundBox; +struct Batch; struct DerivedMesh; struct Object; struct SmokeDomainSettings; diff --git a/source/blender/gpu/CMakeLists.txt b/source/blender/gpu/CMakeLists.txt index c5531b8542e..364e77123d9 100644 --- a/source/blender/gpu/CMakeLists.txt +++ b/source/blender/gpu/CMakeLists.txt @@ -31,6 +31,7 @@ set(INC ../imbuf ../makesdna ../makesrna + ../draw ../editors/include @@ -64,6 +65,7 @@ set(SRC intern/gpu_select.c intern/gpu_shader.c intern/gpu_texture.c + intern/gpu_uniformbuffer.c intern/gpu_viewport.c gawain/attrib_binding.c @@ -122,6 +124,7 @@ set(SRC GPU_select.h GPU_shader.h GPU_texture.h + GPU_uniformbuffer.h GPU_viewport.h intern/gpu_codegen.h @@ -145,10 +148,16 @@ data_to_c_simple(shaders/gpu_shader_image_depth_linear_frag.glsl SRC) data_to_c_simple(shaders/gpu_shader_image_interlace_frag.glsl SRC) data_to_c_simple(shaders/gpu_shader_3D_image_vert.glsl SRC) data_to_c_simple(shaders/gpu_shader_3D_vert.glsl SRC) +data_to_c_simple(shaders/gpu_shader_3D_instance_vert.glsl SRC) data_to_c_simple(shaders/gpu_shader_3D_flat_color_vert.glsl SRC) data_to_c_simple(shaders/gpu_shader_3D_smooth_color_vert.glsl SRC) data_to_c_simple(shaders/gpu_shader_3D_smooth_color_frag.glsl SRC) +data_to_c_simple(shaders/gpu_shader_3D_groundpoint_vert.glsl SRC) +data_to_c_simple(shaders/gpu_shader_3D_groundline_vert.glsl SRC) +data_to_c_simple(shaders/gpu_shader_3D_groundline_geom.glsl SRC) +data_to_c_simple(shaders/gpu_shader_3D_lamp_vert.glsl SRC) + data_to_c_simple(shaders/gpu_shader_point_uniform_color_frag.glsl SRC) data_to_c_simple(shaders/gpu_shader_point_uniform_color_smooth_frag.glsl SRC) data_to_c_simple(shaders/gpu_shader_point_uniform_color_outline_smooth_frag.glsl SRC) diff --git a/source/blender/gpu/GPU_extensions.h b/source/blender/gpu/GPU_extensions.h index 31ad8243c4b..ff00a83d00b 100644 --- a/source/blender/gpu/GPU_extensions.h +++ b/source/blender/gpu/GPU_extensions.h @@ -53,6 +53,8 @@ int GPU_max_textures(void); float GPU_max_texture_anisotropy(void); int GPU_max_color_texture_samples(void); int GPU_max_cube_map_size(void); +int GPU_max_ubo_binds(void); +int GPU_max_ubo_size(void); int GPU_color_depth(void); void GPU_get_dfdy_factors(float fac[2]); diff --git a/source/blender/gpu/GPU_framebuffer.h b/source/blender/gpu/GPU_framebuffer.h index 989b874fd38..9611a6f0577 100644 --- a/source/blender/gpu/GPU_framebuffer.h +++ b/source/blender/gpu/GPU_framebuffer.h @@ -52,6 +52,7 @@ void GPU_texture_bind_as_framebuffer(struct GPUTexture *tex); GPUFrameBuffer *GPU_framebuffer_create(void); bool GPU_framebuffer_texture_attach(GPUFrameBuffer *fb, struct GPUTexture *tex, int slot); void GPU_framebuffer_texture_detach(struct GPUTexture *tex); +void GPU_framebuffer_bind(GPUFrameBuffer *fb); void GPU_framebuffer_slots_bind(GPUFrameBuffer *fb, int slot); void GPU_framebuffer_texture_unbind(GPUFrameBuffer *fb, struct GPUTexture *tex); void GPU_framebuffer_free(GPUFrameBuffer *fb); diff --git a/source/blender/gpu/GPU_shader.h b/source/blender/gpu/GPU_shader.h index 394e751ed9b..b36954dd010 100644 --- a/source/blender/gpu/GPU_shader.h +++ b/source/blender/gpu/GPU_shader.h @@ -38,6 +38,7 @@ extern "C" { typedef struct GPUShader GPUShader; struct GPUTexture; +struct GPUUniformBuffer; /* GPU Shader * - only for fragment shaders now @@ -69,14 +70,17 @@ void GPU_shader_free(GPUShader *shader); void GPU_shader_bind(GPUShader *shader); void GPU_shader_unbind(void); +int GPU_shader_get_program(GPUShader *shader); void *GPU_shader_get_interface(GPUShader *shader); void GPU_shader_set_interface(GPUShader *shader, void *interface); int GPU_shader_get_uniform(GPUShader *shader, const char *name); +int GPU_shader_get_uniform_block(GPUShader *shader, const char *name); void GPU_shader_uniform_vector(GPUShader *shader, int location, int length, int arraysize, const float *value); void GPU_shader_uniform_vector_int(GPUShader *shader, int location, int length, int arraysize, const int *value); +void GPU_shader_uniform_buffer(GPUShader *shader, int location, struct GPUUniformBuffer *ubo); void GPU_shader_uniform_texture(GPUShader *shader, int location, struct GPUTexture *tex); void GPU_shader_uniform_int(GPUShader *shader, int location, int value); void GPU_shader_geometry_stage_primitive_io(GPUShader *shader, int input, int output, int number); @@ -104,6 +108,7 @@ typedef enum GPUBuiltinShader { GPU_SHADER_2D_IMAGE_COLOR, /* for simple 3D drawing */ GPU_SHADER_3D_UNIFORM_COLOR, + GPU_SHADER_3D_UNIFORM_COLOR_INSTANCE, GPU_SHADER_3D_FLAT_COLOR, GPU_SHADER_3D_SMOOTH_COLOR, GPU_SHADER_3D_DEPTH_ONLY, @@ -126,6 +131,10 @@ typedef enum GPUBuiltinShader { GPU_SHADER_3D_POINT_UNIFORM_SIZE_UNIFORM_COLOR_OUTLINE_SMOOTH, GPU_SHADER_3D_POINT_VARYING_SIZE_UNIFORM_COLOR, GPU_SHADER_3D_POINT_VARYING_SIZE_VARYING_COLOR, + /* lamp drawing */ + GPU_SHADER_3D_GROUNDPOINT, + GPU_SHADER_3D_GROUNDLINE, + GPU_SHADER_3D_LAMP_COMMON, GPU_NUM_BUILTIN_SHADERS /* (not an actual shader) */ } GPUBuiltinShader; diff --git a/source/blender/gpu/GPU_uniformbuffer.h b/source/blender/gpu/GPU_uniformbuffer.h new file mode 100644 index 00000000000..bcb6e1077b7 --- /dev/null +++ b/source/blender/gpu/GPU_uniformbuffer.h @@ -0,0 +1,44 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2005 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): Clement Foucault. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file GPU_uniformbuffer.h + * \ingroup gpu + */ + +typedef struct GPUUniformBuffer GPUUniformBuffer; + +GPUUniformBuffer *GPU_uniformbuffer_create(int size, const void *data, char err_out[256]); +void GPU_uniformbuffer_free(GPUUniformBuffer *ubo); + +void GPU_uniformbuffer_update(GPUUniformBuffer *ubo, const void *data); + +void GPU_uniformbuffer_bind(GPUUniformBuffer *ubo, int number); +#if 0 +void GPU_uniformbuffer_unbind(GPUUniformBuffer *ubo); +#endif + +int GPU_uniformbuffer_bindpoint(GPUUniformBuffer *ubo); diff --git a/source/blender/gpu/GPU_viewport.h b/source/blender/gpu/GPU_viewport.h index fce509377ab..e44657a4647 100644 --- a/source/blender/gpu/GPU_viewport.h +++ b/source/blender/gpu/GPU_viewport.h @@ -34,12 +34,52 @@ #include <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_extensions.c b/source/blender/gpu/intern/gpu_extensions.c index e8fd4b8b8b1..d7ed65e853e 100644 --- a/source/blender/gpu/intern/gpu_extensions.c +++ b/source/blender/gpu/intern/gpu_extensions.c @@ -69,6 +69,8 @@ static struct GPUGlobal { GLint maxtexsize; GLint maxcubemapsize; GLint maxtextures; + GLint maxubosize; + GLint maxubobinds; bool extdisabled; int colordepth; int samples_color_texture_max; @@ -121,6 +123,16 @@ int GPU_max_cube_map_size(void) return GG.maxcubemapsize; } +int GPU_max_ubo_binds(void) +{ + return GG.maxubobinds; +} + +int GPU_max_ubo_size(void) +{ + return GG.maxubosize; +} + void GPU_get_dfdy_factors(float fac[2]) { copy_v2_v2(fac, GG.dfdyfactors); @@ -154,6 +166,9 @@ void gpu_extensions_init(void) else GG.max_anisotropy = 1.0f; + glGetIntegerv(GL_MAX_UNIFORM_BUFFER_BINDINGS, &GG.maxubobinds); + glGetIntegerv(GL_MAX_UNIFORM_BLOCK_SIZE, &GG.maxubosize); + GLint r, g, b; glGetIntegerv(GL_RED_BITS, &r); glGetIntegerv(GL_GREEN_BITS, &g); diff --git a/source/blender/gpu/intern/gpu_framebuffer.c b/source/blender/gpu/intern/gpu_framebuffer.c index 2ef8018e5e9..1efc451f4a8 100644 --- a/source/blender/gpu/intern/gpu_framebuffer.c +++ b/source/blender/gpu/intern/gpu_framebuffer.c @@ -260,6 +260,43 @@ void GPU_framebuffer_slots_bind(GPUFrameBuffer *fb, int slot) glPushMatrix(); } +void GPU_framebuffer_bind(GPUFrameBuffer *fb) +{ + int numslots = 0, i; + GLenum attachments[4]; + GLenum readattachement = 0; + GPUTexture *tex; + + for (i = 0; i < 4; i++) { + if (fb->colortex[i]) { + attachments[numslots] = GL_COLOR_ATTACHMENT0 + i; + tex = fb->colortex[i]; + + if (!readattachement) + readattachement = GL_COLOR_ATTACHMENT0 + i; + + numslots++; + } + } + + /* bind framebuffer */ + glBindFramebuffer(GL_FRAMEBUFFER, fb->object); + + if (numslots == 0) { + glDrawBuffer(GL_NONE); + glReadBuffer(GL_NONE); + tex = fb->depthtex; + } + else { + /* last bound prevails here, better allow explicit control here too */ + glDrawBuffers(numslots, attachments); + glReadBuffer(readattachement); + } + + glViewport(0, 0, GPU_texture_width(tex), GPU_texture_height(tex)); + GG.currentfb = fb->object; +} + void GPU_framebuffer_texture_unbind(GPUFrameBuffer *UNUSED(fb), GPUTexture *UNUSED(tex)) { @@ -283,7 +320,6 @@ void GPU_framebuffer_bind_no_save(GPUFrameBuffer *fb, int slot) /* push matrices and set default viewport and matrix */ glViewport(0, 0, GPU_texture_width(fb->colortex[slot]), GPU_texture_height(fb->colortex[slot])); GG.currentfb = fb->object; - GG.currentfb = fb->object; } bool GPU_framebuffer_bound(GPUFrameBuffer *fb) diff --git a/source/blender/gpu/intern/gpu_shader.c b/source/blender/gpu/intern/gpu_shader.c index b81c19d5c70..0d6fd5f7b99 100644 --- a/source/blender/gpu/intern/gpu_shader.c +++ b/source/blender/gpu/intern/gpu_shader.c @@ -37,6 +37,7 @@ #include "GPU_debug.h" #include "GPU_extensions.h" #include "GPU_shader.h" +#include "GPU_uniformbuffer.h" #include "GPU_texture.h" #include "gpu_shader_private.h" @@ -64,10 +65,16 @@ extern char datatoc_gpu_shader_image_modulate_alpha_frag_glsl[]; extern char datatoc_gpu_shader_image_rect_modulate_alpha_frag_glsl[]; extern char datatoc_gpu_shader_image_depth_linear_frag_glsl[]; extern char datatoc_gpu_shader_3D_vert_glsl[]; +extern char datatoc_gpu_shader_3D_instance_vert_glsl[]; extern char datatoc_gpu_shader_3D_flat_color_vert_glsl[]; extern char datatoc_gpu_shader_3D_smooth_color_vert_glsl[]; extern char datatoc_gpu_shader_3D_smooth_color_frag_glsl[]; +extern char datatoc_gpu_shader_3D_groundpoint_vert_glsl[]; +extern char datatoc_gpu_shader_3D_groundline_vert_glsl[]; +extern char datatoc_gpu_shader_3D_groundline_geom_glsl[]; +extern char datatoc_gpu_shader_3D_lamp_vert_glsl[]; + extern char datatoc_gpu_shader_point_uniform_color_frag_glsl[]; extern char datatoc_gpu_shader_point_uniform_color_smooth_frag_glsl[]; extern char datatoc_gpu_shader_point_uniform_color_outline_smooth_frag_glsl[]; @@ -511,11 +518,24 @@ int GPU_shader_get_uniform(GPUShader *shader, const char *name) return glGetUniformLocation(shader->program, name); } +int GPU_shader_get_uniform_block(GPUShader *shader, const char *name) +{ + BLI_assert(shader && shader->program); + + return glGetUniformBlockIndex(shader->program, name); +} + void *GPU_shader_get_interface(GPUShader *shader) { return shader->uniform_interface; } +/* Clement : Temp */ +int GPU_shader_get_program(GPUShader *shader) +{ + return (int)shader->program; +} + void GPU_shader_set_interface(GPUShader *shader, void *interface) { shader->uniform_interface = interface; @@ -563,6 +583,17 @@ void GPU_shader_geometry_stage_primitive_io(GPUShader *shader, int input, int ou } } +void GPU_shader_uniform_buffer(GPUShader *shader, int location, GPUUniformBuffer *ubo) +{ + int bindpoint = GPU_uniformbuffer_bindpoint(ubo); + + if (location == -1) { + return; + } + + glUniformBlockBinding(shader->program, location, bindpoint); +} + void GPU_shader_uniform_texture(GPUShader *UNUSED(shader), int location, GPUTexture *tex) { int number = GPU_texture_bound_number(tex); @@ -645,12 +676,21 @@ GPUShader *GPU_shader_get_builtin_shader(GPUBuiltinShader shader) [GPU_SHADER_2D_IMAGE_COLOR] = { datatoc_gpu_shader_2D_image_vert_glsl, datatoc_gpu_shader_image_color_frag_glsl }, [GPU_SHADER_3D_UNIFORM_COLOR] = { datatoc_gpu_shader_3D_vert_glsl, datatoc_gpu_shader_uniform_color_frag_glsl }, + [GPU_SHADER_3D_UNIFORM_COLOR_INSTANCE] = { datatoc_gpu_shader_3D_instance_vert_glsl, datatoc_gpu_shader_uniform_color_frag_glsl }, [GPU_SHADER_3D_FLAT_COLOR] = { datatoc_gpu_shader_3D_flat_color_vert_glsl, datatoc_gpu_shader_flat_color_frag_glsl }, [GPU_SHADER_3D_SMOOTH_COLOR] = { datatoc_gpu_shader_3D_smooth_color_vert_glsl, datatoc_gpu_shader_3D_smooth_color_frag_glsl }, [GPU_SHADER_3D_DEPTH_ONLY] = { datatoc_gpu_shader_3D_vert_glsl, datatoc_gpu_shader_depth_only_frag_glsl }, + [GPU_SHADER_3D_GROUNDPOINT] = { datatoc_gpu_shader_3D_groundpoint_vert_glsl, datatoc_gpu_shader_point_uniform_color_frag_glsl }, + [GPU_SHADER_3D_GROUNDLINE] = { datatoc_gpu_shader_3D_groundline_vert_glsl, + datatoc_gpu_shader_uniform_color_frag_glsl, + datatoc_gpu_shader_3D_groundline_geom_glsl }, + + [GPU_SHADER_3D_LAMP_COMMON] = { datatoc_gpu_shader_3D_lamp_vert_glsl, + datatoc_gpu_shader_uniform_color_frag_glsl}, + [GPU_SHADER_2D_POINT_FIXED_SIZE_UNIFORM_COLOR] = { datatoc_gpu_shader_2D_vert_glsl, datatoc_gpu_shader_point_uniform_color_frag_glsl }, [GPU_SHADER_2D_POINT_VARYING_SIZE_VARYING_COLOR] = diff --git a/source/blender/gpu/intern/gpu_texture.c b/source/blender/gpu/intern/gpu_texture.c index 6fb658e20eb..3513250993e 100644 --- a/source/blender/gpu/intern/gpu_texture.c +++ b/source/blender/gpu/intern/gpu_texture.c @@ -91,6 +91,7 @@ static GLenum GPU_texture_get_format(int components, GPUTextureFormat data_type, /* Formats texture & renderbuffer */ case GPU_RGBA16F: return GL_RGBA16F; case GPU_RG32F: return GL_RG32F; + case GPU_RG16F: return GL_RG16F; case GPU_RGBA8: return GL_RGBA8; case GPU_R8: return GL_R8; /* Special formats texture & renderbuffer */ diff --git a/source/blender/gpu/intern/gpu_uniformbuffer.c b/source/blender/gpu/intern/gpu_uniformbuffer.c new file mode 100644 index 00000000000..76aa1a8226f --- /dev/null +++ b/source/blender/gpu/intern/gpu_uniformbuffer.c @@ -0,0 +1,105 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2005 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): Clement Foucault. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file gpu_uniformbuffer.c + * \ingroup gpu + */ + +#include "MEM_guardedalloc.h" + +#include "BLI_blenlib.h" + +#include "GPU_extensions.h" +#include "GPU_glew.h" +#include "GPU_uniformbuffer.h" + +struct GPUUniformBuffer { + int size; /* in bytes */ + GLuint bindcode; /* opengl identifier for UBO */ + int bindpoint; /* current binding point */ +}; + +GPUUniformBuffer *GPU_uniformbuffer_create(int size, const void *data, char err_out[256]) +{ + GPUUniformBuffer *ubo = MEM_callocN(sizeof(GPUUniformBuffer), "GPUUniformBuffer"); + ubo->size = size; + + /* Generate Buffer object */ + glGenBuffers(1, &ubo->bindcode); + + if (!ubo->bindcode) { + if (err_out) + BLI_snprintf(err_out, 256, "GPUUniformBuffer: UBO create failed"); + GPU_uniformbuffer_free(ubo); + return NULL; + } + + if (ubo->size > GPU_max_ubo_size()) { + if (err_out) + BLI_snprintf(err_out, 256, "GPUUniformBuffer: UBO too big"); + GPU_uniformbuffer_free(ubo); + return NULL; + } + + glBindBuffer(GL_UNIFORM_BUFFER, ubo->bindcode); + glBufferData(GL_UNIFORM_BUFFER, ubo->size, data, GL_DYNAMIC_DRAW); + glBindBuffer(GL_UNIFORM_BUFFER, 0); + + return ubo; +} + +void GPU_uniformbuffer_free(GPUUniformBuffer *ubo) +{ + glDeleteBuffers(1, &ubo->bindcode); + MEM_freeN(ubo); +} + +void GPU_uniformbuffer_update(GPUUniformBuffer *ubo, const void *data) +{ + glBindBuffer(GL_UNIFORM_BUFFER, ubo->bindcode); + glBufferSubData(GL_UNIFORM_BUFFER, 0, ubo->size, data); + glBindBuffer(GL_UNIFORM_BUFFER, 0); +} + +void GPU_uniformbuffer_bind(GPUUniformBuffer *ubo, int number) +{ + if (number >= GPU_max_ubo_binds()) { + fprintf(stderr, "Not enough UBO slots.\n"); + return; + } + + if (ubo->bindcode != 0) { + glBindBufferBase(GL_UNIFORM_BUFFER, number, ubo->bindcode); + } + + ubo->bindpoint = number; +} + +int GPU_uniformbuffer_bindpoint(GPUUniformBuffer *ubo) +{ + return ubo->bindpoint; +}
\ No newline at end of file diff --git a/source/blender/gpu/intern/gpu_viewport.c b/source/blender/gpu/intern/gpu_viewport.c index a4fb3494639..b1964857ab1 100644 --- a/source/blender/gpu/intern/gpu_viewport.c +++ b/source/blender/gpu/intern/gpu_viewport.c @@ -31,10 +31,19 @@ * System that manages viewport drawing. */ +#include <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,19 +52,200 @@ struct GPUViewport { /* debug */ GPUTexture *debug_depth; - int debug_width, debug_height; + int size[2]; + + /* Viewport Buffer Storage */ + /* TODO indentify to what engine conf are theses buffers */ + DefaultFramebufferList *fbl; + DefaultTextureList *txl; + DefaultPassList *psl; }; +static void GPU_viewport_buffers_free(GPUViewport *viewport); +static void GPU_viewport_passes_free(GPUViewport *viewport); + GPUViewport *GPU_viewport_create(void) { GPUViewport *viewport = MEM_callocN(sizeof(GPUViewport), "GPUViewport"); + viewport->fbl = MEM_callocN(sizeof(FramebufferList), "FramebufferList"); + viewport->txl = MEM_callocN(sizeof(TextureList), "TextureList"); + viewport->psl = MEM_callocN(sizeof(PassList), "PassList"); + viewport->size[0] = viewport->size[1] = -1; + return viewport; } +void GPU_viewport_get_engine_data(GPUViewport *viewport, void **fbs, void **txs, void **pss) +{ + *fbs = viewport->fbl; + *txs = viewport->txl; + *pss = viewport->psl; +} + +void GPU_viewport_bind(GPUViewport *viewport, const rcti *rect) +{ + /* add one pixel because of scissor test */ + int rect_w = BLI_rcti_size_x(rect) + 1, rect_h = BLI_rcti_size_y(rect) + 1; + +#ifndef WITH_VIEWPORT_CACHE_TEST + /* TODO for testing only, we need proper cache invalidation */ + GPU_viewport_passes_free(viewport); +#endif + + if (viewport->fbl->default_fb) { + if (rect_w != viewport->size[0] || rect_h != viewport->size[1]) { + GPU_viewport_buffers_free(viewport); + } + } + + if (!viewport->fbl->default_fb) { + bool ok = true; + viewport->size[0] = rect_w; + viewport->size[1] = rect_h; + + viewport->fbl->default_fb = GPU_framebuffer_create(); + if (!viewport->fbl->default_fb) { + ok = false; + goto cleanup; + } + + /* Color */ + /* No multi samples for now */ + viewport->txl->color = GPU_texture_create_2D(rect_w, rect_h, NULL, NULL); + if (!viewport->txl->color) { + ok = false; + goto cleanup; + } + + if (!GPU_framebuffer_texture_attach(viewport->fbl->default_fb, viewport->txl->color, 0)) { + ok = false; + goto cleanup; + } + + /* Depth */ + viewport->txl->depth = GPU_texture_create_depth(rect_w, rect_h, NULL); + if (!viewport->txl->depth) { + ok = false; + goto cleanup; + } + else if (!GPU_framebuffer_texture_attach(viewport->fbl->default_fb, viewport->txl->depth, 0)) { + ok = false; + goto cleanup; + } + else if (!GPU_framebuffer_check_valid(viewport->fbl->default_fb, NULL)) { + ok = false; + goto cleanup; + } + +cleanup: + if (!ok) { + GPU_viewport_free(viewport); + MEM_freeN(viewport); + return; + } + + GPU_framebuffer_restore(); + } + + GPU_framebuffer_slots_bind(viewport->fbl->default_fb, 0); +} + +static void draw_ofs_to_screen(GPUViewport *viewport) +{ + GPUTexture *color = viewport->txl->color; + + const float w = (float)GPU_texture_width(color); + const float h = (float)GPU_texture_height(color); + + VertexFormat *format = immVertexFormat(); + unsigned texcoord = add_attrib(format, "texCoord", GL_FLOAT, 2, KEEP_FLOAT); + unsigned pos = add_attrib(format, "pos", GL_FLOAT, 2, KEEP_FLOAT); + + immBindBuiltinProgram(GPU_SHADER_3D_IMAGE_MODULATE_ALPHA); + + GPU_texture_bind(color, 0); + + immUniform1i("image", 0); /* default GL_TEXTURE0 unit */ + + immBegin(GL_QUADS, 4); + + immAttrib2f(texcoord, 0.0f, 0.0f); + immVertex2f(pos, 0.0f, 0.0f); + + immAttrib2f(texcoord, 1.0f, 0.0f); + immVertex2f(pos, w, 0.0f); + + immAttrib2f(texcoord, 1.0f, 1.0f); + immVertex2f(pos, w, h); + + immAttrib2f(texcoord, 0.0f, 1.0f); + immVertex2f(pos, 0.0f, h); + + immEnd(); + + GPU_texture_unbind(color); + + immUnbindProgram(); +} + +void GPU_viewport_unbind(GPUViewport *viewport) +{ + if (viewport->fbl->default_fb) { + GPU_framebuffer_texture_unbind(NULL, NULL); + GPU_framebuffer_restore(); + + glEnable(GL_SCISSOR_TEST); + + /* This might be bandwidth limiting */ + draw_ofs_to_screen(viewport); + } +} + +static void GPU_viewport_buffers_free(GPUViewport *viewport) +{ + FramebufferList *fbl = (FramebufferList *)viewport->fbl; + TextureList *txl = (TextureList *)viewport->txl; + int i; + for (i = MAX_BUFFERS - 1; i > -1; --i) { + GPUFrameBuffer *fb = fbl->framebuffers[i]; + if (fb) { + GPU_framebuffer_free(fb); + fbl->framebuffers[i] = NULL; + } + } + for (i = MAX_TEXTURES - 1; i > -1; --i) { + GPUTexture *tex = txl->textures[i]; + if (tex) { + GPU_texture_free(tex); + txl->textures[i] = NULL; + } + } +} + +static void GPU_viewport_passes_free(GPUViewport *viewport) +{ + PassList *psl = (PassList *)viewport->psl; + int i; + + for (i = MAX_PASSES - 1; i > -1; --i) { + struct DRWPass *pass = psl->passes[i]; + if (pass) { + DRW_pass_free(pass); + MEM_freeN(pass); + psl->passes[i] = NULL; + } + } +} + void GPU_viewport_free(GPUViewport *viewport) { GPU_viewport_debug_depth_free(viewport); - MEM_freeN(viewport); + GPU_viewport_buffers_free(viewport); + GPU_viewport_passes_free(viewport); + + MEM_freeN(viewport->fbl); + MEM_freeN(viewport->txl); + MEM_freeN(viewport->psl); } /****************** debug ********************/ diff --git a/source/blender/gpu/shaders/gpu_shader_3D_groundline_geom.glsl b/source/blender/gpu/shaders/gpu_shader_3D_groundline_geom.glsl new file mode 100644 index 00000000000..f16fa21b342 --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_3D_groundline_geom.glsl @@ -0,0 +1,16 @@ + +/* Make to be used with dynamic batching so no Model Matrix needed */ +uniform mat4 ViewProjectionMatrix; + +layout(points) in; +layout(line_strip, max_vertices = 2) out; + +void main() +{ + vec3 vert = gl_in[0].gl_Position.xyz; + gl_Position = ViewProjectionMatrix * vec4(vert.xyz, 1.0); + EmitVertex(); + gl_Position = ViewProjectionMatrix * vec4(vert.xy, 0.0, 1.0); + EmitVertex(); + EndPrimitive(); +} diff --git a/source/blender/gpu/shaders/gpu_shader_3D_groundline_vert.glsl b/source/blender/gpu/shaders/gpu_shader_3D_groundline_vert.glsl new file mode 100644 index 00000000000..60793bf56b6 --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_3D_groundline_vert.glsl @@ -0,0 +1,8 @@ + +/* Does Nothing */ +in vec3 pos; + +void main() +{ + gl_Position = vec4(pos, 1.0); +} diff --git a/source/blender/gpu/shaders/gpu_shader_3D_groundpoint_vert.glsl b/source/blender/gpu/shaders/gpu_shader_3D_groundpoint_vert.glsl new file mode 100644 index 00000000000..be6b6014a19 --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_3D_groundpoint_vert.glsl @@ -0,0 +1,11 @@ + +/* Make to be used with dynamic batching so no Model Matrix needed */ +uniform mat4 ViewProjectionMatrix; + +in vec3 pos; + +void main() +{ + gl_Position = ViewProjectionMatrix * vec4(pos.xy, 0.0, 1.0); + gl_PointSize = 2.0; +} diff --git a/source/blender/gpu/shaders/gpu_shader_3D_instance_vert.glsl b/source/blender/gpu/shaders/gpu_shader_3D_instance_vert.glsl new file mode 100644 index 00000000000..7eb321f2996 --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_3D_instance_vert.glsl @@ -0,0 +1,10 @@ + +uniform mat4 ViewProjectionMatrix; + +in vec3 pos; +in mat4 InstanceModelMatrix; + +void main() +{ + gl_Position = ViewProjectionMatrix * InstanceModelMatrix * vec4(pos, 1.0); +} diff --git a/source/blender/gpu/shaders/gpu_shader_3D_lamp_vert.glsl b/source/blender/gpu/shaders/gpu_shader_3D_lamp_vert.glsl new file mode 100644 index 00000000000..dbc683ef42b --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_3D_lamp_vert.glsl @@ -0,0 +1,24 @@ + +uniform mat4 ViewProjectionMatrix; +uniform vec3 screen_vecs[2]; +uniform float size; +uniform float pixel_size; + +in vec2 pos; +in mat4 InstanceModelMatrix; + +#define lamp_pos InstanceModelMatrix[3].xyz + +float mul_project_m4_v3_zfac(in vec3 co) +{ + return (ViewProjectionMatrix[0][3] * co.x) + + (ViewProjectionMatrix[1][3] * co.y) + + (ViewProjectionMatrix[2][3] * co.z) + ViewProjectionMatrix[3][3]; +} + +void main() +{ + float pix_size = mul_project_m4_v3_zfac(lamp_pos) * pixel_size; + vec3 screen_pos = screen_vecs[0].xyz * pos.x + screen_vecs[1].xyz * pos.y; + gl_Position = ViewProjectionMatrix * vec4(lamp_pos + screen_pos * size * pix_size, 1.0); +} diff --git a/source/blender/makesdna/DNA_layer_types.h b/source/blender/makesdna/DNA_layer_types.h index 6f6c6d7d145..3a4293c8ad8 100644 --- a/source/blender/makesdna/DNA_layer_types.h +++ b/source/blender/makesdna/DNA_layer_types.h @@ -59,6 +59,7 @@ typedef struct LayerCollection { ListBase object_bases; /* (ObjectBase *)LinkData->data - synced with collection->objects and collection->filter_objects */ ListBase overrides; ListBase layer_collections; /* synced with collection->collections */ + ListBase engine_settings; /* CollectionEngineSettings */ } LayerCollection; typedef struct SceneLayer { @@ -102,8 +103,54 @@ enum { /* SceneLayer->flag */ enum { SCENE_LAYER_RENDER = (1 << 0), + SCENE_LAYER_ENGINE_DIRTY = (1 << 1), }; + +/* *************************************************************** */ +/* Engine Settings */ + +typedef struct CollectionEngineProperty { + struct CollectionEngineProperty *next, *prev; + char name[64]; /* MAX_NAME */ + short type; + short pad; + char flag; + char pad2[3]; +} CollectionEngineProperty; + +typedef struct CollectionEnginePropertyInt { + struct CollectionEngineProperty data; + int value; + int pad; +} CollectionEnginePropertyInt; + +typedef struct CollectionEnginePropertyFloat { + struct CollectionEngineProperty data; + float value; + float pad; +} CollectionEnginePropertyFloat; + +typedef struct CollectionEngineSettings { + struct CollectionEngineSettings *next, *prev; + char name[32]; /* engine name - MAX_NAME */ + ListBase properties; /* CollectionProperty */ +} CollectionEngineSettings; + +/* CollectionEngineProperty->flag */ +enum { + COLLECTION_PROP_USE = (1 << 0), +}; + +/* CollectionEntineProperty.type */ +typedef enum CollectionEnginePropertyType { + COLLECTION_PROP_TYPE_FLOAT = 0, + COLLECTION_PROP_TYPE_INT = 1, +} CollectionEnginePropertyType; + +/* *************************************************************** */ + + #ifdef __cplusplus } #endif diff --git a/source/blender/makesdna/DNA_material_types.h b/source/blender/makesdna/DNA_material_types.h index 0c500e366a7..bd8278f897a 100644 --- a/source/blender/makesdna/DNA_material_types.h +++ b/source/blender/makesdna/DNA_material_types.h @@ -90,6 +90,43 @@ typedef struct TexPaintSlot { int pad; } TexPaintSlot; +/* Material Engine Settings */ +typedef struct MaterialEngineSettings { + struct MaterialEngineSettings *next, *prev; + char name[32]; /* engine name - MAX_NAME */ + void *data; +} MaterialEngineSettings; + +/* Clay engine */ + +/* MaterialRuntimeClay.flag */ +#define CLAY_OUTDATED 1 + +typedef struct MaterialEngineSettingsClay { + short type; + short matcap_icon; /* Icon ID */ + + float matcap_rot; + float matcap_hue; + float matcap_sat; + float matcap_val; + + float ssao_distance; + float ssao_attenuation; + float ssao_factor_cavity; + float ssao_factor_edge; + + /* Runtime */ + short flag; + short pad; + int ubo_index; +} MaterialEngineSettingsClay; + +/* MaterialEngineSettingsClay.type */ +#define CLAY_MATCAP_NONE 0 +#define CLAY_MATCAP_SIMPLE 1 +#define CLAY_MATCAP_COMPLETE 2 + typedef struct Material { ID id; struct AnimData *adt; /* animation data (must be immediately after id for utilities to use it) */ @@ -203,6 +240,9 @@ typedef struct Material { struct TexPaintSlot *texpaintslot; /* cached slot for painting. Make sure to recalculate before use * with refresh_texpaint_image_cache */ + /* Engine Settings */ + ListBase engines_settings; /* MaterialEngineSettings */ + ListBase gpumaterial; /* runtime */ } Material; diff --git a/source/blender/makesdna/DNA_object_types.h b/source/blender/makesdna/DNA_object_types.h index 60aaa4ace20..080ade57c0d 100644 --- a/source/blender/makesdna/DNA_object_types.h +++ b/source/blender/makesdna/DNA_object_types.h @@ -46,6 +46,7 @@ struct Object; struct AnimData; struct Ipo; struct BoundBox; +struct CollectionSettings; struct Path; struct Material; struct PartDeflect; @@ -302,6 +303,8 @@ typedef struct Object { LodLevel *currentlod; struct PreviewImage *preview; + + struct ListBase *collection_settings; /* used by depsgraph, flushed from collection-tree */ } Object; /* Warning, this is not used anymore because hooks are now modifiers */ diff --git a/source/blender/makesdna/DNA_scene_types.h b/source/blender/makesdna/DNA_scene_types.h index ba5e50ec441..6e56824b176 100644 --- a/source/blender/makesdna/DNA_scene_types.h +++ b/source/blender/makesdna/DNA_scene_types.h @@ -48,6 +48,7 @@ extern "C" { #include "DNA_freestyle_types.h" #include "DNA_gpu_types.h" #include "DNA_layer_types.h" +#include "DNA_material_types.h" #include "DNA_userdef_types.h" struct CurveMapping; @@ -539,6 +540,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 { @@ -1707,6 +1752,9 @@ typedef struct Scene { struct SceneCollection *collection; int active_layer; int pad4; + + ListBase engines_settings; /* RenderEngineSettings */ + int pad5[2]; } Scene; /* **************** RENDERDATA ********************* */ @@ -1895,6 +1943,7 @@ enum { /* scene->r.engine (scene.c) */ extern const char *RE_engine_id_BLENDER_RENDER; extern const char *RE_engine_id_BLENDER_GAME; +extern const char *RE_engine_id_BLENDER_CLAY; extern const char *RE_engine_id_CYCLES; /* **************** SCENE ********************* */ diff --git a/source/blender/makesrna/RNA_access.h b/source/blender/makesrna/RNA_access.h index 9c45e34f211..2221526fa8b 100644 --- a/source/blender/makesrna/RNA_access.h +++ b/source/blender/makesrna/RNA_access.h @@ -106,6 +106,7 @@ extern StructRNA RNA_ClothCollisionSettings; extern StructRNA RNA_ClothModifier; extern StructRNA RNA_ClothSettings; extern StructRNA RNA_CloudsTexture; +extern StructRNA RNA_CollectionEngineSettings; extern StructRNA RNA_CollectionProperty; extern StructRNA RNA_CollisionModifier; extern StructRNA RNA_CollisionSensor; @@ -385,6 +386,8 @@ extern StructRNA RNA_MaterialStrand; extern StructRNA RNA_MaterialSubsurfaceScattering; extern StructRNA RNA_MaterialTextureSlot; extern StructRNA RNA_MaterialVolume; +extern StructRNA RNA_MaterialEngineSettings; +extern StructRNA RNA_MaterialEngineSettingsClay; extern StructRNA RNA_Mask; extern StructRNA RNA_MaskLayer; extern StructRNA RNA_Menu; @@ -500,6 +503,8 @@ extern StructRNA RNA_RenderLayer; extern StructRNA RNA_RenderPass; extern StructRNA RNA_RenderResult; extern StructRNA RNA_RenderSettings; +extern StructRNA RNA_RenderEngineSettings; +extern StructRNA RNA_RenderEngineSettingsClay; extern StructRNA RNA_RigidBodyWorld; extern StructRNA RNA_RigidBodyObject; extern StructRNA RNA_RigidBodyJointConstraint; diff --git a/source/blender/makesrna/intern/CMakeLists.txt b/source/blender/makesrna/intern/CMakeLists.txt index 0f3ea27a7f9..0bf2bbb6109 100644 --- a/source/blender/makesrna/intern/CMakeLists.txt +++ b/source/blender/makesrna/intern/CMakeLists.txt @@ -192,6 +192,10 @@ if(WITH_GAMEENGINE) add_definitions(-DWITH_GAMEENGINE) endif() +if(WITH_CLAY_ENGINE) + add_definitions(-DWITH_CLAY_ENGINE) +endif() + if(WITH_IMAGE_OPENEXR) add_definitions(-DWITH_OPENEXR) endif() @@ -341,6 +345,7 @@ blender_include_dirs( ../../bmesh ../../blentranslation ../../depsgraph + ../../draw ../../gpu ../../imbuf ../../ikplugin diff --git a/source/blender/makesrna/intern/rna_material.c b/source/blender/makesrna/intern/rna_material.c index b293f20dd95..4d3e3ffca26 100644 --- a/source/blender/makesrna/intern/rna_material.c +++ b/source/blender/makesrna/intern/rna_material.c @@ -313,6 +313,31 @@ static void rna_MaterialTextureSlot_use_set(PointerRNA *ptr, int value) } } +static StructRNA *rna_MaterialEngineSettings_refine(PointerRNA *ptr) +{ +#ifdef WITH_CLAY_ENGINE + MaterialEngineSettings *mes = (MaterialEngineSettings *)ptr->data; + if (STREQ(mes->name, RE_engine_id_BLENDER_CLAY)) { + return &RNA_MaterialEngineSettingsClay; + } +#endif + return &RNA_MaterialEngineSettings; +} + +static void rna_Material_update_engine_data(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *UNUSED(ptr)) +{ +#if 0 + Material *ma = (Material *)ptr->data; + RenderEngineSettings *ed = DRW_material_settings_get(ma, sce->r.engine, NULL); + + if (ed->runtime) { + MEM_freeN(ed->runtime); + ed->runtime = NULL; + } +#endif + WM_main_add_notifier(NC_SPACE | ND_SPACE_VIEW3D, NULL); +} + static void rna_Material_use_diffuse_ramp_set(PointerRNA *ptr, int value) { Material *ma = (Material *)ptr->data; @@ -824,6 +849,118 @@ static void rna_def_material_mtex(BlenderRNA *brna) RNA_def_property_update(prop, 0, "rna_Material_update"); } +static void rna_def_material_settings_clay(BlenderRNA *brna) +{ + StructRNA *srna; + PropertyRNA *prop; + + static EnumPropertyItem clay_matcap_items[] = { + {ICON_MATCAP_01, "01", ICON_MATCAP_01, "", ""}, + {ICON_MATCAP_02, "02", ICON_MATCAP_02, "", ""}, + {ICON_MATCAP_03, "03", ICON_MATCAP_03, "", ""}, + {ICON_MATCAP_04, "04", ICON_MATCAP_04, "", ""}, + {ICON_MATCAP_05, "05", ICON_MATCAP_05, "", ""}, + {ICON_MATCAP_06, "06", ICON_MATCAP_06, "", ""}, + {ICON_MATCAP_07, "07", ICON_MATCAP_07, "", ""}, + {ICON_MATCAP_08, "08", ICON_MATCAP_08, "", ""}, + {ICON_MATCAP_09, "09", ICON_MATCAP_09, "", ""}, + {ICON_MATCAP_10, "10", ICON_MATCAP_10, "", ""}, + {ICON_MATCAP_11, "11", ICON_MATCAP_11, "", ""}, + {ICON_MATCAP_12, "12", ICON_MATCAP_12, "", ""}, + {ICON_MATCAP_13, "13", ICON_MATCAP_13, "", ""}, + {ICON_MATCAP_14, "14", ICON_MATCAP_14, "", ""}, + {ICON_MATCAP_15, "15", ICON_MATCAP_15, "", ""}, + {ICON_MATCAP_16, "16", ICON_MATCAP_16, "", ""}, + {ICON_MATCAP_17, "17", ICON_MATCAP_17, "", ""}, + {ICON_MATCAP_18, "18", ICON_MATCAP_18, "", ""}, + {ICON_MATCAP_19, "19", ICON_MATCAP_19, "", ""}, + {ICON_MATCAP_20, "20", ICON_MATCAP_20, "", ""}, + {ICON_MATCAP_21, "21", ICON_MATCAP_21, "", ""}, + {ICON_MATCAP_22, "22", ICON_MATCAP_22, "", ""}, + {ICON_MATCAP_23, "23", ICON_MATCAP_23, "", ""}, + {ICON_MATCAP_24, "24", ICON_MATCAP_24, "", ""}, + {0, NULL, 0, NULL, NULL} + }; + + static EnumPropertyItem clay_matcap_type[] = { + {CLAY_MATCAP_NONE, "NONE", 0, "Scene", "Use default scene matcap"}, + {CLAY_MATCAP_SIMPLE, "SIMPLE", 0, "Simple", "Let you choose the texture to use with the default settings"}, + {CLAY_MATCAP_COMPLETE, "COMPLETE", 0, "Complete", "Expose all settings"}, + {0, NULL, 0, NULL, NULL} + }; + + srna = RNA_def_struct(brna, "MaterialEngineSettingsClay", "MaterialEngineSettings"); + RNA_def_struct_ui_text(srna, "Material Clay Settings", "Clay Engine settings for a Material data-block"); + RNA_def_struct_sdna_from(srna, "MaterialEngineSettingsClay", "data"); + + prop = RNA_def_property(srna, "type", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_items(prop, clay_matcap_type); + RNA_def_property_ui_text(prop, "Settings Type", "What settings to use for this material"); + RNA_def_property_update(prop, 0, "rna_Material_update_engine_data"); + + prop = RNA_def_property(srna, "matcap_icon", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_items(prop, clay_matcap_items); + RNA_def_property_ui_text(prop, "Matcap", "Image to use for Material Capture by this material"); + RNA_def_property_update(prop, 0, "rna_Material_update_engine_data"); + + prop = RNA_def_property(srna, "matcap_rotation", PROP_FLOAT, PROP_FACTOR); + RNA_def_property_float_sdna(prop, NULL, "matcap_rot"); + RNA_def_property_range(prop, 0.0f, 1.0f); + RNA_def_property_ui_text(prop, "Matcap Rotation", "Orientation of the matcap on the model"); + RNA_def_property_update(prop, 0, "rna_Material_update_engine_data"); + + prop = RNA_def_property(srna, "matcap_hue", PROP_FLOAT, PROP_FACTOR); + RNA_def_property_range(prop, 0.0f, 1.0f); + RNA_def_property_ui_text(prop, "Matcap Hue shift", "Hue correction of the matcap"); + RNA_def_property_update(prop, 0, "rna_Material_update_engine_data"); + + prop = RNA_def_property(srna, "matcap_saturation", PROP_FLOAT, PROP_FACTOR); + RNA_def_property_float_sdna(prop, NULL, "matcap_sat"); + RNA_def_property_range(prop, 0.0f, 1.0f); + RNA_def_property_ui_text(prop, "Matcap Saturation", "Saturation correction of the matcap"); + RNA_def_property_update(prop, 0, "rna_Material_update_engine_data"); + + prop = RNA_def_property(srna, "matcap_value", PROP_FLOAT, PROP_FACTOR); + RNA_def_property_float_sdna(prop, NULL, "matcap_val"); + RNA_def_property_range(prop, 0.0f, 1.0f); + RNA_def_property_ui_text(prop, "Matcap Value", "Value correction of the matcap"); + RNA_def_property_update(prop, 0, "rna_Material_update_engine_data"); + + prop = RNA_def_property(srna, "ssao_factor_cavity", PROP_FLOAT, PROP_NONE); + RNA_def_property_ui_text(prop, "Cavity Strength", "Strength of the Cavity effect"); + RNA_def_property_range(prop, 0.0f, 250.0f); + RNA_def_property_update(prop, 0, "rna_Material_update_engine_data"); + + prop = RNA_def_property(srna, "ssao_factor_edge", PROP_FLOAT, PROP_NONE); + RNA_def_property_ui_text(prop, "Edge Strength", "Strength of the Edge effect"); + RNA_def_property_range(prop, 0.0f, 250.0f); + RNA_def_property_update(prop, 0, "rna_Material_update_engine_data"); + + prop = RNA_def_property(srna, "ssao_distance", PROP_FLOAT, PROP_NONE); + RNA_def_property_ui_text(prop, "Distance", "Distance of object that contribute to the Cavity/Edge effect"); + RNA_def_property_range(prop, 0.0f, 100000.0f); + RNA_def_property_ui_range(prop, 0.0f, 100.0f, 1, 3); + RNA_def_property_update(prop, 0, "rna_Material_update_engine_data"); + + prop = RNA_def_property(srna, "ssao_attenuation", PROP_FLOAT, PROP_NONE); + RNA_def_property_ui_text(prop, "Attenuation", "Attenuation constant"); + RNA_def_property_range(prop, 1.0f, 100000.0f); + RNA_def_property_ui_range(prop, 1.0f, 100.0f, 1, 3); + RNA_def_property_update(prop, 0, "rna_Material_update_engine_data"); +} + +static void rna_def_material_engine_settings(BlenderRNA *brna) +{ + StructRNA *srna; + + srna = RNA_def_struct(brna, "MaterialEngineSettings", NULL); + RNA_def_struct_ui_text(srna, "Engine Settings", "Engine specific settings"); + RNA_def_struct_sdna(srna, "MaterialEngineSettings"); + RNA_def_struct_refine_func(srna, "rna_MaterialEngineSettings_refine"); + + rna_def_material_settings_clay(brna); +} + static void rna_def_material_gamesettings(BlenderRNA *brna) { StructRNA *srna; @@ -2087,6 +2224,11 @@ void RNA_def_material(BlenderRNA *brna) RNA_def_property_struct_type(prop, "MaterialGameSettings"); RNA_def_property_ui_text(prop, "Game Settings", "Game material settings"); + /* Engine settings */ + prop = RNA_def_property(srna, "engines_settings", PROP_COLLECTION, PROP_NONE); + RNA_def_property_struct_type(prop, "MaterialEngineSettings"); + RNA_def_property_ui_text(prop, "Material Engine Settings", "Engine specific settings"); + /* nodetree */ prop = RNA_def_property(srna, "node_tree", PROP_POINTER, PROP_NONE); RNA_def_property_pointer_sdna(prop, NULL, "nodetree"); @@ -2136,6 +2278,7 @@ void RNA_def_material(BlenderRNA *brna) rna_def_material_strand(brna); rna_def_material_physics(brna); rna_def_material_gamesettings(brna); + rna_def_material_engine_settings(brna); RNA_api_material(srna); } diff --git a/source/blender/makesrna/intern/rna_render.c b/source/blender/makesrna/intern/rna_render.c index 518c7efd915..5f796261c73 100644 --- a/source/blender/makesrna/intern/rna_render.c +++ b/source/blender/makesrna/intern/rna_render.c @@ -261,6 +261,24 @@ static void engine_update_script_node(RenderEngine *engine, struct bNodeTree *nt RNA_parameter_list_free(&list); } +static void engine_collection_settings_create(RenderEngine *engine, struct CollectionEngineSettings *ces) +{ + extern FunctionRNA rna_RenderEngine_collection_settings_create_func; + PointerRNA ptr,cesptr; + ParameterList list; + FunctionRNA *func; + + RNA_pointer_create(NULL, engine->type->ext.srna, engine, &ptr); + RNA_pointer_create(NULL, &RNA_CollectionEngineSettings, ces, &cesptr); + func = &rna_RenderEngine_collection_settings_create_func; + + RNA_parameter_list_create(&list, &ptr, func); + RNA_parameter_set_lookup(&list, "collection_settings", &cesptr); + engine->type->ext.call(NULL, &ptr, func, &list); + + RNA_parameter_list_free(&list); +} + /* RenderEngine registration */ static void rna_RenderEngine_unregister(Main *UNUSED(bmain), StructRNA *type) @@ -281,7 +299,7 @@ static StructRNA *rna_RenderEngine_register(Main *bmain, ReportList *reports, vo RenderEngineType *et, dummyet = {NULL}; RenderEngine dummyengine = {NULL}; PointerRNA dummyptr; - int have_function[6]; + int have_function[7]; /* setup dummy engine & engine type to store static properties in */ dummyengine.type = &dummyet; @@ -323,8 +341,9 @@ static StructRNA *rna_RenderEngine_register(Main *bmain, ReportList *reports, vo et->view_update = (have_function[3]) ? engine_view_update : NULL; et->view_draw = (have_function[4]) ? engine_view_draw : NULL; et->update_script_node = (have_function[5]) ? engine_update_script_node : NULL; + et->collection_settings_create = (have_function[6]) ? engine_collection_settings_create : NULL; - BLI_addtail(&R_engines, et); + RE_engines_register(bmain, et); return et->ext.srna; } @@ -489,6 +508,13 @@ static void rna_def_render_engine(BlenderRNA *brna) parm = RNA_def_pointer(func, "node", "Node", "", ""); RNA_def_parameter_flags(parm, 0, PARM_RNAPTR); + /* per-collection engine settings initialization */ + func = RNA_def_function(srna, "collection_settings_create", NULL); + RNA_def_function_ui_description(func, "Create the per collection settings for the engine"); + RNA_def_function_flag(func, FUNC_REGISTER_OPTIONAL | FUNC_ALLOW_WRITE); + parm = RNA_def_pointer(func, "collection_settings", "CollectionEngineSettings", "", ""); + RNA_def_parameter_flags(parm, 0, PARM_RNAPTR); + /* tag for redraw */ func = RNA_def_function(srna, "tag_redraw", "engine_tag_redraw"); RNA_def_function_ui_description(func, "Request redraw for viewport rendering"); diff --git a/source/blender/makesrna/intern/rna_scene.c b/source/blender/makesrna/intern/rna_scene.c index 8f36af96cf4..ec9a08af287 100644 --- a/source/blender/makesrna/intern/rna_scene.c +++ b/source/blender/makesrna/intern/rna_scene.c @@ -52,6 +52,8 @@ #include "GPU_extensions.h" +#include "DRW_engine.h" + #include "RNA_define.h" #include "RNA_enum_types.h" @@ -80,6 +82,8 @@ #include "BLI_threads.h" +#define NO_ENGINE "NO_ENGINE" + #ifdef WITH_OPENEXR EnumPropertyItem rna_enum_exr_codec_items[] = { {R_IMF_EXR_CODEC_NONE, "NONE", 0, "None", ""}, @@ -1872,6 +1876,43 @@ static void rna_GameSettings_exit_key_set(PointerRNA *ptr, int value) gm->exitkey = value; } +static StructRNA *rna_RenderEngineSettings_refine(PointerRNA *ptr) +{ +#ifdef WITH_CLAY_ENGINE + RenderEngineSettings *res = (RenderEngineSettings *)ptr->data; + + if (STREQ(res->name, RE_engine_id_BLENDER_CLAY)) { + return &RNA_RenderEngineSettingsClay; + } +#endif + return &RNA_RenderEngineSettings; +} + +static PointerRNA rna_RenderEngineSettings_active_get(PointerRNA *ptr) +{ + Scene *scene = (Scene *)ptr->data; + RenderEngineSettings *res; + + /* Ensure settings exists */ + DRW_render_settings_get(scene, scene->r.engine); + + res = BLI_findstring(&scene->engines_settings, scene->r.engine, offsetof(RenderEngineSettings, name)); + + return rna_pointer_inherit_refine(ptr, &RNA_RenderEngineSettings, res); +} + +static void rna_RenderEngineSettings_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr) +{ + Scene *sce = (Scene *)ptr->id.data; + MaterialEngineSettingsClay *res; + + res = (MaterialEngineSettingsClay *)DRW_render_settings_get(sce, sce->r.engine); + + res->flag = CLAY_OUTDATED; + + WM_main_add_notifier(NC_SPACE | ND_SPACE_VIEW3D, NULL); +} + static TimeMarker *rna_TimeLine_add(Scene *scene, const char name[], int frame) { TimeMarker *marker = MEM_callocN(sizeof(TimeMarker), "TimeMarker"); @@ -2311,6 +2352,83 @@ static void rna_SceneCollection_object_unlink( WM_main_add_notifier(NC_SCENE | ND_LAYER | ND_OB_ACTIVE, scene); } +/****** layer collection engine settings *******/ + +static StructRNA *rna_CollectionEngineSettings_refine(struct PointerRNA *ptr) +{ + CollectionEngineSettings *ces = (CollectionEngineSettings *)ptr->data; + + if (STREQ(ces->name, "BLENDER_CLAY")) { + return &RNA_CollectionEngineSettingsClay; + } + + /* TODO - handle other engines */ + TODO_LAYER; + (void) ces; + + return &RNA_CollectionEngineSettings; +} + +/****** clay engine settings *******/ + +#define RNA_LAYER_ENGINE_USE_GET_SET(_NAME_) \ + static int rna_LayerEngineSettings_##_NAME_##_use_get(PointerRNA *ptr) \ + { \ + CollectionEngineSettings *ces = (CollectionEngineSettings *)ptr->data; \ + return BKE_collection_engine_property_use_get(ces, #_NAME_) ? 1 : 0; \ + } \ + \ + static void rna_LayerEngineSettings_##_NAME_##_use_set(PointerRNA *ptr, int value) \ + { \ + CollectionEngineSettings *ces = (CollectionEngineSettings *)ptr->data; \ + BKE_collection_engine_property_use_set(ces, #_NAME_, value? true : false); \ + } + +#define RNA_LAYER_ENGINE_GET_SET(_TYPE_, _NAME_) \ +static _TYPE_ rna_LayerEngineSettings_##_NAME_##_get(PointerRNA *ptr) \ +{ \ + CollectionEngineSettings *ces = (CollectionEngineSettings *)ptr->data; \ + return BKE_collection_engine_property_value_get_##_TYPE_(ces, #_NAME_); \ +} \ + \ +static void rna_LayerEngineSettings_##_NAME_##_set(PointerRNA *ptr, _TYPE_ value) \ +{ \ + CollectionEngineSettings *ces = (CollectionEngineSettings *)ptr->data; \ + BKE_collection_engine_property_value_set_##_TYPE_(ces, #_NAME_, value); \ +} \ + RNA_LAYER_ENGINE_USE_GET_SET(_NAME_) + +#define RNA_LAYER_ENGINE_GET_SET_FLOAT(_NAME_) \ + RNA_LAYER_ENGINE_GET_SET(float, _NAME_) + +#define RNA_LAYER_ENGINE_GET_SET_INT(_NAME_) \ + RNA_LAYER_ENGINE_GET_SET(int, _NAME_) + + +RNA_LAYER_ENGINE_GET_SET_INT(type) +RNA_LAYER_ENGINE_GET_SET_INT(matcap_icon) +RNA_LAYER_ENGINE_GET_SET_FLOAT(matcap_rotation) +RNA_LAYER_ENGINE_GET_SET_FLOAT(matcap_hue) +RNA_LAYER_ENGINE_GET_SET_FLOAT(matcap_saturation) +RNA_LAYER_ENGINE_GET_SET_FLOAT(matcap_value) +RNA_LAYER_ENGINE_GET_SET_FLOAT(ssao_factor_cavity) +RNA_LAYER_ENGINE_GET_SET_FLOAT(ssao_factor_edge) +RNA_LAYER_ENGINE_GET_SET_FLOAT(ssao_distance) +RNA_LAYER_ENGINE_GET_SET_FLOAT(ssao_attenuation) + +#undef RNA_LAYER_ENGINE_GET_SET_INT +#undef RNA_LAYER_ENGINE_GET_SET_FLOAT +#undef RNA_LAYER_ENGINE_GET_SET +#undef RNA_LAYER_ENGINE_USE_GET_SET + +static void rna_CollectionEngineSettings_update(bContext *C, PointerRNA *UNUSED(ptr)) +{ + SceneLayer *sl = CTX_data_scene_layer(C); + BKE_scene_layer_engine_settings_recalculate(sl); +} + +/***********************************/ + static void rna_LayerCollection_name_get(PointerRNA *ptr, char *value) { SceneCollection *sc = ((LayerCollection *)ptr->data)->scene_collection; @@ -2340,6 +2458,25 @@ static PointerRNA rna_LayerCollection_objects_get(CollectionPropertyIterator *it return rna_pointer_inherit_refine(&iter->parent, &RNA_Object, base->object); } +static PointerRNA rna_LayerCollection_engine_settings_get(ID *UNUSED(id), LayerCollection *lc, bContext *C, const char *engine) +{ + Scene *scene = CTX_data_scene(C); + const char *engine_name; + + if (STREQ(engine, NO_ENGINE)) { + RenderData *rd = &scene->r; + engine_name = rd->engine; + } + else { + engine_name = engine; + } + + PointerRNA ptr; + CollectionEngineSettings *ces = BKE_layer_collection_engine_get(lc, engine_name); + RNA_pointer_create(NULL, &RNA_CollectionEngineSettings, ces, &ptr); + return rna_pointer_inherit_refine(&ptr, &RNA_CollectionEngineSettings, ces); +} + static void rna_LayerCollection_hide_update(bContext *C, PointerRNA *ptr) { Scene *scene = CTX_data_scene(C); @@ -5602,11 +5739,176 @@ static void rna_def_layer_collection_override(BlenderRNA *brna) RNA_def_property_update(prop, NC_SCENE | ND_LAYER_CONTENT, NULL); } +#define RNA_LAYER_ENGINE_USE(_NAME_) \ + prop = RNA_def_property(srna, #_NAME_"_use", PROP_BOOLEAN, PROP_NONE); \ + RNA_def_property_boolean_funcs(prop, \ + "rna_LayerEngineSettings_"#_NAME_"_use_get", \ + "rna_LayerEngineSettings_"#_NAME_"_use_set"); \ + RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE); \ + RNA_def_property_update(prop, NC_SCENE | ND_LAYER_CONTENT, "rna_CollectionEngineSettings_update"); + +static void rna_def_layer_collection_engine_settings_clay(BlenderRNA *brna) +{ + StructRNA *srna; + PropertyRNA *prop; + + static EnumPropertyItem clay_matcap_items[] = { + {ICON_MATCAP_01, "01", ICON_MATCAP_01, "", ""}, + {ICON_MATCAP_02, "02", ICON_MATCAP_02, "", ""}, + {ICON_MATCAP_03, "03", ICON_MATCAP_03, "", ""}, + {ICON_MATCAP_04, "04", ICON_MATCAP_04, "", ""}, + {ICON_MATCAP_05, "05", ICON_MATCAP_05, "", ""}, + {ICON_MATCAP_06, "06", ICON_MATCAP_06, "", ""}, + {ICON_MATCAP_07, "07", ICON_MATCAP_07, "", ""}, + {ICON_MATCAP_08, "08", ICON_MATCAP_08, "", ""}, + {ICON_MATCAP_09, "09", ICON_MATCAP_09, "", ""}, + {ICON_MATCAP_10, "10", ICON_MATCAP_10, "", ""}, + {ICON_MATCAP_11, "11", ICON_MATCAP_11, "", ""}, + {ICON_MATCAP_12, "12", ICON_MATCAP_12, "", ""}, + {ICON_MATCAP_13, "13", ICON_MATCAP_13, "", ""}, + {ICON_MATCAP_14, "14", ICON_MATCAP_14, "", ""}, + {ICON_MATCAP_15, "15", ICON_MATCAP_15, "", ""}, + {ICON_MATCAP_16, "16", ICON_MATCAP_16, "", ""}, + {ICON_MATCAP_17, "17", ICON_MATCAP_17, "", ""}, + {ICON_MATCAP_18, "18", ICON_MATCAP_18, "", ""}, + {ICON_MATCAP_19, "19", ICON_MATCAP_19, "", ""}, + {ICON_MATCAP_20, "20", ICON_MATCAP_20, "", ""}, + {ICON_MATCAP_21, "21", ICON_MATCAP_21, "", ""}, + {ICON_MATCAP_22, "22", ICON_MATCAP_22, "", ""}, + {ICON_MATCAP_23, "23", ICON_MATCAP_23, "", ""}, + {ICON_MATCAP_24, "24", ICON_MATCAP_24, "", ""}, + {0, NULL, 0, NULL, NULL} + }; + + static EnumPropertyItem clay_matcap_type[] = { + {CLAY_MATCAP_NONE, "NONE", 0, "Scene", "Use default scene matcap"}, + {CLAY_MATCAP_SIMPLE, "SIMPLE", 0, "Simple", "Let you choose the texture to use with the default settings"}, + {CLAY_MATCAP_COMPLETE, "COMPLETE", 0, "Complete", "Expose all settings"}, + {0, NULL, 0, NULL, NULL} + }; + + srna = RNA_def_struct(brna, "CollectionEngineSettingsClay", NULL); + RNA_def_struct_sdna(srna, "CollectionEngineSettings"); + RNA_def_struct_ui_text(srna, "Collections Clay Engine Settings", "Engine specific settings for this collection"); + + prop = RNA_def_property(srna, "name", PROP_STRING, PROP_NONE); + RNA_def_property_ui_text(prop, "Name", "Engine name"); + RNA_def_property_clear_flag(prop, PROP_EDITABLE); + RNA_def_struct_name_property(srna, prop); + + /* see RNA_LAYER_ENGINE_GET_SET macro */ + + prop = RNA_def_property(srna, "type", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_funcs(prop, "rna_LayerEngineSettings_type_get", "rna_LayerEngineSettings_type_set", NULL); + RNA_def_property_enum_items(prop, clay_matcap_type); + RNA_def_property_ui_text(prop, "Settings Type", "What settings to use for this material"); + RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE); + RNA_def_property_update(prop, NC_SCENE | ND_LAYER_CONTENT, "rna_CollectionEngineSettings_update"); + RNA_LAYER_ENGINE_USE(type) + + prop = RNA_def_property(srna, "matcap_icon", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_funcs(prop, "rna_LayerEngineSettings_matcap_icon_get", "rna_LayerEngineSettings_matcap_icon_set", NULL); + RNA_def_property_enum_items(prop, clay_matcap_items); + RNA_def_property_ui_text(prop, "Matcap", "Image to use for Material Capture by this material"); + RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE); + RNA_def_property_update(prop, NC_SCENE | ND_LAYER_CONTENT, "rna_CollectionEngineSettings_update"); + RNA_LAYER_ENGINE_USE(matcap_icon) + + prop = RNA_def_property(srna, "matcap_rotation", PROP_FLOAT, PROP_FACTOR); + RNA_def_property_float_funcs(prop, "rna_LayerEngineSettings_matcap_rotation_get", "rna_LayerEngineSettings_matcap_rotation_set", NULL); + RNA_def_property_range(prop, 0.0f, 1.0f); + RNA_def_property_ui_text(prop, "Matcap Rotation", "Orientation of the matcap on the model"); + RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE); + RNA_def_property_update(prop, NC_SCENE | ND_LAYER_CONTENT, "rna_CollectionEngineSettings_update"); + RNA_LAYER_ENGINE_USE(matcap_rotation) + + prop = RNA_def_property(srna, "matcap_hue", PROP_FLOAT, PROP_FACTOR); + RNA_def_property_float_funcs(prop, "rna_LayerEngineSettings_matcap_hue_get", "rna_LayerEngineSettings_matcap_hue_set", NULL); + RNA_def_property_range(prop, 0.0f, 1.0f); + RNA_def_property_ui_text(prop, "Matcap Hue shift", "Hue correction of the matcap"); + RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE); + RNA_def_property_update(prop, NC_SCENE | ND_LAYER_CONTENT, "rna_CollectionEngineSettings_update"); + RNA_LAYER_ENGINE_USE(matcap_hue) + + prop = RNA_def_property(srna, "matcap_saturation", PROP_FLOAT, PROP_FACTOR); + RNA_def_property_float_funcs(prop, "rna_LayerEngineSettings_matcap_saturation_get", "rna_LayerEngineSettings_matcap_saturation_set", NULL); + RNA_def_property_range(prop, 0.0f, 1.0f); + RNA_def_property_ui_text(prop, "Matcap Saturation", "Saturation correction of the matcap"); + RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE); + RNA_def_property_update(prop, NC_SCENE | ND_LAYER_CONTENT, "rna_CollectionEngineSettings_update"); + RNA_LAYER_ENGINE_USE(matcap_saturation) + + prop = RNA_def_property(srna, "matcap_value", PROP_FLOAT, PROP_FACTOR); + RNA_def_property_float_funcs(prop, "rna_LayerEngineSettings_matcap_value_get", "rna_LayerEngineSettings_matcap_value_set", NULL); + RNA_def_property_range(prop, 0.0f, 1.0f); + RNA_def_property_ui_text(prop, "Matcap Value", "Value correction of the matcap"); + RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE); + RNA_def_property_update(prop, NC_SCENE | ND_LAYER_CONTENT, "rna_CollectionEngineSettings_update"); + RNA_LAYER_ENGINE_USE(matcap_value) + + prop = RNA_def_property(srna, "ssao_factor_cavity", PROP_FLOAT, PROP_NONE); + RNA_def_property_float_funcs(prop, "rna_LayerEngineSettings_ssao_factor_cavity_get", "rna_LayerEngineSettings_ssao_factor_cavity_set", NULL); + RNA_def_property_ui_text(prop, "Cavity Strength", "Strength of the Cavity effect"); + RNA_def_property_range(prop, 0.0f, 250.0f); + RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE); + RNA_def_property_update(prop, NC_SCENE | ND_LAYER_CONTENT, "rna_CollectionEngineSettings_update"); + RNA_LAYER_ENGINE_USE(ssao_factor_cavity) + + prop = RNA_def_property(srna, "ssao_factor_edge", PROP_FLOAT, PROP_NONE); + RNA_def_property_float_funcs(prop, "rna_LayerEngineSettings_ssao_factor_edge_get", "rna_LayerEngineSettings_ssao_factor_edge_set", NULL); + RNA_def_property_ui_text(prop, "Edge Strength", "Strength of the Edge effect"); + RNA_def_property_range(prop, 0.0f, 250.0f); + RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE); + RNA_def_property_update(prop, NC_SCENE | ND_LAYER_CONTENT, "rna_CollectionEngineSettings_update"); + RNA_LAYER_ENGINE_USE(ssao_factor_edge) + + prop = RNA_def_property(srna, "ssao_distance", PROP_FLOAT, PROP_NONE); + RNA_def_property_float_funcs(prop, "rna_LayerEngineSettings_ssao_distance_get", "rna_LayerEngineSettings_ssao_distance_set", NULL); + RNA_def_property_ui_text(prop, "Distance", "Distance of object that contribute to the Cavity/Edge effect"); + RNA_def_property_range(prop, 0.0f, 100000.0f); + RNA_def_property_ui_range(prop, 0.0f, 100.0f, 1, 3); + RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE); + RNA_def_property_update(prop, NC_SCENE | ND_LAYER_CONTENT, "rna_CollectionEngineSettings_update"); + RNA_LAYER_ENGINE_USE(ssao_distance) + + prop = RNA_def_property(srna, "ssao_attenuation", PROP_FLOAT, PROP_NONE); + RNA_def_property_float_funcs(prop, "rna_LayerEngineSettings_ssao_attenuation_get", "rna_LayerEngineSettings_ssao_attenuation_set", NULL); + RNA_def_property_ui_text(prop, "Attenuation", "Attenuation constant"); + RNA_def_property_range(prop, 1.0f, 100000.0f); + RNA_def_property_ui_range(prop, 1.0f, 100.0f, 1, 3); + RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE); + RNA_def_property_update(prop, NC_SCENE | ND_LAYER_CONTENT, "rna_CollectionEngineSettings_update"); + RNA_LAYER_ENGINE_USE(ssao_attenuation) +} + +static void rna_def_layer_collection_engine_settings(BlenderRNA *brna) +{ + StructRNA *srna; + PropertyRNA *prop; + + srna = RNA_def_struct(brna, "CollectionEngineSettings", NULL); + RNA_def_struct_ui_text(srna, "Collections Engine Settings", "Engine specific settings for this collection"); + RNA_def_struct_refine_func(srna, "rna_CollectionEngineSettings_refine"); + + prop = RNA_def_property(srna, "name", PROP_STRING, PROP_NONE); + RNA_def_property_ui_text(prop, "Name", "Engine name"); + RNA_def_property_clear_flag(prop, PROP_EDITABLE); + RNA_def_struct_name_property(srna, prop); + + /* the engine specific structs */ + rna_def_layer_collection_engine_settings_clay(brna); +} + +#undef RNA_LAYER_ENGINE_USE + static void rna_def_layer_collection(BlenderRNA *brna) { StructRNA *srna; PropertyRNA *prop; + FunctionRNA *func; + PropertyRNA *parm; + srna = RNA_def_struct(brna, "LayerCollection", NULL); RNA_def_struct_ui_text(srna, "Layer Collection", "Layer collection"); @@ -5638,6 +5940,15 @@ static void rna_def_layer_collection(BlenderRNA *brna) RNA_def_property_struct_type(prop, "LayerCollectionOverride"); RNA_def_property_ui_text(prop, "Collection Overrides", ""); + func = RNA_def_function(srna, "get_engine_settings", "rna_LayerCollection_engine_settings_get"); + RNA_def_function_ui_description(func, "Return the engine settings for this collection"); + RNA_def_function_flag(func, FUNC_USE_SELF_ID | FUNC_USE_CONTEXT); + parm = RNA_def_string(func, "engine", NO_ENGINE, MAX_NAME, "Engine", "use context one by default"); + RNA_def_parameter_clear_flags(parm, 0, PARM_REQUIRED); + parm = RNA_def_pointer(func, "result", "CollectionEngineSettings", "", ""); + RNA_def_parameter_flags(parm, 0, PARM_RNAPTR); + RNA_def_function_return(func, parm); + /* Flags */ prop = RNA_def_property(srna, "hide", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", COLLECTION_VISIBLE); @@ -6580,6 +6891,115 @@ static void rna_def_scene_quicktime_settings(BlenderRNA *brna) } #endif +#ifdef WITH_CLAY_ENGINE +static void rna_def_render_engine_settings_clay(BlenderRNA *brna) +{ + StructRNA *srna; + PropertyRNA *prop; + static EnumPropertyItem clay_matcap_items[] = { + {ICON_MATCAP_01, "01", ICON_MATCAP_01, "", ""}, + {ICON_MATCAP_02, "02", ICON_MATCAP_02, "", ""}, + {ICON_MATCAP_03, "03", ICON_MATCAP_03, "", ""}, + {ICON_MATCAP_04, "04", ICON_MATCAP_04, "", ""}, + {ICON_MATCAP_05, "05", ICON_MATCAP_05, "", ""}, + {ICON_MATCAP_06, "06", ICON_MATCAP_06, "", ""}, + {ICON_MATCAP_07, "07", ICON_MATCAP_07, "", ""}, + {ICON_MATCAP_08, "08", ICON_MATCAP_08, "", ""}, + {ICON_MATCAP_09, "09", ICON_MATCAP_09, "", ""}, + {ICON_MATCAP_10, "10", ICON_MATCAP_10, "", ""}, + {ICON_MATCAP_11, "11", ICON_MATCAP_11, "", ""}, + {ICON_MATCAP_12, "12", ICON_MATCAP_12, "", ""}, + {ICON_MATCAP_13, "13", ICON_MATCAP_13, "", ""}, + {ICON_MATCAP_14, "14", ICON_MATCAP_14, "", ""}, + {ICON_MATCAP_15, "15", ICON_MATCAP_15, "", ""}, + {ICON_MATCAP_16, "16", ICON_MATCAP_16, "", ""}, + {ICON_MATCAP_17, "17", ICON_MATCAP_17, "", ""}, + {ICON_MATCAP_18, "18", ICON_MATCAP_18, "", ""}, + {ICON_MATCAP_19, "19", ICON_MATCAP_19, "", ""}, + {ICON_MATCAP_20, "20", ICON_MATCAP_20, "", ""}, + {ICON_MATCAP_21, "21", ICON_MATCAP_21, "", ""}, + {ICON_MATCAP_22, "22", ICON_MATCAP_22, "", ""}, + {ICON_MATCAP_23, "23", ICON_MATCAP_23, "", ""}, + {ICON_MATCAP_24, "24", ICON_MATCAP_24, "", ""}, + {0, NULL, 0, NULL, NULL} + }; + + srna = RNA_def_struct(brna, "RenderEngineSettingsClay", "RenderEngineSettings"); + RNA_def_struct_ui_text(srna, "Material Clay Settings", "Clay Engine settings for a Material data-block"); + RNA_def_struct_sdna_from(srna, "RenderEngineSettingsClay", "data"); + + prop = RNA_def_property(srna, "matcap_icon", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_items(prop, clay_matcap_items); + RNA_def_property_ui_text(prop, "Matcap", "Image to use for Material Capture by this material"); + RNA_def_property_update(prop, 0, "rna_RenderEngineSettings_update"); + + prop = RNA_def_property(srna, "matcap_rotation", PROP_FLOAT, PROP_FACTOR); + RNA_def_property_float_sdna(prop, NULL, "matcap_rot"); + RNA_def_property_range(prop, 0.0f, 1.0f); + RNA_def_property_ui_text(prop, "Matcap Rotation", "Orientation of the matcap on the model"); + RNA_def_property_update(prop, 0, "rna_RenderEngineSettings_update"); + + prop = RNA_def_property(srna, "matcap_hue", PROP_FLOAT, PROP_FACTOR); + RNA_def_property_range(prop, 0.0f, 1.0f); + RNA_def_property_ui_text(prop, "Matcap Hue shift", "Hue correction of the matcap"); + RNA_def_property_update(prop, 0, "rna_RenderEngineSettings_update"); + + prop = RNA_def_property(srna, "matcap_saturation", PROP_FLOAT, PROP_FACTOR); + RNA_def_property_float_sdna(prop, NULL, "matcap_sat"); + RNA_def_property_range(prop, 0.0f, 1.0f); + RNA_def_property_ui_text(prop, "Matcap Saturation", "Saturation correction of the matcap"); + RNA_def_property_update(prop, 0, "rna_RenderEngineSettings_update"); + + prop = RNA_def_property(srna, "matcap_value", PROP_FLOAT, PROP_FACTOR); + RNA_def_property_float_sdna(prop, NULL, "matcap_val"); + RNA_def_property_range(prop, 0.0f, 1.0f); + RNA_def_property_ui_text(prop, "Matcap Value", "Value correction of the matcap"); + RNA_def_property_update(prop, 0, "rna_RenderEngineSettings_update"); + + prop = RNA_def_property(srna, "ssao_factor_cavity", PROP_FLOAT, PROP_NONE); + RNA_def_property_ui_text(prop, "Cavity Strength", "Strength of the Cavity effect"); + RNA_def_property_range(prop, 0.0f, 250.0f); + RNA_def_property_update(prop, 0, "rna_RenderEngineSettings_update"); + + prop = RNA_def_property(srna, "ssao_factor_edge", PROP_FLOAT, PROP_NONE); + RNA_def_property_ui_text(prop, "Edge Strength", "Strength of the Edge effect"); + RNA_def_property_range(prop, 0.0f, 250.0f); + RNA_def_property_update(prop, 0, "rna_RenderEngineSettings_update"); + + prop = RNA_def_property(srna, "ssao_distance", PROP_FLOAT, PROP_NONE); + RNA_def_property_ui_text(prop, "Distance", "Distance of object that contribute to the Cavity/Edge effect"); + RNA_def_property_range(prop, 0.0f, 100000.0f); + RNA_def_property_ui_range(prop, 0.0f, 100.0f, 1, 3); + RNA_def_property_update(prop, 0, "rna_RenderEngineSettings_update"); + + prop = RNA_def_property(srna, "ssao_attenuation", PROP_FLOAT, PROP_NONE); + RNA_def_property_ui_text(prop, "Attenuation", "Attenuation constant"); + RNA_def_property_range(prop, 1.0f, 100000.0f); + RNA_def_property_ui_range(prop, 1.0f, 100.0f, 1, 3); + RNA_def_property_update(prop, 0, "rna_RenderEngineSettings_update"); + + /* Clay settings */ + prop = RNA_def_property(srna, "ssao_samples", PROP_INT, PROP_NONE); + RNA_def_property_ui_text(prop, "Samples", "Number of samples"); + RNA_def_property_range(prop, 1, 500); + RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL); +} +#endif + +static void rna_def_scene_render_engine(BlenderRNA *brna) +{ + StructRNA *srna; + + srna = RNA_def_struct(brna, "RenderEngineSettings", NULL); + RNA_def_struct_ui_text(srna, "Render Engine Settings", "Engine specific render settings"); + RNA_def_struct_sdna(srna, "RenderEngineSettings"); + RNA_def_struct_refine_func(srna, "rna_RenderEngineSettings_refine"); + +#ifdef WITH_CLAY_ENGINE + rna_def_render_engine_settings_clay(brna); +#endif +} + static void rna_def_scene_render_data(BlenderRNA *brna) { StructRNA *srna; @@ -8075,7 +8495,17 @@ void RNA_def_scene(BlenderRNA *brna) RNA_def_property_pointer_sdna(prop, NULL, "r"); RNA_def_property_struct_type(prop, "RenderSettings"); RNA_def_property_ui_text(prop, "Render Data", ""); - + + /* Render Engine Data */ + prop = RNA_def_property(srna, "engines_settings", PROP_COLLECTION, PROP_NONE); + RNA_def_property_struct_type(prop, "RenderEngineSettings"); + RNA_def_property_ui_text(prop, "Render Engine Settings", "Engine specific render settings"); + + prop = RNA_def_property(srna, "active_engine_settings", PROP_POINTER, PROP_NONE); + RNA_def_property_struct_type(prop, "RenderEngineSettings"); + RNA_def_property_pointer_funcs(prop, "rna_RenderEngineSettings_active_get", NULL, NULL, NULL); + RNA_def_property_ui_text(prop, "Active Render Engine Settings", "Active Engine specific render settings for this scene"); + /* Safe Areas */ prop = RNA_def_property(srna, "safe_areas", PROP_POINTER, PROP_NONE); RNA_def_property_pointer_sdna(prop, NULL, "safe_areas"); @@ -8222,11 +8652,13 @@ void RNA_def_scene(BlenderRNA *brna) rna_def_scene_collection(brna); rna_def_layer_collection(brna); rna_def_layer_collection_override(brna); + rna_def_layer_collection_engine_settings(brna); rna_def_scene_layer(brna); rna_def_object_base(brna); RNA_define_animate_sdna(true); /* *** Animated *** */ rna_def_scene_render_data(brna); + rna_def_scene_render_engine(brna); rna_def_scene_render_layer(brna); rna_def_gpu_fx(brna); rna_def_scene_render_view(brna); @@ -8236,3 +8668,5 @@ void RNA_def_scene(BlenderRNA *brna) } #endif + +#undef NO_ENGINE diff --git a/source/blender/render/CMakeLists.txt b/source/blender/render/CMakeLists.txt index 9e40ab02ee4..27fa119bc88 100644 --- a/source/blender/render/CMakeLists.txt +++ b/source/blender/render/CMakeLists.txt @@ -35,6 +35,7 @@ set(INC ../makesdna ../makesrna ../physics + ../draw ../../../intern/guardedalloc ../../../intern/mikktspace ../../../intern/smoke/extern diff --git a/source/blender/render/extern/include/RE_engine.h b/source/blender/render/extern/include/RE_engine.h index f83a210275f..f1b3534b40a 100644 --- a/source/blender/render/extern/include/RE_engine.h +++ b/source/blender/render/extern/include/RE_engine.h @@ -39,6 +39,8 @@ struct bNode; struct bNodeTree; +struct CollectionEngineSettings; +struct Main; struct Object; struct Render; struct RenderData; @@ -63,6 +65,7 @@ struct BakePixel; #define RE_USE_TEXTURE_PREVIEW 128 #define RE_USE_SHADING_NODES_CUSTOM 256 #define RE_USE_SPHERICAL_STEREO 512 +#define RE_USE_OGL_PIPELINE 1024 /* RenderEngine.flag */ #define RE_ENGINE_ANIMATION 1 @@ -97,6 +100,8 @@ typedef struct RenderEngineType { void (*update_script_node)(struct RenderEngine *engine, struct bNodeTree *ntree, struct bNode *node); + void (*collection_settings_create)(struct RenderEngine *engine, struct CollectionEngineSettings *ces); + /* RNA integration */ ExtensionRNA ext; } RenderEngineType; @@ -164,6 +169,7 @@ void RE_engine_frame_set(struct RenderEngine *engine, int frame, float subframe) void RE_engines_init(void); void RE_engines_exit(void); +void RE_engines_register(struct Main *bmain, RenderEngineType *render_type); RenderEngineType *RE_engines_find(const char *idname); diff --git a/source/blender/render/intern/source/external_engine.c b/source/blender/render/intern/source/external_engine.c index fd9d95c63b6..1744d88a14f 100644 --- a/source/blender/render/intern/source/external_engine.c +++ b/source/blender/render/intern/source/external_engine.c @@ -45,6 +45,7 @@ #include "BKE_camera.h" #include "BKE_global.h" #include "BKE_colortools.h" +#include "BKE_layer.h" #include "BKE_report.h" #include "BKE_scene.h" @@ -58,6 +59,8 @@ #include "RE_pipeline.h" #include "RE_bake.h" +#include "DRW_engine.h" + #include "initrender.h" #include "renderpipeline.h" #include "render_types.h" @@ -68,7 +71,7 @@ static RenderEngineType internal_render_type = { NULL, NULL, "BLENDER_RENDER", N_("Blender Render"), RE_INTERNAL, - NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, {NULL, NULL, NULL} }; @@ -77,7 +80,7 @@ static RenderEngineType internal_render_type = { static RenderEngineType internal_game_type = { NULL, NULL, "BLENDER_GAME", N_("Blender Game"), RE_INTERNAL | RE_GAME, - NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, {NULL, NULL, NULL} }; @@ -87,16 +90,21 @@ ListBase R_engines = {NULL, NULL}; void RE_engines_init(void) { - BLI_addtail(&R_engines, &internal_render_type); + RE_engines_register(NULL, &internal_render_type); #ifdef WITH_GAMEENGINE - BLI_addtail(&R_engines, &internal_game_type); + RE_engines_register(NULL, &internal_game_type); #endif + DRW_engines_init(); } void RE_engines_exit(void) { RenderEngineType *type, *next; + DRW_engines_free(); + + BKE_layer_collection_engine_settings_callback_free(); + for (type = R_engines.first; type; type = next) { next = type->next; @@ -111,6 +119,14 @@ void RE_engines_exit(void) } } +void RE_engines_register(Main *bmain, RenderEngineType *render_type) +{ + if (render_type->collection_settings_create) { + BKE_layer_collection_engine_settings_callback_register(bmain, render_type->idname, render_type->collection_settings_create); + } + BLI_addtail(&R_engines, render_type); +} + RenderEngineType *RE_engines_find(const char *idname) { RenderEngineType *type; diff --git a/source/blenderplayer/bad_level_call_stubs/stubs.c b/source/blenderplayer/bad_level_call_stubs/stubs.c index e74f6f3208c..a9cf76adae3 100644 --- a/source/blenderplayer/bad_level_call_stubs/stubs.c +++ b/source/blenderplayer/bad_level_call_stubs/stubs.c @@ -186,6 +186,7 @@ struct wmWindowManager; #include "../blender/render/extern/include/RE_pipeline.h" #include "../blender/render/extern/include/RE_render_ext.h" #include "../blender/render/extern/include/RE_shader_ext.h" +#include "../blender/draw/DRW_engine.h" #include "../blender/windowmanager/WM_api.h" @@ -663,6 +664,7 @@ void RE_ReleaseResultImage(struct Render *re) RET_NONE int RE_engine_test_break(struct RenderEngine *engine) RET_ZERO void RE_engines_init() RET_NONE void RE_engines_exit() RET_NONE +void RE_engines_register(struct Main *bmain, RenderEngineType *render_type) RET_NONE void RE_engine_report(struct RenderEngine *engine, int type, const char *msg) RET_NONE ListBase R_engines = {NULL, NULL}; void RE_engine_free(struct RenderEngine *engine) RET_NONE @@ -679,6 +681,9 @@ void RE_instance_get_particle_info(struct ObjectInstanceRen *obi, float *index, void RE_FreeAllPersistentData(void) RET_NONE float RE_fresnel_dielectric(float incoming[3], float normal[3], float eta) RET_ZERO +/* Draw */ +void *DRW_render_settings_get(struct Scene *scene, const char *engine_name) RET_NULL + /* python */ struct wmOperatorType *WM_operatortype_find(const char *idname, bool quiet) RET_NULL void WM_operatortype_iter(struct GHashIterator *ghi) RET_NONE |