diff options
Diffstat (limited to 'source/blender')
485 files changed, 40349 insertions, 20179 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/alembic/intern/abc_exporter.cc b/source/blender/alembic/intern/abc_exporter.cc index 90a99469389..45c31279b50 100644 --- a/source/blender/alembic/intern/abc_exporter.cc +++ b/source/blender/alembic/intern/abc_exporter.cc @@ -123,19 +123,19 @@ static bool object_is_shape(Object *ob) } } -static bool export_object(const ExportSettings * const settings, Object *ob) +static bool export_object(const ExportSettings * const settings, const Base * const ob_base) { - if (settings->selected_only && !parent_selected(ob)) { + if (settings->selected_only && !object_selected(ob_base)) { return false; } - - if (settings->visible_layers_only && !(settings->scene->lay & ob->lay)) { + // FIXME Sybren: handle these cleanly (maybe just remove code), now using active scene layer instead. + if (settings->visible_layers_only && (ob_base->flag & BASE_VISIBLED) == 0) { return false; } - if (settings->renderable_only && (ob->restrictflag & OB_RESTRICT_RENDER)) { - return false; - } + // if (settings->renderable_only && (ob->restrictflag & OB_RESTRICT_RENDER)) { + // return false; + // } return true; } @@ -341,12 +341,10 @@ void AbcExporter::operator()(Main *bmain, float &progress, bool &was_canceled) void AbcExporter::createTransformWritersHierarchy(EvaluationContext *eval_ctx) { - Base *base = static_cast<Base *>(m_scene->base.first); - - while (base) { + for(Base *base = static_cast<Base *>(m_settings.sl->object_bases.first); base; base = base->next) { Object *ob = base->object; - if (export_object(&m_settings, ob)) { + if (export_object(&m_settings, base)) { switch(ob->type) { case OB_LAMP: case OB_LATTICE: @@ -356,53 +354,49 @@ void AbcExporter::createTransformWritersHierarchy(EvaluationContext *eval_ctx) break; default: - exploreTransform(eval_ctx, ob, ob->parent, NULL); + exploreTransform(eval_ctx, base, ob->parent, NULL); } } - - base = base->next; } } void AbcExporter::createTransformWritersFlat() { - Base *base = static_cast<Base *>(m_scene->base.first); - - while (base) { + for(Base *base = static_cast<Base *>(m_settings.sl->object_bases.first); base; base = base->next) { Object *ob = base->object; - if (export_object(&m_settings, ob) && object_is_shape(ob)) { + if (!export_object(&m_settings, base)) { std::string name = get_id_name(ob); m_xforms[name] = new AbcTransformWriter(ob, m_writer->archive().getTop(), 0, m_trans_sampling_index, m_settings); } - - base = base->next; } } -void AbcExporter::exploreTransform(EvaluationContext *eval_ctx, Object *ob, Object *parent, Object *dupliObParent) +void AbcExporter::exploreTransform(EvaluationContext *eval_ctx, Base *ob_base, Object *parent, Object *dupliObParent) { + Object *ob = ob_base->object; - if (export_object(&m_settings, ob) && object_is_shape(ob)) { + if (export_object(&m_settings, ob_base) && object_is_shape(ob)) { createTransformWriter(ob, parent, dupliObParent); } ListBase *lb = object_duplilist(eval_ctx, m_scene, ob); if (lb) { - DupliObject *link = static_cast<DupliObject *>(lb->first); - Object *dupli_ob = NULL; - Object *dupli_parent = NULL; - - while (link) { + Base fake_base = *ob_base; // copy flags (like selection state) from the real object. + fake_base.next = fake_base.prev = NULL; + + for (DupliObject *link = static_cast<DupliObject *>(lb->first); link; link = link->next) { + Object *dupli_ob = NULL; + Object *dupli_parent = NULL; + if (link->type == OB_DUPLIGROUP) { dupli_ob = link->ob; dupli_parent = (dupli_ob->parent) ? dupli_ob->parent : ob; - exploreTransform(eval_ctx, dupli_ob, dupli_parent, ob); + fake_base.object = dupli_ob; + exploreTransform(eval_ctx, &fake_base, dupli_parent, ob); } - - link = link->next; } } @@ -460,44 +454,42 @@ void AbcExporter::createTransformWriter(Object *ob, Object *parent, Object *dupl void AbcExporter::createShapeWriters(EvaluationContext *eval_ctx) { - Base *base = static_cast<Base *>(m_scene->base.first); - - while (base) { - Object *ob = base->object; - exploreObject(eval_ctx, ob, NULL); - - base = base->next; + for(Base *base = static_cast<Base *>(m_settings.sl->object_bases.first); base; base = base->next) { + exploreObject(eval_ctx, base, NULL); } } -void AbcExporter::exploreObject(EvaluationContext *eval_ctx, Object *ob, Object *dupliObParent) +void AbcExporter::exploreObject(EvaluationContext *eval_ctx, Base *ob_base, Object *dupliObParent) { + Object *ob = ob_base->object; ListBase *lb = object_duplilist(eval_ctx, m_scene, ob); - createShapeWriter(ob, dupliObParent); + createShapeWriter(ob_base, dupliObParent); if (lb) { - DupliObject *dupliob = static_cast<DupliObject *>(lb->first); + Base fake_base = *ob_base; // copy flags (like selection state) from the real object. + fake_base.next = fake_base.prev = NULL; - while (dupliob) { + for (DupliObject *dupliob = static_cast<DupliObject *>(lb->first); dupliob; dupliob = dupliob->next) { if (dupliob->type == OB_DUPLIGROUP) { - exploreObject(eval_ctx, dupliob->ob, ob); + fake_base.object = dupliob->ob; + exploreObject(eval_ctx, &fake_base, ob); } - - dupliob = dupliob->next; } } free_object_duplilist(lb); } -void AbcExporter::createShapeWriter(Object *ob, Object *dupliObParent) +void AbcExporter::createShapeWriter(Base *ob_base, Object *dupliObParent) { + Object *ob = ob_base->object; + if (!object_is_shape(ob)) { return; } - if (!export_object(&m_settings, ob)) { + if (!export_object(&m_settings, ob_base)) { return; } diff --git a/source/blender/alembic/intern/abc_exporter.h b/source/blender/alembic/intern/abc_exporter.h index b0eb8e185d6..80fee067c04 100644 --- a/source/blender/alembic/intern/abc_exporter.h +++ b/source/blender/alembic/intern/abc_exporter.h @@ -36,11 +36,14 @@ struct EvaluationContext; struct Main; struct Object; struct Scene; +struct SceneLayer; +struct Base; struct ExportSettings { ExportSettings(); Scene *scene; + SceneLayer *sl; // Scene layer to export; all its objects will be exported, unless selected_only=true bool selected_only; bool visible_layers_only; @@ -105,10 +108,10 @@ private: void createTransformWritersHierarchy(EvaluationContext *eval_ctx); void createTransformWritersFlat(); void createTransformWriter(Object *ob, Object *parent, Object *dupliObParent); - void exploreTransform(EvaluationContext *eval_ctx, Object *ob, Object *parent, Object *dupliObParent = NULL); - void exploreObject(EvaluationContext *eval_ctx, Object *ob, Object *dupliObParent); + void exploreTransform(EvaluationContext *eval_ctx, Base *ob_base, Object *parent, Object *dupliObParent); + void exploreObject(EvaluationContext *eval_ctx, Base *ob_base, Object *dupliObParent); void createShapeWriters(EvaluationContext *eval_ctx); - void createShapeWriter(Object *ob, Object *dupliObParent); + void createShapeWriter(Base *ob_base, Object *dupliObParent); AbcTransformWriter *getXForm(const std::string &name); diff --git a/source/blender/alembic/intern/abc_util.cc b/source/blender/alembic/intern/abc_util.cc index 08c94f437e6..bb375eb9561 100644 --- a/source/blender/alembic/intern/abc_util.cc +++ b/source/blender/alembic/intern/abc_util.cc @@ -35,6 +35,7 @@ extern "C" { #include "DNA_object_types.h" +#include "DNA_layer_types.h" #include "BLI_math.h" } @@ -58,6 +59,16 @@ std::string get_id_name(ID *id) return name; } + +/** + * @brief get_object_dag_path_name returns the name under which the object + * will be exported in the Alembic file. It is of the form + * "[../grandparent/]parent/object" if dupli_parent is NULL, or + * "dupli_parent/[../grandparent/]parent/object" otherwise. + * @param ob + * @param dupli_parent + * @return + */ std::string get_object_dag_path_name(Object *ob, Object *dupli_parent) { std::string name = get_id_name(ob); @@ -76,31 +87,9 @@ std::string get_object_dag_path_name(Object *ob, Object *dupli_parent) return name; } -bool object_selected(Object *ob) +bool object_selected(const Base * const ob_base) { - return ob->flag & SELECT; -} - -bool parent_selected(Object *ob) -{ - if (object_selected(ob)) { - return true; - } - - bool do_export = false; - - Object *parent = ob->parent; - - while (parent != NULL) { - if (object_selected(parent)) { - do_export = true; - break; - } - - parent = parent->parent; - } - - return do_export; + return ob_base->flag & SELECT; } Imath::M44d convert_matrix(float mat[4][4]) diff --git a/source/blender/alembic/intern/abc_util.h b/source/blender/alembic/intern/abc_util.h index a7ac9df91c7..328f2c41a87 100644 --- a/source/blender/alembic/intern/abc_util.h +++ b/source/blender/alembic/intern/abc_util.h @@ -43,13 +43,13 @@ struct ImportSettings; struct ID; struct Object; +struct Base; std::string get_id_name(ID *id); std::string get_id_name(Object *ob); std::string get_object_dag_path_name(Object *ob, Object *dupli_parent); -bool object_selected(Object *ob); -bool parent_selected(Object *ob); +bool object_selected(const Base * const ob_base); Imath::M44d convert_matrix(float mat[4][4]); void create_transform_matrix(float r_mat[4][4]); diff --git a/source/blender/alembic/intern/alembic_capi.cc b/source/blender/alembic/intern/alembic_capi.cc index d8d017119b1..fcfe634924f 100644 --- a/source/blender/alembic/intern/alembic_capi.cc +++ b/source/blender/alembic/intern/alembic_capi.cc @@ -332,21 +332,37 @@ void ABC_export( BLI_strncpy(job->filename, filepath, 1024); job->settings.scene = job->scene; + + /* Sybren: for now we only export the active scene layer. + * Later in the 2.8 development process this may be replaced by using + * a specific collection for Alembic I/O, which can then be toggled + * between "real" objects and cached Alembic files. */ + job->settings.sl = CTX_data_scene_layer(C); + job->settings.frame_start = params->frame_start; job->settings.frame_end = params->frame_end; job->settings.frame_step_xform = params->frame_step_xform; job->settings.frame_step_shape = params->frame_step_shape; job->settings.shutter_open = params->shutter_open; job->settings.shutter_close = params->shutter_close; + + /* Sybren: For now this is ignored, until we can get selection + * detection working through Base pointers (instead of ob->flags). */ job->settings.selected_only = params->selected_only; + job->settings.export_face_sets = params->face_sets; job->settings.export_normals = params->normals; job->settings.export_uvs = params->uvs; job->settings.export_vcols = params->vcolors; job->settings.apply_subdiv = params->apply_subdiv; job->settings.flatten_hierarchy = params->flatten_hierarchy; + + /* Sybren: visible_layer & renderable only is ignored for now, + * to be replaced with collections later in the 2.8 dev process + * (also see note above). */ job->settings.visible_layers_only = params->visible_layers_only; job->settings.renderable_only = params->renderable_only; + job->settings.use_subdiv_schema = params->use_subdiv_schema; job->settings.export_ogawa = (params->compression_type == ABC_ARCHIVE_OGAWA); job->settings.pack_uv = params->packuv; diff --git a/source/blender/blenfont/BLF_api.h b/source/blender/blenfont/BLF_api.h index 1f38d64924c..1b967f889c0 100644 --- a/source/blender/blenfont/BLF_api.h +++ b/source/blender/blenfont/BLF_api.h @@ -34,6 +34,9 @@ #include "BLI_compiler_attrs.h" +/* enable this only if needed (unused circa 2016) */ +#define BLF_BLUR_ENABLE 0 + struct rctf; struct ColorManagedDisplay; struct ResultBLF; @@ -42,6 +45,7 @@ int BLF_init(int points, int dpi); void BLF_exit(void); void BLF_default_dpi(int dpi); void BLF_default_set(int fontid); +int BLF_default(void); /* get default font ID so we can pass it to other functions */ void BLF_cache_clear(void); @@ -61,6 +65,17 @@ void BLF_aspect(int fontid, float x, float y, float z); void BLF_position(int fontid, float x, float y, float z); void BLF_size(int fontid, int size, int dpi); +/* goal: small but useful color API */ +void BLF_color4ubv(int fontid, const unsigned char rgba[4]); +void BLF_color3ubv(int fontid, const unsigned char rgb[3]); +void BLF_color3ubv_alpha(int fontid, const unsigned char rgb[3], unsigned char alpha); +void BLF_color3ub(int fontid, unsigned char r, unsigned char g, unsigned char b); +void BLF_color4f(int fontid, float r, float g, float b, float a); +void BLF_color4fv(int fontid, const float rgba[4]); +void BLF_color3f(int fontid, float r, float g, float b); +void BLF_color3fv_alpha(int fontid, const float rgb[3], float alpha); +/* also available: UI_FontThemeColor(fontid, colorid) */ + /* Set a 4x4 matrix to be multiplied before draw the text. * Remember that you need call BLF_enable(BLF_MATRIX) * to enable this. @@ -122,29 +137,16 @@ void BLF_width_and_height(int fontid, const char *str, size_t len, float *r_widt */ float BLF_fixed_width(int fontid) ATTR_WARN_UNUSED_RESULT; -/* and this two function return the width and height - * of the string, using the default font and both value - * are multiplied by the aspect of the font. - */ -void BLF_width_and_height_default(const char *str, size_t len, float *r_width, float *r_height) ATTR_NONNULL(); -float BLF_width_default(const char *str, size_t len) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); -float BLF_height_default(const char *str, size_t len) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); - -/* Set rotation for default font. */ -void BLF_rotation_default(float angle); - -/* Enable/disable options to the default font. */ -void BLF_enable_default(int option); -void BLF_disable_default(int option); - /* By default, rotation and clipping are disable and * have to be enable/disable using BLF_enable/disable. */ void BLF_rotation(int fontid, float angle); void BLF_clipping(int fontid, float xmin, float ymin, float xmax, float ymax); -void BLF_clipping_default(float xmin, float ymin, float xmax, float ymax); void BLF_wordwrap(int fontid, int wrap_width); + +#if BLF_BLUR_ENABLE void BLF_blur(int fontid, int size); +#endif void BLF_enable(int fontid, int option); void BLF_disable(int fontid, int option); diff --git a/source/blender/blenfont/intern/blf.c b/source/blender/blenfont/intern/blf.c index 132a0ec3808..ab7c831f95c 100644 --- a/source/blender/blenfont/intern/blf.c +++ b/source/blender/blenfont/intern/blf.c @@ -50,13 +50,14 @@ #include "BLI_math.h" #include "BLI_threads.h" -#include "BIF_gl.h" #include "BLF_api.h" #include "IMB_colormanagement.h" #ifndef BLF_STANDALONE -#include "GPU_basic_shader.h" +#include "GPU_shader.h" +#include "GPU_matrix.h" +#include "GPU_immediate.h" #endif #include "blf_internal_types.h" @@ -174,6 +175,12 @@ void BLF_default_set(int fontid) } } +int BLF_default(void) +{ + ASSERT_DEFAULT_SET; + return global_font_default; +} + int BLF_load(const char *name) { FontBLF *font; @@ -357,24 +364,6 @@ void BLF_disable(int fontid, int option) } } -void BLF_enable_default(int option) -{ - FontBLF *font = blf_get(global_font_default); - - if (font) { - font->flags |= option; - } -} - -void BLF_disable_default(int option) -{ - FontBLF *font = blf_get(global_font_default); - - if (font) { - font->flags &= ~option; - } -} - void BLF_aspect(int fontid, float x, float y, float z) { FontBLF *font = blf_get(fontid); @@ -453,6 +442,7 @@ void BLF_size(int fontid, int size, int dpi) } } +#if BLF_BLUR_ENABLE void BLF_blur(int fontid, int size) { FontBLF *font = blf_get(fontid); @@ -461,6 +451,77 @@ void BLF_blur(int fontid, int size) font->blur = size; } } +#endif + +void BLF_color4ubv(int fontid, const unsigned char rgba[4]) +{ + FontBLF *font = blf_get(fontid); + + if (font) { + font->color[0] = rgba[0]; + font->color[1] = rgba[1]; + font->color[2] = rgba[2]; + font->color[3] = rgba[3]; + } +} + +void BLF_color3ubv_alpha(int fontid, const unsigned char rgb[3], unsigned char alpha) +{ + FontBLF *font = blf_get(fontid); + + if (font) { + font->color[0] = rgb[0]; + font->color[1] = rgb[1]; + font->color[2] = rgb[2]; + font->color[3] = alpha; + } +} + +void BLF_color3ubv(int fontid, const unsigned char rgb[3]) +{ + BLF_color3ubv_alpha(fontid, rgb, 255); +} + +void BLF_color3ub(int fontid, unsigned char r, unsigned char g, unsigned char b) +{ + FontBLF *font = blf_get(fontid); + + if (font) { + font->color[0] = r; + font->color[1] = g; + font->color[2] = b; + font->color[3] = 255; + } +} + +void BLF_color4fv(int fontid, const float rgba[4]) +{ + FontBLF *font = blf_get(fontid); + + if (font) { + rgba_float_to_uchar(font->color, rgba); + } +} + +void BLF_color4f(int fontid, float r, float g, float b, float a) +{ + float rgba[4] = { r, g, b, a }; + BLF_color4fv(fontid, rgba); +} + +void BLF_color3fv_alpha(int fontid, const float rgb[3], float alpha) +{ + float rgba[4]; + copy_v3_v3(rgba, rgb); + rgba[3] = alpha; + BLF_color4fv(fontid, rgba); +} + +void BLF_color3f(int fontid, float r, float g, float b) +{ + float rgba[4] = { r, g, b, 1.0f }; + BLF_color4fv(fontid, rgba); +} void BLF_draw_default(float x, float y, float z, const char *str, size_t len) { @@ -481,16 +542,7 @@ void BLF_draw_default_ascii(float x, float y, float z, const char *str, size_t l BLF_draw_ascii(global_font_default, str, len); /* XXX, use real length */ } -void BLF_rotation_default(float angle) -{ - FontBLF *font = blf_get(global_font_default); - - if (font) { - font->angle = angle; - } -} - -static void blf_draw_gl__start(FontBLF *font, GLint *mode) +static void blf_draw_gl__start(FontBLF *font) { /* * The pixmap alignment hack is handle @@ -500,52 +552,44 @@ static void blf_draw_gl__start(FontBLF *font, GLint *mode) glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); -#ifndef BLF_STANDALONE - GPU_basic_shader_bind(GPU_SHADER_TEXTURE_2D | GPU_SHADER_USE_COLOR); -#endif - - /* Save the current matrix mode. */ - glGetIntegerv(GL_MATRIX_MODE, mode); - - glMatrixMode(GL_TEXTURE); - glPushMatrix(); - glLoadIdentity(); - - glMatrixMode(GL_MODELVIEW); - glPushMatrix(); + gpuMatrixBegin3D_legacy(); if (font->flags & BLF_MATRIX) - glMultMatrixf(font->m); + gpuMultMatrix3D((float (*)[4])font->m); - glTranslate3fv(font->pos); + gpuTranslate3fv(font->pos); if (font->flags & BLF_ASPECT) - glScalef(font->aspect[0], font->aspect[1], font->aspect[2]); + gpuScale3fv(font->aspect); if (font->flags & BLF_ROTATION) /* radians -> degrees */ - glRotatef(font->angle * (float)(180.0 / M_PI), 0.0f, 0.0f, 1.0f); + gpuRotateAxis(RAD2DEG(font->angle), 'Z'); - if (font->shadow || font->blur) - glGetFloatv(GL_CURRENT_COLOR, font->orig_col); +#ifndef BLF_STANDALONE + VertexFormat *format = immVertexFormat(); + unsigned pos = add_attrib(format, "pos", GL_FLOAT, 2, KEEP_FLOAT); + unsigned texCoord = add_attrib(format, "texCoord", GL_FLOAT, 2, KEEP_FLOAT); + unsigned color = add_attrib(format, "color", GL_UNSIGNED_BYTE, 4, NORMALIZE_INT_TO_FLOAT); + + BLI_assert(pos == BLF_POS_ID); + BLI_assert(texCoord == BLF_COORD_ID); + BLI_assert(color == BLF_COLOR_ID); + + immBindBuiltinProgram(GPU_SHADER_TEXT); +#endif /* always bind the texture for the first glyph */ font->tex_bind_state = -1; } -static void blf_draw_gl__end(GLint mode) +static void blf_draw_gl__end(void) { - glMatrixMode(GL_TEXTURE); - glPopMatrix(); - - glMatrixMode(GL_MODELVIEW); - glPopMatrix(); - - if (mode != GL_MODELVIEW) - glMatrixMode(mode); + gpuMatrixEnd(); #ifndef BLF_STANDALONE - GPU_basic_shader_bind(GPU_SHADER_USE_COLOR); + immUnbindProgram(); #endif + glDisable(GL_BLEND); } @@ -554,23 +598,26 @@ void BLF_draw_ex( struct ResultBLF *r_info) { FontBLF *font = blf_get(fontid); - GLint mode; BLF_RESULT_CHECK_INIT(r_info); if (font && font->glyph_cache) { - blf_draw_gl__start(font, &mode); + blf_draw_gl__start(font); if (font->flags & BLF_WORD_WRAP) { blf_font_draw__wrap(font, str, len, r_info); } else { blf_font_draw(font, str, len, r_info); } - blf_draw_gl__end(mode); + blf_draw_gl__end(); } } void BLF_draw(int fontid, const char *str, size_t len) { + if (len == 0 || str[0] == '\0') { + return; + } + BLF_draw_ex(fontid, str, len, NULL); } @@ -579,12 +626,11 @@ void BLF_draw_ascii_ex( struct ResultBLF *r_info) { FontBLF *font = blf_get(fontid); - GLint mode; BLF_RESULT_CHECK_INIT(r_info); if (font && font->glyph_cache) { - blf_draw_gl__start(font, &mode); + blf_draw_gl__start(font); if (font->flags & BLF_WORD_WRAP) { /* use non-ascii draw function for word-wrap */ blf_font_draw__wrap(font, str, len, r_info); @@ -592,24 +638,31 @@ void BLF_draw_ascii_ex( else { blf_font_draw_ascii(font, str, len, r_info); } - blf_draw_gl__end(mode); + blf_draw_gl__end(); } } void BLF_draw_ascii(int fontid, const char *str, size_t len) { + if (len == 0 || str[0] == '\0') { + return; + } + BLF_draw_ascii_ex(fontid, str, len, NULL); } int BLF_draw_mono(int fontid, const char *str, size_t len, int cwidth) { + if (len == 0 || str[0] == '\0') { + return 0; + } + FontBLF *font = blf_get(fontid); - GLint mode; int columns = 0; if (font && font->glyph_cache) { - blf_draw_gl__start(font, &mode); + blf_draw_gl__start(font); columns = blf_font_draw_mono(font, str, len, cwidth); - blf_draw_gl__end(mode); + blf_draw_gl__end(); } return columns; @@ -689,14 +742,6 @@ void BLF_width_and_height(int fontid, const char *str, size_t len, float *r_widt } } -void BLF_width_and_height_default(const char *str, size_t len, float *r_width, float *r_height) -{ - ASSERT_DEFAULT_SET; - - BLF_size(global_font_default, global_font_points, global_font_dpi); - BLF_width_and_height(global_font_default, str, len, r_width, r_height); -} - float BLF_width_ex( int fontid, const char *str, size_t len, struct ResultBLF *r_info) @@ -727,14 +772,6 @@ float BLF_fixed_width(int fontid) return 0.0f; } -float BLF_width_default(const char *str, size_t len) -{ - ASSERT_DEFAULT_SET; - - BLF_size(global_font_default, global_font_points, global_font_dpi); - return BLF_width(global_font_default, str, len); -} - float BLF_height_ex( int fontid, const char *str, size_t len, struct ResultBLF *r_info) @@ -798,15 +835,6 @@ float BLF_ascender(int fontid) return 0.0f; } -float BLF_height_default(const char *str, size_t len) -{ - ASSERT_DEFAULT_SET; - - BLF_size(global_font_default, global_font_points, global_font_dpi); - - return BLF_height(global_font_default, str, len); -} - void BLF_rotation(int fontid, float angle) { FontBLF *font = blf_get(fontid); @@ -828,18 +856,6 @@ void BLF_clipping(int fontid, float xmin, float ymin, float xmax, float ymax) } } -void BLF_clipping_default(float xmin, float ymin, float xmax, float ymax) -{ - FontBLF *font = blf_get(global_font_default); - - if (font) { - font->clip_rec.xmin = xmin; - font->clip_rec.ymin = ymin; - font->clip_rec.xmax = xmax; - font->clip_rec.ymax = ymax; - } -} - void BLF_wordwrap(int fontid, int wrap_width) { FontBLF *font = blf_get(fontid); @@ -855,7 +871,7 @@ void BLF_shadow(int fontid, int level, const float rgba[4]) if (font) { font->shadow = level; - copy_v4_v4(font->shadow_col, rgba); + rgba_float_to_uchar(font->shadow_color, rgba); } } diff --git a/source/blender/blenfont/intern/blf_font.c b/source/blender/blenfont/intern/blf_font.c index 44a1d08f1fd..d0293eccf3a 100644 --- a/source/blender/blenfont/intern/blf_font.c +++ b/source/blender/blenfont/intern/blf_font.c @@ -58,6 +58,8 @@ #include "BIF_gl.h" #include "BLF_api.h" +#include "GPU_immediate.h" + #include "blf_internal_types.h" #include "blf_internal.h" @@ -172,6 +174,23 @@ static void blf_font_ensure_ascii_table(FontBLF *font) } \ } (void)0 +static unsigned verts_needed(const FontBLF *font, const char *str, size_t len) +{ + unsigned length = (unsigned)((len == INT_MAX) ? strlen(str) : len); + unsigned quad_ct = 1; + + if (font->flags & BLF_SHADOW) { + if (font->shadow == 0) + quad_ct += 1; + if (font->shadow <= 4) + quad_ct += 9; /* 3x3 kernel */ + else + quad_ct += 25; /* 5x5 kernel */ + } + + return length * quad_ct * 4; +} + static void blf_font_draw_ex( FontBLF *font, const char *str, size_t len, struct ResultBLF *r_info, int pen_y) @@ -187,6 +206,9 @@ static void blf_font_draw_ex( blf_font_ensure_ascii_table(font); + immBeginAtMost(GL_QUADS, verts_needed(font, str, len)); + /* at most because some glyphs might be clipped & not drawn */ + while ((i < len) && str[i]) { BLF_UTF8_NEXT_FAST(font, g, str, i, c, glyph_ascii_table); @@ -204,6 +226,8 @@ static void blf_font_draw_ex( g_prev = g; } + immEnd(); + if (r_info) { r_info->lines = 1; r_info->width = pen_x; @@ -229,6 +253,8 @@ static void blf_font_draw_ascii_ex( blf_font_ensure_ascii_table(font); + immBeginAtMost(GL_QUADS, verts_needed(font, str, len)); + while ((c = *(str++)) && len--) { BLI_assert(c < 128); if ((g = glyph_ascii_table[c]) == NULL) @@ -243,6 +269,8 @@ static void blf_font_draw_ascii_ex( g_prev = g; } + immEnd(); + if (r_info) { r_info->lines = 1; r_info->width = pen_x; @@ -265,6 +293,8 @@ int blf_font_draw_mono(FontBLF *font, const char *str, size_t len, int cwidth) blf_font_ensure_ascii_table(font); + immBeginAtMost(GL_QUADS, verts_needed(font, str, len)); + while ((i < len) && str[i]) { BLF_UTF8_NEXT_FAST(font, g, str, i, c, glyph_ascii_table); @@ -284,6 +314,8 @@ int blf_font_draw_mono(FontBLF *font, const char *str, size_t len, int cwidth) pen_x += cwidth * col; } + immEnd(); + return columns; } @@ -901,8 +933,6 @@ void blf_font_free(FontBLF *font) static void blf_font_fill(FontBLF *font) { - unsigned int i; - font->aspect[0] = 1.0f; font->aspect[1] = 1.0f; font->aspect[2] = 1.0f; @@ -910,9 +940,15 @@ static void blf_font_fill(FontBLF *font) font->pos[1] = 0.0f; font->angle = 0.0f; - for (i = 0; i < 16; i++) + for (int i = 0; i < 16; i++) font->m[i] = 0; + /* annoying bright color so we can see where to add BLF_color calls */ + font->color[0] = 255; + font->color[1] = 255; + font->color[2] = 0; + font->color[3] = 255; + font->clip_rec.xmin = 0.0f; font->clip_rec.xmax = 0.0f; font->clip_rec.ymin = 0.0f; @@ -922,7 +958,9 @@ static void blf_font_fill(FontBLF *font) font->size = 0; BLI_listbase_clear(&font->cache); font->glyph_cache = NULL; +#if BLF_BLUR_ENABLE font->blur = 0; +#endif font->max_tex_size = -1; font->buf_info.fbuf = NULL; diff --git a/source/blender/blenfont/intern/blf_glyph.c b/source/blender/blenfont/intern/blf_glyph.c index aa7d539538b..b1bab13f3ae 100644 --- a/source/blender/blenfont/intern/blf_glyph.c +++ b/source/blender/blenfont/intern/blf_glyph.c @@ -56,7 +56,7 @@ #include "BLF_api.h" #ifndef BLF_STANDALONE -#include "GPU_basic_shader.h" +#include "GPU_immediate.h" #endif #include "blf_internal_types.h" @@ -182,17 +182,6 @@ static void blf_glyph_cache_texture(FontBLF *font, GlyphCacheBLF *gc) glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - -#ifndef BLF_STANDALONE - /* needed since basic shader doesn't support alpha-only textures, - * while we could add support this is only used in a few places - * (an alternative could be to have a simple shader for BLF). */ - if (GLEW_ARB_texture_swizzle && GPU_basic_shader_use_glsl_get()) { - GLint swizzle_mask[] = {GL_ONE, GL_ONE, GL_ONE, GL_ALPHA}; - glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_RGBA, swizzle_mask); - } -#endif - glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA8, gc->p2_width, gc->p2_height, 0, GL_ALPHA, GL_UNSIGNED_BYTE, NULL); } @@ -326,73 +315,73 @@ void blf_glyph_free(GlyphBLF *g) MEM_freeN(g); } -static void blf_texture_draw(float uv[2][2], float dx, float y1, float dx1, float y2) +static void blf_texture_draw(const unsigned char color[4], float uv[2][2], float dx, float y1, float dx1, float y2) { - glBegin(GL_QUADS); - glTexCoord2f(uv[0][0], uv[0][1]); - glVertex2f(dx, y1); - - glTexCoord2f(uv[0][0], uv[1][1]); - glVertex2f(dx, y2); - - glTexCoord2f(uv[1][0], uv[1][1]); - glVertex2f(dx1, y2); - - glTexCoord2f(uv[1][0], uv[0][1]); - glVertex2f(dx1, y1); - glEnd(); + immAttrib2f(BLF_COORD_ID, uv[0][0], uv[0][1]); + immSkipAttrib(BLF_COLOR_ID); /* skip color of most vertices */ + immVertex2f(BLF_POS_ID, dx, y1); + + immAttrib2f(BLF_COORD_ID, uv[0][0], uv[1][1]); + immSkipAttrib(BLF_COLOR_ID); + immVertex2f(BLF_POS_ID, dx, y2); + + immAttrib2f(BLF_COORD_ID, uv[1][0], uv[1][1]); + immSkipAttrib(BLF_COLOR_ID); + immVertex2f(BLF_POS_ID, dx1, y2); + + immAttrib2f(BLF_COORD_ID, uv[1][0], uv[0][1]); + immAttrib4ubv(BLF_COLOR_ID, color); /* set color of provoking vertex */ + immVertex2f(BLF_POS_ID, dx1, y1); } -static void blf_texture5_draw(const float shadow_col[4], float uv[2][2], float x1, float y1, float x2, float y2) +static void blf_texture5_draw(const unsigned char color_in[4], float uv[2][2], float x1, float y1, float x2, float y2) { const float soft[25] = {1 / 60.0f, 1 / 60.0f, 2 / 60.0f, 1 / 60.0f, 1 / 60.0f, 1 / 60.0f, 3 / 60.0f, 5 / 60.0f, 3 / 60.0f, 1 / 60.0f, 2 / 60.0f, 5 / 60.0f, 8 / 60.0f, 5 / 60.0f, 2 / 60.0f, 1 / 60.0f, 3 / 60.0f, 5 / 60.0f, 3 / 60.0f, 1 / 60.0f, 1 / 60.0f, 1 / 60.0f, 2 / 60.0f, 1 / 60.0f, 1 / 60.0f}; - + const float *fp = soft; - float color[4]; + unsigned char color[4]; float dx, dy; - color[0] = shadow_col[0]; - color[1] = shadow_col[1]; - color[2] = shadow_col[2]; - + color[0] = color_in[0]; + color[1] = color_in[1]; + color[2] = color_in[2]; + + const float alpha_in = (1 / 255.0f) * color_in[3]; + for (dx = -2; dx < 3; dx++) { for (dy = -2; dy < 3; dy++, fp++) { - color[3] = *(fp) * shadow_col[3]; - glColor4fv(color); - blf_texture_draw(uv, x1 + dx, y1 + dy, x2 + dx, y2 + dy); + color[3] = FTOCHAR(*fp * alpha_in); + blf_texture_draw(color, uv, x1 + dx, y1 + dy, x2 + dx, y2 + dy); } } - - glColor4fv(color); } -static void blf_texture3_draw(const float shadow_col[4], float uv[2][2], float x1, float y1, float x2, float y2) +static void blf_texture3_draw(const unsigned char color_in[4], float uv[2][2], float x1, float y1, float x2, float y2) { const float soft[9] = {1 / 16.0f, 2 / 16.0f, 1 / 16.0f, 2 / 16.0f, 4 / 16.0f, 2 / 16.0f, 1 / 16.0f, 2 / 16.0f, 1 / 16.0f}; const float *fp = soft; - float color[4]; + unsigned char color[4]; float dx, dy; - color[0] = shadow_col[0]; - color[1] = shadow_col[1]; - color[2] = shadow_col[2]; + color[0] = color_in[0]; + color[1] = color_in[1]; + color[2] = color_in[2]; + + const float alpha_in = (1 / 255.0f) * color_in[3]; for (dx = -1; dx < 2; dx++) { for (dy = -1; dy < 2; dy++, fp++) { - color[3] = *(fp) * shadow_col[3]; - glColor4fv(color); - blf_texture_draw(uv, x1 + dx, y1 + dy, x2 + dx, y2 + dy); + color[3] = FTOCHAR(*fp * alpha_in); + blf_texture_draw(color, uv, x1 + dx, y1 + dy, x2 + dx, y2 + dy); } } - - glColor4fv(color); } static void blf_glyph_calc_rect(rctf *rect, GlyphBLF *g, float x, float y) @@ -486,39 +475,37 @@ void blf_glyph_render(FontBLF *font, GlyphBLF *g, float x, float y) glBindTexture(GL_TEXTURE_2D, (font->tex_bind_state = g->tex)); } + /* TODO: blur & shadow in shader, single quad per glyph */ + if (font->flags & BLF_SHADOW) { rctf rect_ofs; blf_glyph_calc_rect(&rect_ofs, g, x + (float)font->shadow_x, y + (float)font->shadow_y); - switch (font->shadow) { - case 3: - blf_texture3_draw(font->shadow_col, g->uv, rect_ofs.xmin, rect_ofs.ymin, rect_ofs.xmax, rect_ofs.ymax); - break; - case 5: - blf_texture5_draw(font->shadow_col, g->uv, rect_ofs.xmin, rect_ofs.ymin, rect_ofs.xmax, rect_ofs.ymax); - break; - default: - glColor4fv(font->shadow_col); - blf_texture_draw(g->uv, rect_ofs.xmin, rect_ofs.ymin, rect_ofs.xmax, rect_ofs.ymax); - break; + if (font->shadow == 0) { + blf_texture_draw(font->shadow_color, g->uv, rect_ofs.xmin, rect_ofs.ymin, rect_ofs.xmax, rect_ofs.ymax); + } + else if (font->shadow <= 4) { + blf_texture3_draw(font->shadow_color, g->uv, rect_ofs.xmin, rect_ofs.ymin, rect_ofs.xmax, rect_ofs.ymax); + } + else { + blf_texture5_draw(font->shadow_color, g->uv, rect_ofs.xmin, rect_ofs.ymin, rect_ofs.xmax, rect_ofs.ymax); } - - glColor4fv(font->orig_col); } +#if BLF_BLUR_ENABLE switch (font->blur) { case 3: - blf_texture3_draw(font->orig_col, g->uv, rect.xmin, rect.ymin, rect.xmax, rect.ymax); + blf_texture3_draw(font->color, g->uv, rect.xmin, rect.ymin, rect.xmax, rect.ymax); break; case 5: - blf_texture5_draw(font->orig_col, g->uv, rect.xmin, rect.ymin, rect.xmax, rect.ymax); + blf_texture5_draw(font->color, g->uv, rect.xmin, rect.ymin, rect.xmax, rect.ymax); break; default: - blf_texture_draw(g->uv, rect.xmin, rect.ymin, rect.xmax, rect.ymax); - break; + blf_texture_draw(font->color, g->uv, rect.xmin, rect.ymin, rect.xmax, rect.ymax); } - - return; +#else + blf_texture_draw(font->color, g->uv, rect.xmin, rect.ymin, rect.xmax, rect.ymax); +#endif } diff --git a/source/blender/blenfont/intern/blf_internal.h b/source/blender/blenfont/intern/blf_internal.h index d9d758ce548..ba17e050399 100644 --- a/source/blender/blenfont/intern/blf_internal.h +++ b/source/blender/blenfont/intern/blf_internal.h @@ -37,6 +37,11 @@ struct GlyphBLF; struct GlyphCacheBLF; struct rctf; +/* vertex attribute IDs (fixed IDs so we don't have to pass them around) */ +#define BLF_POS_ID 0 +#define BLF_COORD_ID 1 +#define BLF_COLOR_ID 2 + unsigned int blf_next_p2(unsigned int x); unsigned int blf_hash(unsigned int val); diff --git a/source/blender/blenfont/intern/blf_internal_types.h b/source/blender/blenfont/intern/blf_internal_types.h index 0fac576a8cc..9164a02b2cc 100644 --- a/source/blender/blenfont/intern/blf_internal_types.h +++ b/source/blender/blenfont/intern/blf_internal_types.h @@ -175,8 +175,10 @@ typedef struct FontBLF { /* angle in radians. */ float angle; +#if 0 /* BLF_BLUR_ENABLE */ /* blur: 3 or 5 large kernel */ int blur; +#endif /* shadow level. */ int shadow; @@ -186,10 +188,10 @@ typedef struct FontBLF { int shadow_y; /* shadow color. */ - float shadow_col[4]; + unsigned char shadow_color[4]; - /* store color here when drawing shadow or blur. */ - float orig_col[4]; + /* main text color. */ + unsigned char color[4]; /* Multiplied this matrix with the current one before * draw the text! see blf_draw__start. diff --git a/source/blender/blenkernel/BKE_armature.h b/source/blender/blenkernel/BKE_armature.h index 78d6f6c7cb9..c2323100205 100644 --- a/source/blender/blenkernel/BKE_armature.h +++ b/source/blender/blenkernel/BKE_armature.h @@ -97,7 +97,6 @@ void BKE_armature_where_is(struct bArmature *arm); void BKE_armature_where_is_bone(struct Bone *bone, struct Bone *prevbone, const bool use_recursion); void BKE_pose_clear_pointers(struct bPose *pose); void BKE_pose_rebuild(struct Object *ob, struct bArmature *arm); -void BKE_pose_rebuild_ex(struct Object *ob, struct bArmature *arm, const bool sort_bones); void BKE_pose_where_is(struct Scene *scene, struct Object *ob); void BKE_pose_where_is_bone(struct Scene *scene, struct Object *ob, struct bPoseChannel *pchan, float ctime, bool do_extra); void BKE_pose_where_is_bone_tail(struct bPoseChannel *pchan); diff --git a/source/blender/blenkernel/BKE_collection.h b/source/blender/blenkernel/BKE_collection.h new file mode 100644 index 00000000000..644bcef6226 --- /dev/null +++ b/source/blender/blenkernel/BKE_collection.h @@ -0,0 +1,91 @@ +/* + * ***** 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. + * + * Contributor(s): Dalai Felinto + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#ifndef __BKE_COLLECTION_H__ +#define __BKE_COLLECTION_H__ + +/** \file blender/blenkernel/BKE_collection.h + * \ingroup bke + */ + +#include "BLI_ghash.h" +#include "BLI_iterator.h" +#include "DNA_listBase.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct Iterator; +struct SceneCollection; +struct Object; +struct Base; +struct Main; +struct Scene; + +struct SceneCollection *BKE_collection_add(struct Scene *scene, struct SceneCollection *sc_parent, const char *name); +bool BKE_collection_remove(struct Scene *scene, struct SceneCollection *sc); +struct SceneCollection *BKE_collection_master(const struct Scene *scene); +void BKE_collection_master_free(struct Scene *scene); +void BKE_collection_object_add(struct Scene *scene, struct SceneCollection *sc, struct Object *object); +void BKE_collection_object_add_from(struct Scene *scene, struct Object *ob_src, struct Object *ob_dst); +void BKE_collection_object_remove(struct Main *bmain, struct Scene *scene, struct SceneCollection *sc, struct Object *object, const bool free_us); +void BKE_collections_object_remove(struct Main *bmain, struct Scene *scene, struct Object *object, const bool free_us); + +typedef void (*BKE_scene_objects_Cb)(struct Object *ob, void *data); +typedef void (*BKE_scene_collections_Cb)(struct SceneCollection *ob, void *data); + +void BKE_scene_collections_callback(struct Scene *scene, BKE_scene_collections_Cb callback, void *data); +void BKE_scene_objects_callback(struct Scene *scene, BKE_scene_objects_Cb callback, void *data); + +/* iterators */ +void BKE_scene_collections_Iterator_begin(struct Iterator *iter, void *data_in); +void BKE_scene_collections_Iterator_next(struct Iterator *iter); +void BKE_scene_collections_Iterator_end(struct Iterator *iter); + +void BKE_scene_objects_Iterator_begin(struct Iterator *iter, void *data_in); +void BKE_scene_objects_Iterator_next(struct Iterator *iter); +void BKE_scene_objects_Iterator_end(struct Iterator *iter); + +#define FOREACH_SCENE_COLLECTION(scene, _instance) \ + ITER_BEGIN(BKE_scene_collections_Iterator_begin, \ + BKE_scene_collections_Iterator_next, \ + BKE_scene_collections_Iterator_end, \ + scene, SceneCollection *, _instance) + +#define FOREACH_SCENE_COLLECTION_END \ + ITER_END + +#define FOREACH_SCENE_OBJECT(scene, _instance) \ + ITER_BEGIN(BKE_scene_objects_Iterator_begin, \ + BKE_scene_objects_Iterator_next, \ + BKE_scene_objects_Iterator_end, \ + scene, Object *, _instance) + +#define FOREACH_SCENE_OBJECT_END \ + ITER_END + +#ifdef __cplusplus +} +#endif + +#endif /* __BKE_COLLECTION_H__ */ diff --git a/source/blender/blenkernel/BKE_context.h b/source/blender/blenkernel/BKE_context.h index 4da6a61cbfa..606b045dff8 100644 --- a/source/blender/blenkernel/BKE_context.h +++ b/source/blender/blenkernel/BKE_context.h @@ -40,12 +40,16 @@ extern "C" { struct ARegion; struct bScreen; struct CacheFile; +struct LayerCollection; struct ListBase; struct Main; struct Object; +struct Base; struct PointerRNA; struct ReportList; struct Scene; +struct SceneCollection; +struct SceneLayer; struct ScrArea; struct SpaceLink; struct View3D; @@ -239,6 +243,9 @@ int ctx_data_list_count(const bContext *C, int (*func)(const bContext *, ListBas struct Main *CTX_data_main(const bContext *C); struct Scene *CTX_data_scene(const bContext *C); +struct LayerCollection *CTX_data_layer_collection(const bContext *C); +struct SceneCollection *CTX_data_scene_collection(const bContext *C); +struct SceneLayer *CTX_data_scene_layer(const bContext *C); struct ToolSettings *CTX_data_tool_settings(const bContext *C); const char *CTX_data_mode_string(const bContext *C); diff --git a/source/blender/blenkernel/BKE_group.h b/source/blender/blenkernel/BKE_group.h index 09a069ee36f..f718e9c8555 100644 --- a/source/blender/blenkernel/BKE_group.h +++ b/source/blender/blenkernel/BKE_group.h @@ -33,6 +33,7 @@ * \author nzc */ +struct BaseLegacy; struct Base; struct EvaluationContext; struct Group; @@ -44,8 +45,8 @@ void BKE_group_free(struct Group *group); struct Group *BKE_group_add(struct Main *bmain, const char *name); struct Group *BKE_group_copy(struct Main *bmain, struct Group *group); void BKE_group_make_local(struct Main *bmain, struct Group *group, const bool lib_local); -bool BKE_group_object_add(struct Group *group, struct Object *ob, struct Scene *scene, struct Base *base); -bool BKE_group_object_unlink(struct Group *group, struct Object *ob, struct Scene *scene, struct Base *base); +bool BKE_group_object_add(struct Group *group, struct Object *ob); +bool BKE_group_object_unlink(struct Group *group, struct Object *ob); struct Group *BKE_group_object_find(struct Group *group, struct Object *ob); bool BKE_group_object_exists(struct Group *group, struct Object *ob); bool BKE_group_object_cyclic_check(struct Main *bmain, struct Object *object, struct Group *group); diff --git a/source/blender/blenkernel/BKE_layer.h b/source/blender/blenkernel/BKE_layer.h new file mode 100644 index 00000000000..d208cee5b4b --- /dev/null +++ b/source/blender/blenkernel/BKE_layer.h @@ -0,0 +1,238 @@ +/* + * ***** 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. + * + * Contributor(s): Blender Foundation, Dalai Felinto + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#ifndef __BKE_LAYER_H__ +#define __BKE_LAYER_H__ + +/** \file blender/blenkernel/BKE_layer.h + * \ingroup bke + */ + +#include "BKE_collection.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define TODO_LAYER_SYNC /* syncing of SceneCollection and LayerCollection trees*/ +#define TODO_LAYER_SYNC_FILTER /* syncing of filter_objects across all trees */ +#define TODO_LAYER_OVERRIDE /* CollectionOverride */ +#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 CollectionEngineSettings; +struct LayerCollection; +struct ID; +struct ListBase; +struct Main; +struct Object; +struct Base; +struct RenderEngine; +struct Scene; +struct SceneCollection; +struct SceneLayer; + +struct SceneLayer *BKE_scene_layer_render_active(const struct Scene *scene); +struct SceneLayer *BKE_scene_layer_context_active(struct Scene *scene); +struct SceneLayer *BKE_scene_layer_add(struct Scene *scene, const char *name); + +bool BKE_scene_layer_remove(struct Main *bmain, struct Scene *scene, struct SceneLayer *sl); + +void BKE_scene_layer_free(struct SceneLayer *sl); + +void BKE_scene_layer_engine_set(struct SceneLayer *sl, const char *engine); + +void BKE_scene_layer_selected_objects_tag(struct SceneLayer *sl, const int tag); + +struct SceneLayer *BKE_scene_layer_find_from_collection(struct Scene *scene, struct LayerCollection *lc); +struct Base *BKE_scene_layer_base_find(struct SceneLayer *sl, struct Object *ob); +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_object_recalculate(struct SceneLayer *sl, struct Object *ob); +void BKE_scene_layer_engine_settings_collection_recalculate(struct SceneLayer *sl, struct LayerCollection *lc); +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); + +int BKE_layer_collection_count(struct SceneLayer *sl); + +int BKE_layer_collection_findindex(struct SceneLayer *sl, struct LayerCollection *lc); +void BKE_layer_collection_reinsert_after(const struct Scene *scene, struct SceneLayer *sl, + struct LayerCollection *lc_reinsert, struct LayerCollection *lc_after); + +struct LayerCollection *BKE_collection_link(struct SceneLayer *sl, struct SceneCollection *sc); + +void BKE_collection_unlink(struct SceneLayer *sl, struct LayerCollection *lc); + +bool BKE_scene_layer_has_collection(struct SceneLayer *sl, struct SceneCollection *sc); +bool BKE_scene_has_object(struct Scene *scene, struct Object *ob); + +/* syncing */ + +void BKE_layer_sync_new_scene_collection(struct Scene *scene, const struct SceneCollection *sc_parent, struct SceneCollection *sc); +void BKE_layer_sync_object_link(struct Scene *scene, struct SceneCollection *sc, struct Object *ob); +void BKE_layer_sync_object_unlink(struct Scene *scene, struct SceneCollection *sc, struct Object *ob); + +/* override */ + +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 int type, const char *engine_name); +struct CollectionEngineSettings *BKE_object_collection_engine_get(struct Object *ob, const int type, 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); + +struct CollectionEngineSettings *BKE_layer_collection_engine_settings_create(const char *engine_name); +void BKE_layer_collection_engine_settings_free(struct CollectionEngineSettings *ces); +void BKE_layer_collection_engine_settings_list_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); +void BKE_collection_engine_property_add_bool(struct CollectionEngineSettings *ces, const char *name, bool 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); +bool BKE_collection_engine_property_value_get_bool(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); +void BKE_collection_engine_property_value_set_bool(struct CollectionEngineSettings *ces, const char *name, bool 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); +void BKE_selected_objects_Iterator_next(Iterator *iter); +void BKE_selected_objects_Iterator_end(Iterator *iter); + +void BKE_visible_objects_Iterator_begin(Iterator *iter, void *data_in); +void BKE_visible_objects_Iterator_next(Iterator *iter); +void BKE_visible_objects_Iterator_end(Iterator *iter); + +void BKE_visible_bases_Iterator_begin(Iterator *iter, void *data_in); +void BKE_visible_bases_Iterator_next(Iterator *iter); +void BKE_visible_bases_Iterator_end(Iterator *iter); + +#define FOREACH_SELECTED_OBJECT(sl, _instance) \ + ITER_BEGIN(BKE_selected_objects_Iterator_begin, \ + BKE_selected_objects_Iterator_next, \ + BKE_selected_objects_Iterator_end, \ + sl, Object *, _instance) + +#define FOREACH_SELECTED_OBJECT_END \ + ITER_END + +#define FOREACH_VISIBLE_OBJECT(sl, _instance) \ + ITER_BEGIN(BKE_visible_objects_Iterator_begin, \ + BKE_visible_objects_Iterator_next, \ + BKE_visible_objects_Iterator_end, \ + sl, Object *, _instance) + +#define FOREACH_VISIBLE_OBJECT_END \ + ITER_END + + +#define FOREACH_VISIBLE_BASE(sl, _instance) \ + ITER_BEGIN(BKE_visible_bases_Iterator_begin, \ + BKE_visible_bases_Iterator_next, \ + BKE_visible_bases_Iterator_end, \ + sl, Base *, _instance) + +#define FOREACH_VISIBLE_BASE_END \ + ITER_END + + +#define FOREACH_OBJECT(sl, _instance) \ +{ \ + Object *_instance; \ + Base *base; \ + for (base = (sl)->object_bases.first; base; base = base->next) { \ + _instance = base->object; + +#define FOREACH_OBJECT_END \ + } \ +} + +#define FOREACH_OBJECT_FLAG(scene, sl, flag, _instance) \ +{ \ + IteratorBeginCb func_begin; \ + IteratorCb func_next, func_end; \ + void *data_in; \ + \ + if (flag == SELECT) { \ + func_begin = &BKE_selected_objects_Iterator_begin; \ + func_next = &BKE_selected_objects_Iterator_next; \ + func_end = &BKE_selected_objects_Iterator_end; \ + data_in = (sl); \ + } \ + else { \ + func_begin = BKE_scene_objects_Iterator_begin; \ + func_next = BKE_scene_objects_Iterator_next; \ + func_end = BKE_scene_objects_Iterator_end; \ + data_in = (scene); \ + } \ + ITER_BEGIN(func_begin, func_next, func_end, data_in, Object *, _instance) + + +#define FOREACH_OBJECT_FLAG_END \ + ITER_END \ +} + +/* temporary hacky solution waiting for final depsgraph evaluation */ +#define DEG_OBJECT_ITER(sl_, instance_) \ +{ \ + Object *instance_; \ + /* 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) { \ + if ((base_->flag & BASE_VISIBLED) == 0) { \ + continue; \ + } \ + \ + instance_ = base_->object; \ + instance_->base_flag = base_->flag; + +#define DEG_OBJECT_ITER_END \ + } \ +} + +/* temporary doversion functions */ +void BKE_scene_layer_doversion_update(struct Main *bmain); + +#ifdef __cplusplus +} +#endif + +#endif /* __BKE_LAYER_H__ */ diff --git a/source/blender/blenkernel/BKE_mesh_render.h b/source/blender/blenkernel/BKE_mesh_render.h new file mode 100644 index 00000000000..0538bac2dc2 --- /dev/null +++ b/source/blender/blenkernel/BKE_mesh_render.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) 2017 by Blender Foundation. + * All rights reserved. + * + * Contributor(s): Blender Foundation, Mike Erwin, Dalai Felinto + * + * ***** END GPL LICENSE BLOCK ***** + */ +#ifndef __BKE_MESH_RENDER_H__ +#define __BKE_MESH_RENDER_H__ + +/** \file BKE_mesh_render.h + * \ingroup bke + */ + +struct Batch; +struct Mesh; + +void BKE_mesh_batch_cache_dirty(struct Mesh *me); +void BKE_mesh_batch_cache_free(struct Mesh *me); +struct Batch *BKE_mesh_batch_cache_get_all_edges(struct Mesh *me); +struct Batch *BKE_mesh_batch_cache_get_all_triangles(struct Mesh *me); +struct Batch *BKE_mesh_batch_cache_get_triangles_with_normals(struct Mesh *me); +struct Batch *BKE_mesh_batch_cache_get_all_verts(struct Mesh *me); +struct Batch *BKE_mesh_batch_cache_get_fancy_edges(struct Mesh *me); +struct Batch *BKE_mesh_batch_cache_get_overlay_edges(struct Mesh *me); + +#endif /* __BKE_MESH_RENDER_H__ */ diff --git a/source/blender/blenkernel/BKE_modifier.h b/source/blender/blenkernel/BKE_modifier.h index b241b5ca5b7..7a522cba282 100644 --- a/source/blender/blenkernel/BKE_modifier.h +++ b/source/blender/blenkernel/BKE_modifier.h @@ -260,15 +260,6 @@ typedef struct ModifierTypeInfo { */ bool (*isDisabled)(struct ModifierData *md, int userRenderParams); - /* Add the appropriate relations to the DEP graph depending on the - * modifier data. - * - * This function is optional. - */ - void (*updateDepgraph)(struct ModifierData *md, struct DagForest *forest, - struct Main *bmain, struct Scene *scene, - struct Object *ob, struct DagNode *obNode); - /* Add the appropriate relations to the dependency graph. * * This function is optional. diff --git a/source/blender/blenkernel/BKE_node.h b/source/blender/blenkernel/BKE_node.h index 546f0d97c2b..67f7fa5e029 100644 --- a/source/blender/blenkernel/BKE_node.h +++ b/source/blender/blenkernel/BKE_node.h @@ -687,6 +687,13 @@ bool BKE_node_tree_iter_step(struct NodeTreeIterStore *ntreeiter, } /** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Node Tree + */ + +void BKE_nodetree_remove_layer_n(struct bNodeTree *ntree, struct Scene *scene, const int layer_index); + /* -------------------------------------------------------------------- */ /** \name Shader Nodes */ diff --git a/source/blender/blenkernel/BKE_object.h b/source/blender/blenkernel/BKE_object.h index 89adbc4338f..b3b67d0924a 100644 --- a/source/blender/blenkernel/BKE_object.h +++ b/source/blender/blenkernel/BKE_object.h @@ -35,12 +35,13 @@ extern "C" { #include "BLI_compiler_attrs.h" -struct Base; +struct BaseLegacy; struct EvaluationContext; struct Scene; struct Object; struct BoundBox; struct View3D; +struct SceneLayer; struct SoftBody; struct BulletSoftBody; struct MovieClip; @@ -89,9 +90,9 @@ struct Object *BKE_object_add_only_object( int type, const char *name) ATTR_NONNULL(1) ATTR_RETURNS_NONNULL; struct Object *BKE_object_add( - struct Main *bmain, struct Scene *scene, + struct Main *bmain, struct Scene *scene, struct SceneLayer *sl, int type, const char *name) - ATTR_NONNULL(1, 2) ATTR_RETURNS_NONNULL; + ATTR_NONNULL(1, 2, 3) ATTR_RETURNS_NONNULL; void *BKE_object_obdata_add_from_type( struct Main *bmain, int type, const char *name) @@ -199,6 +200,7 @@ void BKE_object_eval_uber_transform(struct EvaluationContext *eval_ctx, void BKE_object_eval_uber_data(struct EvaluationContext *eval_ctx, struct Scene *scene, struct Object *ob); +void BKE_object_eval_shading(struct EvaluationContext *eval_ctx, struct Object *ob); void BKE_object_handle_data_update(struct EvaluationContext *eval_ctx, struct Scene *scene, @@ -252,7 +254,7 @@ typedef enum eObjectSet { struct LinkNode *BKE_object_relational_superset(struct Scene *scene, eObjectSet objectSet, eObRelationTypes includeFilter); struct LinkNode *BKE_object_groups(struct Object *ob); -void BKE_object_groups_clear(struct Scene *scene, struct Base *base, struct Object *object); +void BKE_object_groups_clear(struct Object *object); struct KDTree *BKE_object_as_kdtree(struct Object *ob, int *r_tot); diff --git a/source/blender/blenkernel/BKE_scene.h b/source/blender/blenkernel/BKE_scene.h index d2152950bff..bed643c2133 100644 --- a/source/blender/blenkernel/BKE_scene.h +++ b/source/blender/blenkernel/BKE_scene.h @@ -38,14 +38,16 @@ extern "C" { #endif struct AviCodecData; -struct Base; +struct BaseLegacy; struct EvaluationContext; struct Main; struct Object; +struct Base; struct QuicktimeCodecData; struct RenderData; struct SceneRenderLayer; struct Scene; +struct SceneLayer; struct UnitSettings; struct Main; @@ -70,13 +72,15 @@ void BKE_scene_free(struct Scene *sce); void BKE_scene_init(struct Scene *sce); struct Scene *BKE_scene_add(struct Main *bmain, const char *name); +void BKE_scene_remove_rigidbody_object(struct Scene *scene, struct Object *ob); + /* base functions */ -struct Base *BKE_scene_base_find_by_name(struct Scene *scene, const char *name); -struct Base *BKE_scene_base_find(struct Scene *scene, struct Object *ob); -struct Base *BKE_scene_base_add(struct Scene *sce, struct Object *ob); -void BKE_scene_base_unlink(struct Scene *sce, struct Base *base); +struct BaseLegacy *BKE_scene_base_find_by_name(struct Scene *scene, const char *name); +struct BaseLegacy *BKE_scene_base_find(struct Scene *scene, struct Object *ob); +struct BaseLegacy *BKE_scene_base_add(struct Scene *sce, struct Object *ob); +void BKE_scene_base_unlink(struct Scene *sce, struct BaseLegacy *base); void BKE_scene_base_deselect_all(struct Scene *sce); -void BKE_scene_base_select(struct Scene *sce, struct Base *selbase); +void BKE_scene_base_select(struct Scene *sce, struct BaseLegacy *selbase); /* Scene base iteration function. * Define struct here, so no need to bother with alloc/free it. @@ -90,10 +94,14 @@ typedef struct SceneBaseIter { } SceneBaseIter; int BKE_scene_base_iter_next(struct EvaluationContext *eval_ctx, struct SceneBaseIter *iter, - struct Scene **scene, int val, struct Base **base, struct Object **ob); + struct Scene **scene, int val, struct BaseLegacy **base, struct Object **ob); -void BKE_scene_base_flag_to_objects(struct Scene *scene); +void BKE_scene_base_flag_to_objects(struct SceneLayer *sl); void BKE_scene_base_flag_from_objects(struct Scene *scene); +void BKE_scene_base_flag_sync_from_base(struct BaseLegacy *base); +void BKE_scene_base_flag_sync_from_object(struct BaseLegacy *base); +void BKE_scene_object_base_flag_sync_from_base(struct Base *base); +void BKE_scene_object_base_flag_sync_from_object(struct Base *base); void BKE_scene_set_background(struct Main *bmain, struct Scene *sce); struct Scene *BKE_scene_set_name(struct Main *bmain, const char *name); diff --git a/source/blender/blenkernel/BKE_screen.h b/source/blender/blenkernel/BKE_screen.h index 14e978b23f2..010810ad0cc 100644 --- a/source/blender/blenkernel/BKE_screen.h +++ b/source/blender/blenkernel/BKE_screen.h @@ -49,6 +49,7 @@ struct bScreen; struct uiLayout; struct uiList; struct wmKeyConfig; +struct wmManipulatorMap; struct wmNotifier; struct wmWindow; struct wmWindowManager; @@ -96,6 +97,9 @@ typedef struct SpaceType { /* on startup, define dropboxes for spacetype+regions */ void (*dropboxes)(void); + /* initialize manipulator-map-types and manipulator-group-types with the region */ + void (*manipulators)(void); + /* return context data */ int (*context)(const struct bContext *, const char *, struct bContextDataResult *); @@ -284,6 +288,8 @@ void BKE_spacedata_id_unref(struct ScrArea *sa, struct SpaceLink *sl, struct ID struct ARegion *BKE_area_region_copy(struct SpaceType *st, struct ARegion *ar); void BKE_area_region_free(struct SpaceType *st, struct ARegion *ar); void BKE_screen_area_free(struct ScrArea *sa); +/* Manipulator-maps of a region need to be freed with the region. Uses callback to avoid low-level call. */ +void BKE_region_callback_free_manipulatormap_set(void (*callback)(struct wmManipulatorMap *)); struct ARegion *BKE_area_find_region_type(struct ScrArea *sa, int type); struct ARegion *BKE_area_find_region_active_win(struct ScrArea *sa); diff --git a/source/blender/blenkernel/CMakeLists.txt b/source/blender/blenkernel/CMakeLists.txt index 157c4408d6a..b665183a37b 100644 --- a/source/blender/blenkernel/CMakeLists.txt +++ b/source/blender/blenkernel/CMakeLists.txt @@ -30,6 +30,7 @@ set(INC ../blenloader ../blentranslation ../depsgraph + ../draw ../gpu ../ikplugin ../imbuf @@ -85,6 +86,7 @@ set(SRC intern/camera.c intern/cdderivedmesh.c intern/cloth.c + intern/collection.c intern/collision.c intern/colortools.c intern/constraint.c @@ -133,6 +135,7 @@ set(SRC intern/mesh_evaluate.c intern/mesh_mapping.c intern/mesh_remap.c + intern/mesh_render.c intern/mesh_validate.c intern/modifier.c intern/modifiers_bmesh.c @@ -156,6 +159,7 @@ set(SRC intern/pbvh_bmesh.c intern/pointcache.c intern/property.c + intern/layer.c intern/report.c intern/rigidbody.c intern/sca.c @@ -213,6 +217,7 @@ set(SRC BKE_ccg.h BKE_cdderivedmesh.h BKE_cloth.h + BKE_collection.h BKE_collision.h BKE_colortools.h BKE_constraint.h @@ -257,6 +262,7 @@ set(SRC BKE_mesh.h BKE_mesh_mapping.h BKE_mesh_remap.h + BKE_mesh_render.h BKE_modifier.h BKE_movieclip.h BKE_multires.h @@ -272,6 +278,7 @@ set(SRC BKE_pbvh.h BKE_pointcache.h BKE_property.h + BKE_layer.h BKE_report.h BKE_rigidbody.h BKE_sca.h @@ -535,8 +542,4 @@ endif() # set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /WX") #endif() -if(WITH_LEGACY_DEPSGRAPH) - add_definitions(-DWITH_LEGACY_DEPSGRAPH) -endif() - blender_add_lib(bf_blenkernel "${SRC}" "${INC}" "${INC_SYS}") diff --git a/source/blender/blenkernel/intern/DerivedMesh.c b/source/blender/blenkernel/intern/DerivedMesh.c index 160adcc3988..39f1db0b886 100644 --- a/source/blender/blenkernel/intern/DerivedMesh.c +++ b/source/blender/blenkernel/intern/DerivedMesh.c @@ -317,7 +317,7 @@ void DM_init( dm->numPolyData = numPolys; DM_init_funcs(dm); - + dm->needsFree = 1; dm->auto_bump_scale = -1.0f; dm->dirty = 0; @@ -377,6 +377,7 @@ int DM_release(DerivedMesh *dm) if (dm->needsFree) { bvhcache_free(&dm->bvhCache); GPU_drawobject_free(dm); + CustomData_free(&dm->vertData, dm->numVertData); CustomData_free(&dm->edgeData, dm->numEdgeData); CustomData_free(&dm->faceData, dm->numTessFaceData); diff --git a/source/blender/blenkernel/intern/anim.c b/source/blender/blenkernel/intern/anim.c index 2f65e71c6d2..237e4e80172 100644 --- a/source/blender/blenkernel/intern/anim.c +++ b/source/blender/blenkernel/intern/anim.c @@ -283,7 +283,7 @@ void animviz_get_object_motionpaths(Object *ob, ListBase *targets) /* tweak the object ordering to trick depsgraph into making MotionPath calculations run faster */ static void motionpaths_calc_optimise_depsgraph(Scene *scene, ListBase *targets) { - Base *base, *baseNext; + BaseLegacy *base, *baseNext; MPathTarget *mpt; /* make sure our temp-tag isn't already in use */ @@ -321,7 +321,7 @@ static void motionpaths_calc_update_scene(Scene *scene) BKE_scene_update_for_newframe(G.main->eval_ctx, G.main, scene, scene->lay); } else { /* otherwise we can optimize by restricting updates */ - Base *base, *last = NULL; + BaseLegacy *base, *last = NULL; /* only stuff that moves or needs display still */ DAG_scene_update_flags(G.main, scene, scene->lay, true, false); diff --git a/source/blender/blenkernel/intern/armature.c b/source/blender/blenkernel/intern/armature.c index 02cc31e5977..2565eb1900c 100644 --- a/source/blender/blenkernel/intern/armature.c +++ b/source/blender/blenkernel/intern/armature.c @@ -1930,7 +1930,7 @@ void BKE_pose_clear_pointers(bPose *pose) /* only after leave editmode, duplicating, validating older files, library syncing */ /* NOTE: pose->flag is set for it */ -void BKE_pose_rebuild_ex(Object *ob, bArmature *arm, const bool sort_bones) +void BKE_pose_rebuild(Object *ob, bArmature *arm) { Bone *bone; bPose *pose; @@ -1974,25 +1974,12 @@ void BKE_pose_rebuild_ex(Object *ob, bArmature *arm, const bool sort_bones) BKE_pose_update_constraint_flags(ob->pose); /* for IK detection for example */ -#ifdef WITH_LEGACY_DEPSGRAPH - /* the sorting */ - /* Sorting for new dependnecy graph is done on the scene graph level. */ - if (counter > 1 && sort_bones) { - DAG_pose_sort(ob); - } -#endif - ob->pose->flag &= ~POSE_RECALC; ob->pose->flag |= POSE_WAS_REBUILT; BKE_pose_channels_hash_make(ob->pose); } -void BKE_pose_rebuild(Object *ob, bArmature *arm) -{ - BKE_pose_rebuild_ex(ob, arm, true); -} - /* ********************** THE POSE SOLVER ******************* */ /* loc/rot/size to given mat4 */ diff --git a/source/blender/blenkernel/intern/armature_update.c b/source/blender/blenkernel/intern/armature_update.c index 3bc81a69c86..a8ab1e9357b 100644 --- a/source/blender/blenkernel/intern/armature_update.c +++ b/source/blender/blenkernel/intern/armature_update.c @@ -53,11 +53,7 @@ #include "DEG_depsgraph.h" -#ifdef WITH_LEGACY_DEPSGRAPH -# define DEBUG_PRINT if (!DEG_depsgraph_use_legacy() && G.debug & G_DEBUG_DEPSGRAPH) printf -#else -# define DEBUG_PRINT if (G.debug & G_DEBUG_DEPSGRAPH) printf -#endif +#define DEBUG_PRINT if (G.debug & G_DEBUG_DEPSGRAPH) printf /* ********************** SPLINE IK SOLVER ******************* */ diff --git a/source/blender/blenkernel/intern/cachefile.c b/source/blender/blenkernel/intern/cachefile.c index 3dce08eb756..8630e8562b0 100644 --- a/source/blender/blenkernel/intern/cachefile.c +++ b/source/blender/blenkernel/intern/cachefile.c @@ -205,7 +205,7 @@ float BKE_cachefile_time_offset(CacheFile *cache_file, const float time, const f /* TODO(kevin): replace this with some depsgraph mechanism, or something similar. */ void BKE_cachefile_clean(Scene *scene, CacheFile *cache_file) { - for (Base *base = scene->base.first; base; base = base->next) { + for (BaseLegacy *base = scene->base.first; base; base = base->next) { Object *ob = base->object; ModifierData *md = modifiers_findByType(ob, eModifierType_MeshSequenceCache); diff --git a/source/blender/blenkernel/intern/camera.c b/source/blender/blenkernel/intern/camera.c index 9cb553aa27b..978204f1cf5 100644 --- a/source/blender/blenkernel/intern/camera.c +++ b/source/blender/blenkernel/intern/camera.c @@ -853,7 +853,7 @@ static Object *camera_multiview_advanced(Scene *scene, Object *camera, const cha } if (name[0] != '\0') { - Base *base = BKE_scene_base_find_by_name(scene, name); + BaseLegacy *base = BKE_scene_base_find_by_name(scene, name); if (base) { return base->object; } diff --git a/source/blender/blenkernel/intern/cloth.c b/source/blender/blenkernel/intern/cloth.c index 28ef3f6f248..162525c7cd5 100644 --- a/source/blender/blenkernel/intern/cloth.c +++ b/source/blender/blenkernel/intern/cloth.c @@ -478,7 +478,6 @@ void clothModifier_do(ClothModifierData *clmd, Scene *scene, Object *ob, Derived return; } - if (!can_simulate) return; /* if on second frame, write cache for first frame */ diff --git a/source/blender/blenkernel/intern/collection.c b/source/blender/blenkernel/intern/collection.c new file mode 100644 index 00000000000..18af75771c0 --- /dev/null +++ b/source/blender/blenkernel/intern/collection.c @@ -0,0 +1,452 @@ +/* + * ***** 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. + * + * Contributor(s): Dalai Felinto + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/blenkernel/intern/collection.c + * \ingroup bke + */ + +#include "BLI_blenlib.h" +#include "BLI_ghash.h" +#include "BLI_iterator.h" +#include "BLI_listbase.h" +#include "BLT_translation.h" +#include "BLI_string_utils.h" + +#include "BKE_collection.h" +#include "BKE_layer.h" +#include "BKE_library.h" +#include "BKE_main.h" +#include "BKE_scene.h" + +#include "DNA_ID.h" +#include "DNA_layer_types.h" +#include "DNA_object_types.h" +#include "DNA_scene_types.h" + +#include "MEM_guardedalloc.h" + + +/** + * Add a collection to a collection ListBase and syncronize all render layers + * The ListBase is NULL when the collection is to be added to the master collection + */ +SceneCollection *BKE_collection_add(Scene *scene, SceneCollection *sc_parent, const char *name) +{ + SceneCollection *sc_master = BKE_collection_master(scene); + SceneCollection *sc = MEM_callocN(sizeof(SceneCollection), "New Collection"); + + if (!name) { + name = DATA_("New Collection"); + } + + if (!sc_parent) { + sc_parent = sc_master; + } + + BLI_strncpy(sc->name, name, sizeof(sc->name)); + BLI_uniquename(&sc_master->scene_collections, sc, DATA_("Collection"), '.', offsetof(SceneCollection, name), sizeof(sc->name)); + + BLI_addtail(&sc_parent->scene_collections, sc); + + BKE_layer_sync_new_scene_collection(scene, sc_parent, sc); + return sc; +} + +/** + * Free the collection items recursively + */ +static void collection_free(SceneCollection *sc) +{ + for (LinkData *link = sc->objects.first; link; link = link->next) { + id_us_min(link->data); + } + BLI_freelistN(&sc->objects); + + for (LinkData *link = sc->filter_objects.first; link; link = link->next) { + id_us_min(link->data); + } + BLI_freelistN(&sc->filter_objects); + + for (SceneCollection *nsc = sc->scene_collections.first; nsc; nsc = nsc->next) { + collection_free(nsc); + } + BLI_freelistN(&sc->scene_collections); +} + +/** + * Unlink the collection recursively + * \return true if unlinked. + */ +static bool collection_remlink(SceneCollection *sc_parent, SceneCollection *sc_gone) +{ + for (SceneCollection *sc = sc_parent->scene_collections.first; sc; sc = sc->next) { + if (sc == sc_gone) { + BLI_remlink(&sc_parent->scene_collections, sc_gone); + return true; + } + + if (collection_remlink(sc, sc_gone)) { + return true; + } + } + return false; +} + +/** + * Recursively remove any instance of this SceneCollection + */ +static void layer_collection_remove(SceneLayer *sl, ListBase *lb, const SceneCollection *sc) +{ + LayerCollection *lc = lb->first; + while (lc) { + if (lc->scene_collection == sc) { + BKE_scene_layer_engine_settings_collection_recalculate(sl, lc); + BKE_layer_collection_free(sl, lc); + BLI_remlink(lb, lc); + + LayerCollection *lc_next = lc->next; + MEM_freeN(lc); + lc = lc_next; + + /* only the "top-level" layer collections may have the + * same SceneCollection in a sibling tree. + */ + if (lb != &sl->layer_collections) { + return; + } + } + + else { + layer_collection_remove(sl, &lc->layer_collections, sc); + lc = lc->next; + } + } +} + +/** + * Remove a collection from the scene, and syncronize all render layers + */ +bool BKE_collection_remove(Scene *scene, SceneCollection *sc) +{ + SceneCollection *sc_master = BKE_collection_master(scene); + + /* the master collection cannot be removed */ + if (sc == sc_master) { + return false; + } + + /* unlink from the respective collection tree */ + if (!collection_remlink(sc_master, sc)) { + BLI_assert(false); + } + + /* clear the collection items */ + collection_free(sc); + + /* check all layers that use this collection and clear them */ + for (SceneLayer *sl = scene->render_layers.first; sl; sl = sl->next) { + layer_collection_remove(sl, &sl->layer_collections, sc); + BKE_scene_layer_base_flag_recalculate(sl); + sl->active_collection = 0; + } + + MEM_freeN(sc); + return true; +} + +/** + * Returns the master collection + */ +SceneCollection *BKE_collection_master(const Scene *scene) +{ + return scene->collection; +} + +/** + * Free (or release) any data used by the master collection (does not free the master collection itself). + * Used only to clear the entire scene data since it's not doing re-syncing of the LayerCollection tree + */ +void BKE_collection_master_free(Scene *scene) +{ + collection_free(BKE_collection_master(scene)); +} + +static void collection_object_add(Scene *scene, SceneCollection *sc, Object *ob) +{ + BLI_addtail(&sc->objects, BLI_genericNodeN(ob)); + id_us_plus((ID *)ob); + BKE_layer_sync_object_link(scene, sc, ob); +} + +/** + * Add object to collection + */ +void BKE_collection_object_add(Scene *scene, SceneCollection *sc, Object *ob) +{ + if (BLI_findptr(&sc->objects, ob, offsetof(LinkData, data))) { + /* don't add the same object twice */ + return; + } + collection_object_add(scene, sc, ob); +} + +/** + * Add object to all collections that reference objects is in + * (used to copy objects) + */ +void BKE_collection_object_add_from(Scene *scene, Object *ob_src, Object *ob_dst) +{ + FOREACH_SCENE_COLLECTION(scene, sc) + { + if (BLI_findptr(&sc->objects, ob_src, offsetof(LinkData, data))) { + collection_object_add(scene, sc, ob_dst); + } + } + FOREACH_SCENE_COLLECTION_END +} + +/** + * Remove object from collection + */ +void BKE_collection_object_remove(Main *bmain, Scene *scene, SceneCollection *sc, Object *ob, const bool free_us) +{ + + LinkData *link = BLI_findptr(&sc->objects, ob, offsetof(LinkData, data)); + + if (link == NULL) { + return; + } + + BLI_remlink(&sc->objects, link); + MEM_freeN(link); + + TODO_LAYER_SYNC_FILTER; /* need to remove all instances of ob in scene collections -> filter_objects */ + BKE_layer_sync_object_unlink(scene, sc, ob); + + if (free_us) { + BKE_libblock_free_us(bmain, ob); + } + else { + id_us_min(&ob->id); + } +} + +/** + * Remove object from all collections of scene + */ +void BKE_collections_object_remove(Main *bmain, Scene *scene, Object *ob, const bool free_us) +{ + BKE_scene_remove_rigidbody_object(scene, ob); + + FOREACH_SCENE_COLLECTION(scene, sc) + { + BKE_collection_object_remove(bmain, scene, sc, ob, free_us); + } + FOREACH_SCENE_COLLECTION_END +} + +/* ---------------------------------------------------------------------- */ +/* Iteractors */ +/* scene collection iteractor */ + +typedef struct SceneCollectionsIteratorData { + Scene *scene; + void **array; + int tot, cur; +} SceneCollectionsIteratorData; + +static void scene_collection_callback(SceneCollection *sc, BKE_scene_collections_Cb callback, void *data) +{ + callback(sc, data); + + for (SceneCollection *nsc = sc->scene_collections.first; nsc; nsc = nsc->next) { + scene_collection_callback(nsc, callback, data); + } +} + +static void scene_collections_count(SceneCollection *UNUSED(sc), void *data) +{ + int *tot = data; + (*tot)++; +} + +static void scene_collections_build_array(SceneCollection *sc, void *data) +{ + SceneCollection ***array = data; + **array = sc; + (*array)++; +} + +static void scene_collections_array(Scene *scene, SceneCollection ***collections_array, int *tot) +{ + SceneCollection *sc = BKE_collection_master(scene); + SceneCollection **array; + + *collections_array = NULL; + *tot = 0; + + if (scene == NULL) + return; + + scene_collection_callback(sc, scene_collections_count, tot); + + if (*tot == 0) + return; + + *collections_array = array = MEM_mallocN(sizeof(SceneCollection *) * (*tot), "SceneCollectionArray"); + scene_collection_callback(sc, scene_collections_build_array, &array); +} + +/** + * Only use this in non-performance critical situations + * (it iterates over all scene collections twice) + */ +void BKE_scene_collections_Iterator_begin(Iterator *iter, void *data_in) +{ + Scene *scene = data_in; + SceneCollectionsIteratorData *data = MEM_callocN(sizeof(SceneCollectionsIteratorData), __FUNCTION__); + + data->scene = scene; + iter->data = data; + + scene_collections_array(scene, (SceneCollection ***)&data->array, &data->tot); + BLI_assert(data->tot != 0); + + data->cur = 0; + iter->current = data->array[data->cur]; + iter->valid = true; +} + +void BKE_scene_collections_Iterator_next(struct Iterator *iter) +{ + SceneCollectionsIteratorData *data = iter->data; + + if (++data->cur < data->tot) { + iter->current = data->array[data->cur]; + } + else { + iter->valid = false; + } +} + +void BKE_scene_collections_Iterator_end(struct Iterator *iter) +{ + SceneCollectionsIteratorData *data = iter->data; + + if (data) { + if (data->array) { + MEM_freeN(data->array); + } + MEM_freeN(data); + } + iter->valid = false; +} + + +/* scene objects iteractor */ + +typedef struct SceneObjectsIteratorData { + GSet *visited; + LinkData *link; + Iterator scene_collection_iter; +} SceneObjectsIteratorData; + +void BKE_scene_objects_Iterator_begin(Iterator *iter, void *data_in) +{ + Scene *scene = data_in; + SceneObjectsIteratorData *data = MEM_callocN(sizeof(SceneObjectsIteratorData), __FUNCTION__); + iter->data = data; + + /* lookup list ot make sure each object is object called once */ + data->visited = BLI_gset_ptr_new(__func__); + + /* we wrap the scenecollection iterator here to go over the scene collections */ + BKE_scene_collections_Iterator_begin(&data->scene_collection_iter, scene); + + SceneCollection *sc = data->scene_collection_iter.current; + iter->current = sc->objects.first; + iter->valid = true; + + if (iter->current == NULL) { + BKE_scene_objects_Iterator_next(iter); + } +} + +/** + * Gets the first unique object in the sequence + */ +static LinkData *object_base_unique(GSet *gs, LinkData *link) +{ + if (link == NULL) { + return NULL; + } + + Object *ob = link->data; + if (!BLI_gset_haskey(gs, ob)) { + BLI_gset_add(gs, ob); + return link; + } + else { + return object_base_unique(gs, link->next); + } +} + +void BKE_scene_objects_Iterator_next(Iterator *iter) +{ + SceneObjectsIteratorData *data = iter->data; + LinkData *link = data->link ? object_base_unique(data->visited, data->link->next) : NULL; + + if (link) { + data->link = link; + iter->current = link->data; + } + else { + /* if this is the last object of this ListBase look at the next SceneCollection */ + SceneCollection *sc; + BKE_scene_collections_Iterator_next(&data->scene_collection_iter); + do { + sc = data->scene_collection_iter.current; + /* get the first unique object of this collection */ + LinkData *new_link = object_base_unique(data->visited, sc->objects.first); + if (new_link) { + data->link = new_link; + iter->current = data->link->data; + return; + } + BKE_scene_collections_Iterator_next(&data->scene_collection_iter); + } while (data->scene_collection_iter.valid); + + if (!data->scene_collection_iter.valid) { + iter->valid = false; + } + } +} + +void BKE_scene_objects_Iterator_end(Iterator *iter) +{ + SceneObjectsIteratorData *data = iter->data; + if (data) { + BKE_scene_collections_Iterator_end(&data->scene_collection_iter); + BLI_gset_free(data->visited, NULL); + MEM_freeN(data); + } +} diff --git a/source/blender/blenkernel/intern/collision.c b/source/blender/blenkernel/intern/collision.c index ee25be36855..23cfee721ae 100644 --- a/source/blender/blenkernel/intern/collision.c +++ b/source/blender/blenkernel/intern/collision.c @@ -512,7 +512,7 @@ static void add_collision_object(Object ***objs, unsigned int *numobj, unsigned // return all collision objects in scene // collision object will exclude self -Object **get_collisionobjects_ext(Scene *scene, Object *self, Group *group, int layer, unsigned int *numcollobj, unsigned int modifier_type, bool dupli) +Object **get_collisionobjects_ext(Scene *scene, Object *self, Group *group, int UNUSED(layer), unsigned int *numcollobj, unsigned int modifier_type, bool dupli) { Base *base; Object **objs; @@ -532,9 +532,9 @@ Object **get_collisionobjects_ext(Scene *scene, Object *self, Group *group, int Scene *sce_iter; /* add objects in same layer in scene */ for (SETLOOPER(scene, sce_iter, base)) { - if ( base->lay & layer ) + if ((base->flag & BASE_VISIBLED) != 0) { add_collision_object(&objs, &numobj, &maxobj, base->object, self, level, modifier_type); - + } } } @@ -600,7 +600,7 @@ ListBase *get_collider_cache(Scene *scene, Object *self, Group *group) /* add objects in same layer in scene */ for (SETLOOPER(scene, sce_iter, base)) { - if (!self || (base->lay & self->lay)) + if (!self || ((base->flag & BASE_VISIBLED) != 0)) add_collider_cache_object(&objs, base->object, self, 0); } diff --git a/source/blender/blenkernel/intern/context.c b/source/blender/blenkernel/intern/context.c index 4c01bfd35f2..560d84c1d2d 100644 --- a/source/blender/blenkernel/intern/context.c +++ b/source/blender/blenkernel/intern/context.c @@ -47,6 +47,7 @@ #include "BLT_translation.h" #include "BKE_context.h" +#include "BKE_layer.h" #include "BKE_main.h" #include "BKE_screen.h" #include "BKE_sound.h" @@ -836,8 +837,9 @@ void CTX_wm_window_set(bContext *C, wmWindow *win) void CTX_wm_screen_set(bContext *C, bScreen *screen) { C->wm.screen = screen; - if (C->wm.screen) - C->data.scene = C->wm.screen->scene; + if (C->wm.screen) { + CTX_data_scene_set(C, C->wm.screen->scene); + } C->wm.area = NULL; C->wm.region = NULL; } @@ -896,6 +898,59 @@ Scene *CTX_data_scene(const bContext *C) return C->data.scene; } +SceneLayer *CTX_data_scene_layer(const bContext *C) +{ + SceneLayer *sl; + + if (ctx_data_pointer_verify(C, "render_layer", (void *)&sl)) { + return sl; + } + else { + return BKE_scene_layer_context_active(CTX_data_scene(C)); + } +} + +/** + * This is tricky. Sometimes the user overrides the render_layer + * but not the scene_collection. In this case what to do? + * + * If the scene_collection is linked to the SceneLayer we use it. + * Otherwise we fallback to the active one of the SceneLayer. + */ +LayerCollection *CTX_data_layer_collection(const bContext *C) +{ + SceneLayer *sl = CTX_data_scene_layer(C); + LayerCollection *lc; + + if (ctx_data_pointer_verify(C, "layer_collection", (void *)&lc)) { + if (BKE_scene_layer_has_collection(sl, lc->scene_collection)) { + return lc; + } + } + + /* fallback */ + return BKE_layer_collection_active(sl); +} + +SceneCollection *CTX_data_scene_collection(const bContext *C) +{ + SceneCollection *sc; + if (ctx_data_pointer_verify(C, "scene_collection", (void *)&sc)) { + if (BKE_scene_layer_has_collection(CTX_data_scene_layer(C), sc)) { + return sc; + } + } + + LayerCollection *lc = CTX_data_layer_collection(C); + if (lc) { + return lc->scene_collection; + } + + /* fallback */ + Scene *scene = CTX_data_scene(C); + return BKE_collection_master(scene); +} + int CTX_data_mode_enum(const bContext *C) { Object *obedit = CTX_data_edit_object(C); diff --git a/source/blender/blenkernel/intern/depsgraph.c b/source/blender/blenkernel/intern/depsgraph.c index 294a4ce76b7..c5b8a18fd65 100644 --- a/source/blender/blenkernel/intern/depsgraph.c +++ b/source/blender/blenkernel/intern/depsgraph.c @@ -40,56 +40,12 @@ #endif #include "BLI_utildefines.h" -#include "BLI_listbase.h" -#include "BLI_ghash.h" -#include "BLI_threads.h" -#include "DNA_anim_types.h" -#include "DNA_camera_types.h" -#include "DNA_cachefile_types.h" -#include "DNA_group_types.h" -#include "DNA_lamp_types.h" -#include "DNA_lattice_types.h" -#include "DNA_key_types.h" -#include "DNA_material_types.h" -#include "DNA_mesh_types.h" -#include "DNA_node_types.h" +#include "DNA_object_types.h" #include "DNA_scene_types.h" -#include "DNA_screen_types.h" -#include "DNA_windowmanager_types.h" -#include "DNA_movieclip_types.h" -#include "DNA_mask_types.h" -#include "DNA_modifier_types.h" -#include "DNA_rigidbody_types.h" -#include "BKE_anim.h" -#include "BKE_animsys.h" -#include "BKE_action.h" -#include "BKE_DerivedMesh.h" -#include "BKE_collision.h" -#include "BKE_effect.h" -#include "BKE_fcurve.h" #include "BKE_global.h" -#include "BKE_idcode.h" -#include "BKE_image.h" -#include "BKE_key.h" -#include "BKE_library.h" #include "BKE_main.h" -#include "BKE_node.h" -#include "BKE_material.h" -#include "BKE_mball.h" -#include "BKE_modifier.h" -#include "BKE_object.h" -#include "BKE_paint.h" -#include "BKE_particle.h" -#include "BKE_pointcache.h" -#include "BKE_scene.h" -#include "BKE_screen.h" -#include "BKE_tracking.h" - -#include "GPU_buffers.h" - -#include "atomic_ops.h" #include "depsgraph_private.h" @@ -98,3310 +54,6 @@ #include "DEG_depsgraph_debug.h" #include "DEG_depsgraph_query.h" -#ifdef WITH_LEGACY_DEPSGRAPH - -static SpinLock threaded_update_lock; - -void DAG_init(void) -{ - BLI_spin_init(&threaded_update_lock); - DEG_register_node_types(); -} - -void DAG_exit(void) -{ - BLI_spin_end(&threaded_update_lock); - DEG_free_node_types(); -} - -/* Queue and stack operations for dag traversal - * - * the queue store a list of freenodes to avoid successive alloc/dealloc - */ - -DagNodeQueue *queue_create(int slots) -{ - DagNodeQueue *queue; - DagNodeQueueElem *elem; - int i; - - queue = MEM_mallocN(sizeof(DagNodeQueue), "DAG queue"); - queue->freenodes = MEM_mallocN(sizeof(DagNodeQueue), "DAG queue"); - queue->count = 0; - queue->maxlevel = 0; - queue->first = queue->last = NULL; - elem = MEM_mallocN(sizeof(DagNodeQueueElem), "DAG queue elem3"); - elem->node = NULL; - elem->next = NULL; - queue->freenodes->first = queue->freenodes->last = elem; - - for (i = 1; i < slots; i++) { - elem = MEM_mallocN(sizeof(DagNodeQueueElem), "DAG queue elem4"); - elem->node = NULL; - elem->next = NULL; - queue->freenodes->last->next = elem; - queue->freenodes->last = elem; - } - queue->freenodes->count = slots; - return queue; -} - -void queue_raz(DagNodeQueue *queue) -{ - DagNodeQueueElem *elem; - - elem = queue->first; - if (queue->freenodes->last) - queue->freenodes->last->next = elem; - else - queue->freenodes->first = queue->freenodes->last = elem; - - elem->node = NULL; - queue->freenodes->count++; - while (elem->next) { - elem = elem->next; - elem->node = NULL; - queue->freenodes->count++; - } - queue->freenodes->last = elem; - queue->count = 0; -} - -void queue_delete(DagNodeQueue *queue) -{ - DagNodeQueueElem *elem; - DagNodeQueueElem *temp; - - elem = queue->first; - while (elem) { - temp = elem; - elem = elem->next; - MEM_freeN(temp); - } - - elem = queue->freenodes->first; - while (elem) { - temp = elem; - elem = elem->next; - MEM_freeN(temp); - } - - MEM_freeN(queue->freenodes); - MEM_freeN(queue); -} - -/* insert in queue, remove in front */ -void push_queue(DagNodeQueue *queue, DagNode *node) -{ - DagNodeQueueElem *elem; - int i; - - if (node == NULL) { - fprintf(stderr, "pushing null node\n"); - return; - } - /*fprintf(stderr, "BFS push : %s %d\n", ((ID *) node->ob)->name, queue->count);*/ - - elem = queue->freenodes->first; - if (elem != NULL) { - queue->freenodes->first = elem->next; - if (queue->freenodes->last == elem) { - queue->freenodes->last = NULL; - queue->freenodes->first = NULL; - } - queue->freenodes->count--; - } - else { /* alllocating more */ - elem = MEM_mallocN(sizeof(DagNodeQueueElem), "DAG queue elem1"); - elem->node = NULL; - elem->next = NULL; - queue->freenodes->first = queue->freenodes->last = elem; - - for (i = 1; i < DAGQUEUEALLOC; i++) { - elem = MEM_mallocN(sizeof(DagNodeQueueElem), "DAG queue elem2"); - elem->node = NULL; - elem->next = NULL; - queue->freenodes->last->next = elem; - queue->freenodes->last = elem; - } - queue->freenodes->count = DAGQUEUEALLOC; - - elem = queue->freenodes->first; - queue->freenodes->first = elem->next; - } - elem->next = NULL; - elem->node = node; - if (queue->last != NULL) - queue->last->next = elem; - queue->last = elem; - if (queue->first == NULL) { - queue->first = elem; - } - queue->count++; -} - - -/* insert in front, remove in front */ -void push_stack(DagNodeQueue *queue, DagNode *node) -{ - DagNodeQueueElem *elem; - int i; - - elem = queue->freenodes->first; - if (elem != NULL) { - queue->freenodes->first = elem->next; - if (queue->freenodes->last == elem) { - queue->freenodes->last = NULL; - queue->freenodes->first = NULL; - } - queue->freenodes->count--; - } - else { /* alllocating more */ - elem = MEM_mallocN(sizeof(DagNodeQueueElem), "DAG queue elem1"); - elem->node = NULL; - elem->next = NULL; - queue->freenodes->first = queue->freenodes->last = elem; - - for (i = 1; i < DAGQUEUEALLOC; i++) { - elem = MEM_mallocN(sizeof(DagNodeQueueElem), "DAG queue elem2"); - elem->node = NULL; - elem->next = NULL; - queue->freenodes->last->next = elem; - queue->freenodes->last = elem; - } - queue->freenodes->count = DAGQUEUEALLOC; - - elem = queue->freenodes->first; - queue->freenodes->first = elem->next; - } - elem->next = queue->first; - elem->node = node; - queue->first = elem; - if (queue->last == NULL) - queue->last = elem; - queue->count++; -} - - -DagNode *pop_queue(DagNodeQueue *queue) -{ - DagNodeQueueElem *elem; - DagNode *node; - - elem = queue->first; - if (elem) { - queue->first = elem->next; - if (queue->last == elem) { - queue->last = NULL; - queue->first = NULL; - } - queue->count--; - if (queue->freenodes->last) - queue->freenodes->last->next = elem; - queue->freenodes->last = elem; - if (queue->freenodes->first == NULL) - queue->freenodes->first = elem; - node = elem->node; - elem->node = NULL; - elem->next = NULL; - queue->freenodes->count++; - return node; - } - else { - fprintf(stderr, "return null\n"); - return NULL; - } -} - -DagNode *get_top_node_queue(DagNodeQueue *queue) -{ - return queue->first->node; -} - -DagForest *dag_init(void) -{ - DagForest *forest; - /* use callocN to init all zero */ - forest = MEM_callocN(sizeof(DagForest), "DAG root"); - forest->ugly_hack_sorry = true; - return forest; -} - -/* isdata = object data... */ -/* XXX this needs to be extended to be more flexible (so that not only objects are evaluated via depsgraph)... */ -static void dag_add_driver_relation(AnimData *adt, DagForest *dag, DagNode *node, int isdata) -{ - FCurve *fcu; - DagNode *node1; - - for (fcu = adt->drivers.first; fcu; fcu = fcu->next) { - ChannelDriver *driver = fcu->driver; - DriverVar *dvar; - int isdata_fcu = (isdata) || (fcu->rna_path && strstr(fcu->rna_path, "modifiers[")); - - /* loop over variables to get the target relationships */ - for (dvar = driver->variables.first; dvar; dvar = dvar->next) { - /* only used targets */ - DRIVER_TARGETS_USED_LOOPER(dvar) - { - if (dtar->id) { - /* FIXME: other data types need to be added here so that they can work! */ - if (GS(dtar->id->name) == ID_OB) { - Object *ob = (Object *)dtar->id; - - /* normal channel-drives-channel */ - node1 = dag_get_node(dag, dtar->id); - - /* check if bone... */ - if ((ob->type == OB_ARMATURE) && - ( ((dtar->rna_path) && strstr(dtar->rna_path, "pose.bones[")) || - ((dtar->flag & DTAR_FLAG_STRUCT_REF) && (dtar->pchan_name[0])) )) - { - dag_add_relation(dag, node1, node, isdata_fcu ? DAG_RL_DATA_DATA : DAG_RL_DATA_OB, "Driver"); - } - /* check if ob data */ - else if (dtar->rna_path && strstr(dtar->rna_path, "data.")) - dag_add_relation(dag, node1, node, isdata_fcu ? DAG_RL_DATA_DATA : DAG_RL_DATA_OB, "Driver"); - /* normal */ - else - dag_add_relation(dag, node1, node, isdata_fcu ? DAG_RL_OB_DATA : DAG_RL_OB_OB, "Driver"); - } - } - } - DRIVER_TARGETS_LOOPER_END - } - } -} - -/* XXX: forward def for material driver handling... */ -static void dag_add_material_driver_relations(DagForest *dag, DagNode *node, Material *ma); - -/* recursive handling for shader nodetree drivers */ -static void dag_add_shader_nodetree_driver_relations(DagForest *dag, DagNode *node, bNodeTree *ntree) -{ - bNode *n; - - /* nodetree itself */ - if (ntree->adt) { - dag_add_driver_relation(ntree->adt, dag, node, 1); - } - - /* nodetree's nodes... */ - for (n = ntree->nodes.first; n; n = n->next) { - if (n->id) { - if (GS(n->id->name) == ID_MA) { - dag_add_material_driver_relations(dag, node, (Material *)n->id); - } - else if (n->type == NODE_GROUP) { - dag_add_shader_nodetree_driver_relations(dag, node, (bNodeTree *)n->id); - } - } - } -} - -/* recursive handling for material drivers */ -static void dag_add_material_driver_relations(DagForest *dag, DagNode *node, Material *ma) -{ - /* Prevent infinite recursion by checking (and tagging the material) as having been visited - * already (see build_dag()). This assumes ma->id.tag & LIB_TAG_DOIT isn't set by anything else - * in the meantime... [#32017] - */ - if (ma->id.tag & LIB_TAG_DOIT) - return; - - ma->id.tag |= LIB_TAG_DOIT; - - /* material itself */ - if (ma->adt) - dag_add_driver_relation(ma->adt, dag, node, 1); - - /* textures */ - // TODO... - //dag_add_texture_driver_relations(DagForest *dag, DagNode *node, ID *id); - - /* material's nodetree */ - if (ma->nodetree) - dag_add_shader_nodetree_driver_relations(dag, node, ma->nodetree); - - ma->id.tag &= ~LIB_TAG_DOIT; -} - -/* recursive handling for lamp drivers */ -static void dag_add_lamp_driver_relations(DagForest *dag, DagNode *node, Lamp *la) -{ - /* Prevent infinite recursion by checking (and tagging the lamp) as having been visited - * already (see build_dag()). This assumes la->id.tag & LIB_TAG_DOIT isn't set by anything else - * in the meantime... [#32017] - */ - if (la->id.tag & LIB_TAG_DOIT) - return; - - la->id.tag |= LIB_TAG_DOIT; - - /* lamp itself */ - if (la->adt) - dag_add_driver_relation(la->adt, dag, node, 1); - - /* textures */ - // TODO... - //dag_add_texture_driver_relations(DagForest *dag, DagNode *node, ID *id); - - /* lamp's nodetree */ - if (la->nodetree) - dag_add_shader_nodetree_driver_relations(dag, node, la->nodetree); - - la->id.tag &= ~LIB_TAG_DOIT; -} - -static void create_collision_relation(DagForest *dag, DagNode *node, Object *ob1, const char *name) -{ - DagNode *node2 = dag_get_node(dag, ob1); - dag_add_relation(dag, node2, node, DAG_RL_DATA_DATA | DAG_RL_OB_DATA, name); -} - -void dag_add_collision_relations(DagForest *dag, Scene *scene, Object *ob, DagNode *node, Group *group, int layer, unsigned int modifier_type, DagCollobjFilterFunction fn, bool dupli, const char *name) -{ - unsigned int numcollobj; - Object **collobjs = get_collisionobjects_ext(scene, ob, group, layer, &numcollobj, modifier_type, dupli); - - for (unsigned int i = 0; i < numcollobj; i++) { - Object *ob1 = collobjs[i]; - - if (!fn || fn(ob1, modifiers_findByType(ob1, modifier_type))) { - create_collision_relation(dag, node, ob1, name); - } - } - - if (collobjs) - MEM_freeN(collobjs); -} - -void dag_add_forcefield_relations(DagForest *dag, Scene *scene, Object *ob, DagNode *node, EffectorWeights *effector_weights, bool add_absorption, int skip_forcefield, const char *name) -{ - ListBase *effectors = pdInitEffectors(scene, ob, NULL, effector_weights, false); - - if (effectors) { - for (EffectorCache *eff = effectors->first; eff; eff = eff->next) { - if (eff->ob != ob && eff->pd->forcefield != skip_forcefield) { - create_collision_relation(dag, node, eff->ob, name); - - if (eff->pd->forcefield == PFIELD_SMOKEFLOW && eff->pd->f_source) { - create_collision_relation(dag, node, eff->pd->f_source, "Smoke Force Domain"); - } - - if (add_absorption && (eff->pd->flag & PFIELD_VISIBILITY)) { - /* Actual code uses get_collider_cache */ - dag_add_collision_relations(dag, scene, ob, node, NULL, eff->ob->lay, eModifierType_Collision, NULL, true, "Force Absorption"); - } - } - } - } - - pdEndEffectors(&effectors); -} - -static void build_dag_object(DagForest *dag, DagNode *scenenode, Main *bmain, Scene *scene, Object *ob, int mask) -{ - bConstraint *con; - DagNode *node; - DagNode *node2; - DagNode *node3; - Key *key; - ParticleSystem *psys; - int addtoroot = 1; - - node = dag_get_node(dag, ob); - - if ((ob->data) && (mask & DAG_RL_DATA)) { - node2 = dag_get_node(dag, ob->data); - dag_add_relation(dag, node, node2, DAG_RL_DATA, "Object-Data Relation"); - node2->first_ancestor = ob; - node2->ancestor_count += 1; - } - - /* also build a custom data mask for dependencies that need certain layers */ - - if (ob->type == OB_ARMATURE) { - if (ob->pose) { - bPoseChannel *pchan; - - for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) { - for (con = pchan->constraints.first; con; con = con->next) { - const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con); - ListBase targets = {NULL, NULL}; - bConstraintTarget *ct; - - if (cti && cti->get_constraint_targets) { - cti->get_constraint_targets(con, &targets); - - for (ct = targets.first; ct; ct = ct->next) { - if (ct->tar && ct->tar != ob) { - // fprintf(stderr, "armature %s target :%s\n", ob->id.name, target->id.name); - node3 = dag_get_node(dag, ct->tar); - - if (ct->subtarget[0]) { - dag_add_relation(dag, node3, node, DAG_RL_OB_DATA | DAG_RL_DATA_DATA, cti->name); - if (ct->tar->type == OB_MESH) - node3->customdata_mask |= CD_MASK_MDEFORMVERT; - } - else if (ELEM(con->type, CONSTRAINT_TYPE_FOLLOWPATH, CONSTRAINT_TYPE_CLAMPTO, CONSTRAINT_TYPE_SPLINEIK)) - dag_add_relation(dag, node3, node, DAG_RL_DATA_DATA | DAG_RL_OB_DATA, cti->name); - else - dag_add_relation(dag, node3, node, DAG_RL_OB_DATA, cti->name); - } - } - - if (cti->flush_constraint_targets) - cti->flush_constraint_targets(con, &targets, 1); - } - - } - } - } - } - - /* driver dependencies, nla modifiers */ -#if 0 // XXX old animation system - if (ob->nlastrips.first) { - bActionStrip *strip; - bActionChannel *chan; - for (strip = ob->nlastrips.first; strip; strip = strip->next) { - if (strip->modifiers.first) { - bActionModifier *amod; - for (amod = strip->modifiers.first; amod; amod = amod->next) { - if (amod->ob) { - node2 = dag_get_node(dag, amod->ob); - dag_add_relation(dag, node2, node, DAG_RL_DATA_DATA | DAG_RL_OB_DATA, "NLA Strip Modifier"); - } - } - } - } - } -#endif // XXX old animation system - if (ob->adt) - dag_add_driver_relation(ob->adt, dag, node, (ob->type == OB_ARMATURE)); // XXX isdata arg here doesn't give an accurate picture of situation - - key = BKE_key_from_object(ob); - if (key && key->adt) - dag_add_driver_relation(key->adt, dag, node, 1); - - if (ob->modifiers.first) { - ModifierData *md; - - for (md = ob->modifiers.first; md; md = md->next) { - const ModifierTypeInfo *mti = modifierType_getInfo(md->type); - - if (mti->updateDepgraph) mti->updateDepgraph(md, dag, bmain, scene, ob, node); - } - } - if (ob->parent) { - node2 = dag_get_node(dag, ob->parent); - - switch (ob->partype) { - case PARSKEL: - dag_add_relation(dag, node2, node, DAG_RL_DATA_DATA | DAG_RL_OB_OB, "Parent"); - break; - case PARVERT1: case PARVERT3: - dag_add_relation(dag, node2, node, DAG_RL_DATA_OB | DAG_RL_OB_OB, "Vertex Parent"); - node2->customdata_mask |= CD_MASK_ORIGINDEX; - break; - case PARBONE: - dag_add_relation(dag, node2, node, DAG_RL_DATA_OB | DAG_RL_OB_OB, "Bone Parent"); - break; - default: - if (ob->parent->type == OB_LATTICE) - dag_add_relation(dag, node2, node, DAG_RL_DATA_DATA | DAG_RL_OB_OB, "Lattice Parent"); - else if (ob->parent->type == OB_CURVE) { - Curve *cu = ob->parent->data; - if (cu->flag & CU_PATH) - dag_add_relation(dag, node2, node, DAG_RL_DATA_OB | DAG_RL_OB_OB, "Curve Parent"); - else - dag_add_relation(dag, node2, node, DAG_RL_OB_OB, "Curve Parent"); - } - else - dag_add_relation(dag, node2, node, DAG_RL_OB_OB, "Parent"); - break; - } - /* exception case: parent is duplivert */ - if (ob->type == OB_MBALL && (ob->parent->transflag & OB_DUPLIVERTS)) { - dag_add_relation(dag, node2, node, DAG_RL_DATA_DATA | DAG_RL_OB_OB, "Duplivert"); - } - - addtoroot = 0; - } - if (ob->proxy) { - node2 = dag_get_node(dag, ob->proxy); - dag_add_relation(dag, node, node2, DAG_RL_DATA_DATA | DAG_RL_OB_OB, "Proxy"); - /* inverted relation, so addtoroot shouldn't be set to zero */ - } - - if (ob->transflag & OB_DUPLI) { - if ((ob->transflag & OB_DUPLIGROUP) && ob->dup_group) { - GroupObject *go; - for (go = ob->dup_group->gobject.first; go; go = go->next) { - if (go->ob) { - node2 = dag_get_node(dag, go->ob); - /* node2 changes node1, this keeps animations updated in groups?? not logical? */ - dag_add_relation(dag, node2, node, DAG_RL_OB_OB, "Dupligroup"); - } - } - } - } - - /* rigidbody force fields */ - if ((ob->type == OB_MESH) || (ob->type == OB_CURVE) || (ob->type == OB_LATTICE)) { - if (ob->rigidbody_object && scene->rigidbody_world) { - dag_add_forcefield_relations(dag, scene, ob, node, scene->rigidbody_world->effector_weights, true, 0, "Force Field"); - } - } - - /* object data drivers */ - if (ob->data) { - AnimData *adt = BKE_animdata_from_id((ID *)ob->data); - if (adt) - dag_add_driver_relation(adt, dag, node, 1); - } - - /* object type/data relationships */ - switch (ob->type) { - case OB_CAMERA: - { - Camera *cam = (Camera *)ob->data; - - if (cam->dof_ob) { - node2 = dag_get_node(dag, cam->dof_ob); - dag_add_relation(dag, node2, node, DAG_RL_OB_OB, "Camera DoF"); - } - break; - } - case OB_MBALL: - { - Object *mom = BKE_mball_basis_find(scene, ob); - - if (mom != ob) { - node2 = dag_get_node(dag, mom); - dag_add_relation(dag, node, node2, DAG_RL_DATA_DATA | DAG_RL_OB_DATA, "Metaball"); /* mom depends on children! */ - } - break; - } - case OB_CURVE: - case OB_FONT: - { - Curve *cu = ob->data; - - if (cu->bevobj) { - node2 = dag_get_node(dag, cu->bevobj); - dag_add_relation(dag, node2, node, DAG_RL_DATA_DATA | DAG_RL_OB_DATA, "Curve Bevel"); - } - if (cu->taperobj) { - node2 = dag_get_node(dag, cu->taperobj); - dag_add_relation(dag, node2, node, DAG_RL_DATA_DATA | DAG_RL_OB_DATA, "Curve Taper"); - } - if (ob->type == OB_FONT) { - /* Really rather dirty hack. needs to support font family to work - * reliably on render export. - * - * This totally mimics behavior of regular verts duplication with - * parenting. The only tricky thing here is to get list of objects - * used for the custom "font". - * - * This shouldn't harm so much because this code only runs on DAG - * rebuild and this feature is not that commonly used. - * - * - sergey - - */ - if (cu->family[0] != '\n') { - ListBase *duplilist; - DupliObject *dob; - duplilist = object_duplilist(G.main->eval_ctx, scene, ob); - for (dob = duplilist->first; dob; dob = dob->next) { - node2 = dag_get_node(dag, dob->ob); - dag_add_relation(dag, node, node2, DAG_RL_DATA_DATA | DAG_RL_OB_DATA, "Object Font"); - } - free_object_duplilist(duplilist); - } - - if (cu->textoncurve) { - node2 = dag_get_node(dag, cu->textoncurve); - /* Text on curve requires path to be evaluated for the target curve. */ - node2->eval_flags |= DAG_EVAL_NEED_CURVE_PATH; - dag_add_relation(dag, node2, node, DAG_RL_DATA_DATA | DAG_RL_OB_DATA, "Texture On Curve"); - } - } - break; - } - } - - /* material drivers */ - if (ob->totcol) { - int a; - - for (a = 1; a <= ob->totcol; a++) { - Material *ma = give_current_material(ob, a); - - if (ma) { - /* recursively figure out if there are drivers, and hook these up to this object */ - dag_add_material_driver_relations(dag, node, ma); - } - } - } - else if (ob->type == OB_LAMP) { - dag_add_lamp_driver_relations(dag, node, ob->data); - } - - /* particles */ - psys = ob->particlesystem.first; - if (psys) { - GroupObject *go; - - for (; psys; psys = psys->next) { - BoidRule *rule = NULL; - BoidState *state = NULL; - ParticleSettings *part = psys->part; - - if (part->adt) { - dag_add_driver_relation(part->adt, dag, node, 1); - } - - dag_add_relation(dag, node, node, DAG_RL_OB_DATA, "Particle-Object Relation"); - - if (!psys_check_enabled(ob, psys, G.is_rendering)) - continue; - - if (ELEM(part->phystype, PART_PHYS_KEYED, PART_PHYS_BOIDS)) { - ParticleTarget *pt = psys->targets.first; - - for (; pt; pt = pt->next) { - if (pt->ob && BLI_findlink(&pt->ob->particlesystem, pt->psys - 1)) { - node2 = dag_get_node(dag, pt->ob); - dag_add_relation(dag, node2, node, DAG_RL_DATA_DATA | DAG_RL_OB_DATA, "Particle Targets"); - } - } - } - - if (part->ren_as == PART_DRAW_OB && part->dup_ob) { - node2 = dag_get_node(dag, part->dup_ob); - /* note that this relation actually runs in the wrong direction, the problem - * is that dupli system all have this (due to parenting), and the render - * engine instancing assumes particular ordering of objects in list */ - dag_add_relation(dag, node, node2, DAG_RL_OB_OB, "Particle Object Visualization"); - if (part->dup_ob->type == OB_MBALL) - dag_add_relation(dag, node, node2, DAG_RL_DATA_DATA, "Particle Object Visualization"); - } - - if (part->ren_as == PART_DRAW_GR && part->dup_group) { - for (go = part->dup_group->gobject.first; go; go = go->next) { - node2 = dag_get_node(dag, go->ob); - dag_add_relation(dag, node2, node, DAG_RL_OB_OB, "Particle Group Visualization"); - } - } - - if (part->type != PART_HAIR) { - /* Actual code uses get_collider_cache */ - dag_add_collision_relations(dag, scene, ob, node, part->collision_group, ob->lay, eModifierType_Collision, NULL, true, "Particle Collision"); - } - else if ((psys->flag & PSYS_HAIR_DYNAMICS) && psys->clmd && psys->clmd->coll_parms) { - /* Hair uses cloth simulation, i.e. get_collision_objects */ - dag_add_collision_relations(dag, scene, ob, node, psys->clmd->coll_parms->group, ob->lay | scene->lay, eModifierType_Collision, NULL, true, "Hair Collision"); - } - - dag_add_forcefield_relations(dag, scene, ob, node, part->effector_weights, part->type == PART_HAIR, 0, "Particle Force Field"); - - if (part->boids) { - for (state = part->boids->states.first; state; state = state->next) { - for (rule = state->rules.first; rule; rule = rule->next) { - Object *ruleob = NULL; - if (rule->type == eBoidRuleType_Avoid) - ruleob = ((BoidRuleGoalAvoid *)rule)->ob; - else if (rule->type == eBoidRuleType_FollowLeader) - ruleob = ((BoidRuleFollowLeader *)rule)->ob; - - if (ruleob) { - node2 = dag_get_node(dag, ruleob); - dag_add_relation(dag, node2, node, DAG_RL_OB_DATA, "Boid Rule"); - } - } - } - } - } - } - - /* object constraints */ - for (con = ob->constraints.first; con; con = con->next) { - const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con); - ListBase targets = {NULL, NULL}; - bConstraintTarget *ct; - - if (!cti) - continue; - - /* special case for camera tracking -- it doesn't use targets to define relations */ - if (ELEM(cti->type, CONSTRAINT_TYPE_FOLLOWTRACK, CONSTRAINT_TYPE_CAMERASOLVER, CONSTRAINT_TYPE_OBJECTSOLVER)) { - int depends_on_camera = 0; - - if (cti->type == CONSTRAINT_TYPE_FOLLOWTRACK) { - bFollowTrackConstraint *data = (bFollowTrackConstraint *)con->data; - - if ((data->clip || data->flag & FOLLOWTRACK_ACTIVECLIP) && data->track[0]) - depends_on_camera = 1; - - if (data->depth_ob) { - node2 = dag_get_node(dag, data->depth_ob); - dag_add_relation(dag, node2, node, DAG_RL_DATA_OB | DAG_RL_OB_OB, cti->name); - } - } - else if (cti->type == CONSTRAINT_TYPE_OBJECTSOLVER) - depends_on_camera = 1; - - if (depends_on_camera && scene->camera) { - node2 = dag_get_node(dag, scene->camera); - dag_add_relation(dag, node2, node, DAG_RL_DATA_OB | DAG_RL_OB_OB, cti->name); - } - - dag_add_relation(dag, scenenode, node, DAG_RL_SCENE, "Scene Relation"); - addtoroot = 0; - } - else if (cti->get_constraint_targets) { - cti->get_constraint_targets(con, &targets); - - for (ct = targets.first; ct; ct = ct->next) { - Object *obt; - - if (ct->tar) - obt = ct->tar; - else - continue; - - node2 = dag_get_node(dag, obt); - if (ELEM(con->type, CONSTRAINT_TYPE_FOLLOWPATH, CONSTRAINT_TYPE_CLAMPTO)) - dag_add_relation(dag, node2, node, DAG_RL_DATA_OB | DAG_RL_OB_OB, cti->name); - else { - if (ELEM(obt->type, OB_ARMATURE, OB_MESH, OB_LATTICE) && (ct->subtarget[0])) { - dag_add_relation(dag, node2, node, DAG_RL_DATA_OB | DAG_RL_OB_OB, cti->name); - if (obt->type == OB_MESH) - node2->customdata_mask |= CD_MASK_MDEFORMVERT; - } - else - dag_add_relation(dag, node2, node, DAG_RL_OB_OB, cti->name); - } - addtoroot = 0; - } - - if (cti->flush_constraint_targets) - cti->flush_constraint_targets(con, &targets, 1); - } - } - - if (addtoroot == 1) - dag_add_relation(dag, scenenode, node, DAG_RL_SCENE, "Scene Relation"); -} - -static void build_dag_group(DagForest *dag, DagNode *scenenode, Main *bmain, Scene *scene, Group *group, short mask) -{ - GroupObject *go; - - if (group->id.tag & LIB_TAG_DOIT) - return; - - group->id.tag |= LIB_TAG_DOIT; - - for (go = group->gobject.first; go; go = go->next) { - build_dag_object(dag, scenenode, bmain, scene, go->ob, mask); - if (go->ob->dup_group) - build_dag_group(dag, scenenode, bmain, scene, go->ob->dup_group, mask); - } -} - -DagForest *build_dag(Main *bmain, Scene *sce, short mask) -{ - Base *base; - Object *ob; - DagNode *node; - DagNode *scenenode; - DagForest *dag; - DagAdjList *itA; - - dag = sce->theDag; - if (dag) - free_forest(dag); - else { - dag = dag_init(); - sce->theDag = dag; - } - dag->need_update = false; - - BKE_main_id_tag_idcode(bmain, ID_OB, LIB_TAG_DOIT, false); - - /* clear "LIB_TAG_DOIT" flag from all materials, to prevent infinite recursion problems later [#32017] */ - BKE_main_id_tag_idcode(bmain, ID_MA, LIB_TAG_DOIT, false); - BKE_main_id_tag_idcode(bmain, ID_LA, LIB_TAG_DOIT, false); - BKE_main_id_tag_idcode(bmain, ID_GR, LIB_TAG_DOIT, false); - - /* add base node for scene. scene is always the first node in DAG */ - scenenode = dag_add_node(dag, sce); - - /* add current scene objects */ - for (base = sce->base.first; base; base = base->next) { - ob = base->object; - ob->id.tag |= LIB_TAG_DOIT; - build_dag_object(dag, scenenode, bmain, sce, ob, mask); - if (ob->proxy) - build_dag_object(dag, scenenode, bmain, sce, ob->proxy, mask); - if (ob->dup_group) - build_dag_group(dag, scenenode, bmain, sce, ob->dup_group, mask); - } - - /* There might be situations when object from current scene depends on - * objects form other scene AND objects from other scene has own - * dependencies on objects from other scene. - * - * This is really important to include such indirect dependencies in order - * to keep threaded update safe but since we don't really know if object is - * coming from current scene or another scene we do rather stupid tag-based - * check here: all the objects for which build_dag_object() was called are - * getting tagged with LIB_TAG_DOIT. This way if some node has untagged - * object we know it's an object from other scene. - * - * It should be enough to to it once, because if there's longer chain of - * indirect dependencies, all the new nodes will be added to the end of the - * list, meaning we'll keep covering them in this for loop. - */ - for (node = sce->theDag->DagNode.first; node != NULL; node = node->next) { - if (node->type == ID_OB) { - ob = node->ob; - if ((ob->id.tag & LIB_TAG_DOIT) == 0) { - ob->id.tag |= LIB_TAG_DOIT; - build_dag_object(dag, scenenode, bmain, sce, ob, mask); - if (ob->proxy) - build_dag_object(dag, scenenode, bmain, sce, ob->proxy, mask); - if (ob->dup_group) - build_dag_group(dag, scenenode, bmain, sce, ob->dup_group, mask); - } - } - } - - BKE_main_id_tag_idcode(bmain, ID_GR, LIB_TAG_DOIT, false); - - /* Now all relations were built, but we need to solve 1 exceptional case; - * When objects have multiple "parents" (for example parent + constraint working on same object) - * the relation type has to be synced. One of the parents can change, and should give same event to child */ - - /* nodes were callocced, so we can use node->color for temporal storage */ - for (node = sce->theDag->DagNode.first; node; node = node->next) { - if (node->type == ID_OB) { - for (itA = node->child; itA; itA = itA->next) { - if (itA->node->type == ID_OB) { - itA->node->color |= itA->type; - } - } - - /* also flush custom data mask */ - ((Object *)node->ob)->customdata_mask = node->customdata_mask; - - if (node->parent == NULL) { - dag_add_relation(dag, scenenode, node, DAG_RL_SCENE, "Scene Relation"); - } - } - } - /* now set relations equal, so that when only one parent changes, the correct recalcs are found */ - for (node = sce->theDag->DagNode.first; node; node = node->next) { - if (node->type == ID_OB) { - for (itA = node->child; itA; itA = itA->next) { - if (itA->node->type == ID_OB) { - itA->type |= itA->node->color; - } - } - } - } - - /* cycle detection and solving */ - // solve_cycles(dag); - - return dag; -} - - -void free_forest(DagForest *Dag) -{ /* remove all nodes and deps */ - DagNode *tempN; - DagAdjList *tempA; - DagAdjList *itA; - DagNode *itN = Dag->DagNode.first; - - while (itN) { - itA = itN->child; - while (itA) { - tempA = itA; - itA = itA->next; - MEM_freeN(tempA); - } - - itA = itN->parent; - while (itA) { - tempA = itA; - itA = itA->next; - MEM_freeN(tempA); - } - - tempN = itN; - itN = itN->next; - MEM_freeN(tempN); - } - - BLI_ghash_free(Dag->nodeHash, NULL, NULL); - Dag->nodeHash = NULL; - Dag->DagNode.first = NULL; - Dag->DagNode.last = NULL; - Dag->numNodes = 0; - -} - -DagNode *dag_find_node(DagForest *forest, void *fob) -{ - if (forest->nodeHash) - return BLI_ghash_lookup(forest->nodeHash, fob); - - return NULL; -} - -static int dag_print_dependencies = 0; /* debugging */ - -/* no checking of existence, use dag_find_node first or dag_get_node */ -DagNode *dag_add_node(DagForest *forest, void *fob) -{ - DagNode *node; - - node = MEM_callocN(sizeof(DagNode), "DAG node"); - if (node) { - node->ob = fob; - node->color = DAG_WHITE; - - if (forest->ugly_hack_sorry) node->type = GS(((ID *) fob)->name); /* sorry, done for pose sorting */ - if (forest->numNodes) { - ((DagNode *) forest->DagNode.last)->next = node; - forest->DagNode.last = node; - forest->numNodes++; - } - else { - forest->DagNode.last = node; - forest->DagNode.first = node; - forest->numNodes = 1; - } - - if (!forest->nodeHash) - forest->nodeHash = BLI_ghash_ptr_new("dag_add_node gh"); - BLI_ghash_insert(forest->nodeHash, fob, node); - } - - return node; -} - -DagNode *dag_get_node(DagForest *forest, void *fob) -{ - DagNode *node; - - node = dag_find_node(forest, fob); - if (!node) - node = dag_add_node(forest, fob); - return node; -} - - - -DagNode *dag_get_sub_node(DagForest *forest, void *fob) -{ - DagNode *node; - DagAdjList *mainchild, *prev = NULL; - - mainchild = ((DagNode *) forest->DagNode.first)->child; - /* remove from first node (scene) adj list if present */ - while (mainchild) { - if (mainchild->node == fob) { - if (prev) { - prev->next = mainchild->next; - MEM_freeN(mainchild); - break; - } - else { - ((DagNode *) forest->DagNode.first)->child = mainchild->next; - MEM_freeN(mainchild); - break; - } - } - prev = mainchild; - mainchild = mainchild->next; - } - node = dag_find_node(forest, fob); - if (!node) - node = dag_add_node(forest, fob); - return node; -} - -static void dag_add_parent_relation(DagForest *UNUSED(forest), DagNode *fob1, DagNode *fob2, short rel, const char *name) -{ - DagAdjList *itA = fob2->parent; - - while (itA) { /* search if relation exist already */ - if (itA->node == fob1) { - itA->type |= rel; - itA->count += 1; - return; - } - itA = itA->next; - } - /* create new relation and insert at head. MALLOC alert! */ - itA = MEM_mallocN(sizeof(DagAdjList), "DAG adj list"); - itA->node = fob1; - itA->type = rel; - itA->count = 1; - itA->next = fob2->parent; - itA->name = name; - fob2->parent = itA; -} - -void dag_add_relation(DagForest *forest, DagNode *fob1, DagNode *fob2, short rel, const char *name) -{ - DagAdjList *itA = fob1->child; - - /* parent relation is for cycle checking */ - dag_add_parent_relation(forest, fob1, fob2, rel, name); - - /* TODO(sergey): Find a better place for this. */ -#ifdef WITH_OPENSUBDIV - if ((rel & (DAG_RL_DATA_DATA | DAG_RL_DATA_OB)) != 0) { - if (fob1->type == ID_OB) { - if ((fob1->eval_flags & DAG_EVAL_NEED_CPU) == 0) { - Object *ob2 = fob2->ob; - if (ob2->recalc & OB_RECALC_ALL) { - /* Make sure object has all the data on CPU. */ - Object *ob1 = fob1->ob; - ob1->recalc |= OB_RECALC_DATA; - } - fob1->eval_flags |= DAG_EVAL_NEED_CPU; - } - } - } -#endif - - while (itA) { /* search if relation exist already */ - if (itA->node == fob2) { - itA->type |= rel; - itA->count += 1; - return; - } - itA = itA->next; - } - /* create new relation and insert at head. MALLOC alert! */ - itA = MEM_mallocN(sizeof(DagAdjList), "DAG adj list"); - itA->node = fob2; - itA->type = rel; - itA->count = 1; - itA->next = fob1->child; - itA->name = name; - fob1->child = itA; -} - -static const char *dag_node_name(DagForest *dag, DagNode *node) -{ - if (node->ob == NULL) - return "null"; - else if (dag->ugly_hack_sorry) - return ((ID *)(node->ob))->name + 2; - else - return ((bPoseChannel *)(node->ob))->name; -} - -static void dag_node_print_dependencies(DagForest *dag, DagNode *node) -{ - DagAdjList *itA; - - printf("%s depends on:\n", dag_node_name(dag, node)); - - for (itA = node->parent; itA; itA = itA->next) - printf(" %s through %s\n", dag_node_name(dag, itA->node), itA->name); - printf("\n"); -} - -static int dag_node_print_dependency_recurs(DagForest *dag, DagNode *node, DagNode *endnode) -{ - DagAdjList *itA; - - if (node->color == DAG_BLACK) - return 0; - - node->color = DAG_BLACK; - - if (node == endnode) - return 1; - - for (itA = node->parent; itA; itA = itA->next) { - if (dag_node_print_dependency_recurs(dag, itA->node, endnode)) { - printf(" %s depends on %s through %s.\n", dag_node_name(dag, node), dag_node_name(dag, itA->node), itA->name); - return 1; - } - } - - return 0; -} - -static void dag_node_print_dependency_cycle(DagForest *dag, DagNode *startnode, DagNode *endnode, const char *name) -{ - DagNode *node; - - for (node = dag->DagNode.first; node; node = node->next) - node->color = DAG_WHITE; - - printf(" %s depends on %s through %s.\n", dag_node_name(dag, endnode), dag_node_name(dag, startnode), name); - dag_node_print_dependency_recurs(dag, startnode, endnode); - printf("\n"); -} - -static int dag_node_recurs_level(DagNode *node, int level) -{ - DagAdjList *itA; - int newlevel; - - node->color = DAG_BLACK; /* done */ - newlevel = ++level; - - for (itA = node->parent; itA; itA = itA->next) { - if (itA->node->color == DAG_WHITE) { - itA->node->ancestor_count = dag_node_recurs_level(itA->node, level); - newlevel = MAX2(newlevel, level + itA->node->ancestor_count); - } - else - newlevel = MAX2(newlevel, level + itA->node->ancestor_count); - } - - return newlevel; -} - -static void dag_check_cycle(DagForest *dag) -{ - DagNode *node; - DagAdjList *itA; - - dag->is_acyclic = true; - - /* debugging print */ - if (dag_print_dependencies) - for (node = dag->DagNode.first; node; node = node->next) - dag_node_print_dependencies(dag, node); - - /* tag nodes unchecked */ - for (node = dag->DagNode.first; node; node = node->next) - node->color = DAG_WHITE; - - for (node = dag->DagNode.first; node; node = node->next) { - if (node->color == DAG_WHITE) { - node->ancestor_count = dag_node_recurs_level(node, 0); - } - } - - /* check relations, and print errors */ - for (node = dag->DagNode.first; node; node = node->next) { - for (itA = node->parent; itA; itA = itA->next) { - if (itA->node->ancestor_count > node->ancestor_count) { - if (node->ob && itA->node->ob) { - dag->is_acyclic = false; - printf("Dependency cycle detected:\n"); - dag_node_print_dependency_cycle(dag, itA->node, node, itA->name); - } - } - } - } - - /* parent relations are only needed for cycle checking, so free now */ - for (node = dag->DagNode.first; node; node = node->next) { - while (node->parent) { - itA = node->parent->next; - MEM_freeN(node->parent); - node->parent = itA; - } - } -} - -/* debug test functions */ - -void graph_print_queue(DagNodeQueue *nqueue) -{ - DagNodeQueueElem *queueElem; - - queueElem = nqueue->first; - while (queueElem) { - fprintf(stderr, "** %s %i %i-%i ", ((ID *) queueElem->node->ob)->name, queueElem->node->color, queueElem->node->DFS_dvtm, queueElem->node->DFS_fntm); - queueElem = queueElem->next; - } - fprintf(stderr, "\n"); -} - -void graph_print_queue_dist(DagNodeQueue *nqueue) -{ - DagNodeQueueElem *queueElem; - int count; - - queueElem = nqueue->first; - count = 0; - while (queueElem) { - fprintf(stderr, "** %25s %2.2i-%2.2i ", ((ID *) queueElem->node->ob)->name, queueElem->node->DFS_dvtm, queueElem->node->DFS_fntm); - while (count < queueElem->node->DFS_dvtm - 1) { fputc(' ', stderr); count++; } - fputc('|', stderr); - while (count < queueElem->node->DFS_fntm - 2) { fputc('-', stderr); count++; } - fputc('|', stderr); - fputc('\n', stderr); - count = 0; - queueElem = queueElem->next; - } - fprintf(stderr, "\n"); -} - -void graph_print_adj_list(DagForest *dag) -{ - DagNode *node; - DagAdjList *itA; - - node = dag->DagNode.first; - while (node) { - fprintf(stderr, "node : %s col: %i", ((ID *) node->ob)->name, node->color); - itA = node->child; - while (itA) { - fprintf(stderr, "-- %s ", ((ID *) itA->node->ob)->name); - - itA = itA->next; - } - fprintf(stderr, "\n"); - node = node->next; - } -} - -/* ************************ API *********************** */ - -/* mechanism to allow editors to be informed of depsgraph updates, - * to do their own updates based on changes... */ -static void (*EditorsUpdateIDCb)(Main *bmain, ID *id) = NULL; -static void (*EditorsUpdateSceneCb)(Main *bmain, Scene *scene, int updated) = NULL; -static void (*EditorsUpdateScenePreCb)(Main *bmain, Scene *scene, bool time) = NULL; - -void DAG_editors_update_cb(void (*id_func)(Main *bmain, ID *id), - void (*scene_func)(Main *bmain, Scene *scene, int updated), - void (*scene_pre_func)(Main *bmain, Scene *scene, bool time)) -{ - if (DEG_depsgraph_use_legacy()) { - EditorsUpdateIDCb = id_func; - EditorsUpdateSceneCb = scene_func; - EditorsUpdateScenePreCb = scene_pre_func; - } - else { - /* New dependency graph. */ - DEG_editors_set_update_cb(id_func, scene_func, scene_pre_func); - } -} - -void DAG_editors_update_pre(Main *bmain, Scene *scene, bool time) -{ - if (DEG_depsgraph_use_legacy()) { - if (EditorsUpdateScenePreCb != NULL) { - EditorsUpdateScenePreCb(bmain, scene, time); - } - } - else { - DEG_editors_update_pre(bmain, scene, time); - } -} - -static void dag_editors_id_update(Main *bmain, ID *id) -{ - if (EditorsUpdateIDCb) - EditorsUpdateIDCb(bmain, id); -} - -static void dag_editors_scene_update(Main *bmain, Scene *scene, int updated) -{ - if (EditorsUpdateSceneCb) - EditorsUpdateSceneCb(bmain, scene, updated); -} - -/* groups with objects in this scene need to be put in the right order as well */ -static void scene_sort_groups(Main *bmain, Scene *sce) -{ - Base *base; - Group *group; - GroupObject *go; - Object *ob; - - /* test; are group objects all in this scene? */ - for (ob = bmain->object.first; ob; ob = ob->id.next) { - ob->id.tag &= ~LIB_TAG_DOIT; - } - for (base = sce->base.first; base; base = base->next) - base->object->id.tag |= LIB_TAG_DOIT; - - for (group = bmain->group.first; group; group = group->id.next) { - for (go = group->gobject.first; go; go = go->next) { - if ((go->ob->id.tag & LIB_TAG_DOIT) == 0) - break; - } - /* this group is entirely in this scene */ - if (go == NULL) { - ListBase listb = {NULL, NULL}; - - for (go = group->gobject.first; go; go = go->next) - go->ob->id.newid = (ID *)go; - - /* in order of sorted bases we reinsert group objects */ - for (base = sce->base.first; base; base = base->next) { - - if (base->object->id.newid) { - go = (GroupObject *)base->object->id.newid; - base->object->id.newid = NULL; - BLI_remlink(&group->gobject, go); - BLI_addtail(&listb, go); - } - } - /* copy the newly sorted listbase */ - group->gobject = listb; - } - } - - /* newid abused for GroupObject, cleanup. */ - for (ob = bmain->object.first; ob; ob = ob->id.next) { - ob->id.newid = NULL; - } -} - -static void dag_scene_tag_rebuild(Scene *sce) -{ - if (sce->theDag) { - sce->theDag->need_update = true; - } -} - -/* free the depency graph */ -static void dag_scene_free(Scene *sce) -{ - if (sce->theDag) { - free_forest(sce->theDag); - MEM_freeN(sce->theDag); - sce->theDag = NULL; - } -} - -/* Check whether object data needs to be evaluated before it - * might be used by others. - * - * Means that mesh object needs to have proper derivedFinal, - * curves-typed objects are to have proper curve cache. - * - * Other objects or objects which are tagged for data update are - * not considered to be in need of evaluation. - */ -static bool check_object_needs_evaluation(Object *object) -{ - if (object->recalc & OB_RECALC_ALL) { - /* Object is tagged for update anyway, no need to re-tag it. */ - return false; - } - - if (object->type == OB_MESH) { - return object->derivedFinal == NULL; - } - else if (ELEM(object->type, OB_CURVE, OB_SURF, OB_FONT, OB_MBALL, OB_LATTICE)) { - return object->curve_cache == NULL; - } - - return false; -} - -/* Check whether object data is tagged for update. */ -static bool check_object_tagged_for_update(Object *object) -{ - if (object->recalc & OB_RECALC_ALL) { - return true; - } - - if (ELEM(object->type, OB_MESH, OB_CURVE, OB_SURF, OB_FONT, OB_MBALL, OB_LATTICE)) { - ID *data_id = object->data; - return (data_id->tag & (LIB_TAG_ID_RECALC_DATA | LIB_TAG_ID_RECALC)) != 0; - } - - return false; -} - -/* Flush changes from tagged objects in the scene to their - * dependencies which are not evaluated yet. - * - * This is needed to ensure all the dependencies are met - * before objects gets handled by object_handle_update(), - * - * This is needed when visible layers are changed or changing - * scene graph layout which involved usage of objects which - * aren't in the scene or weren't visible yet. - */ -static void dag_invisible_dependencies_flush(Scene *scene) -{ - DagNode *root_node = scene->theDag->DagNode.first, *node; - DagNodeQueue *queue; - - for (node = root_node; node != NULL; node = node->next) { - node->color = DAG_WHITE; - } - - queue = queue_create(DAGQUEUEALLOC); - - for (node = root_node; node != NULL; node = node->next) { - if (node->color == DAG_WHITE) { - push_stack(queue, node); - node->color = DAG_GRAY; - - while (queue->count) { - DagNode *current_node = get_top_node_queue(queue); - DagAdjList *itA; - bool skip = false; - - for (itA = current_node->child; itA; itA = itA->next) { - if (itA->node->color == DAG_WHITE) { - itA->node->color = DAG_GRAY; - push_stack(queue, itA->node); - skip = true; - break; - } - } - - if (!skip) { - current_node = pop_queue(queue); - - if (current_node->type == ID_OB) { - Object *current_object = current_node->ob; - if (check_object_needs_evaluation(current_object)) { - for (itA = current_node->child; itA; itA = itA->next) { - if (itA->node->type == ID_OB) { - Object *object = itA->node->ob; - if (check_object_tagged_for_update(object)) { - current_object->recalc |= OB_RECALC_OB | OB_RECALC_DATA; - } - } - } - } - } - node->color = DAG_BLACK; - } - } - } - } - - queue_delete(queue); -} - -static void dag_invisible_dependencies_check_flush(Main *bmain, Scene *scene) -{ - if (DAG_id_type_tagged(bmain, ID_OB) || - DAG_id_type_tagged(bmain, ID_ME) || /* Mesh */ - DAG_id_type_tagged(bmain, ID_CU) || /* Curve */ - DAG_id_type_tagged(bmain, ID_MB) || /* MetaBall */ - DAG_id_type_tagged(bmain, ID_LT)) /* Lattice */ - { - dag_invisible_dependencies_flush(scene); - } -} - -/* sort the base list on dependency order */ -static void dag_scene_build(Main *bmain, Scene *sce) -{ - DagNode *node, *rootnode; - DagNodeQueue *nqueue; - DagAdjList *itA; - int time; - int skip = 0; - ListBase tempbase; - Base *base; - - BLI_listbase_clear(&tempbase); - - build_dag(bmain, sce, DAG_RL_ALL_BUT_DATA); - - dag_check_cycle(sce->theDag); - - nqueue = queue_create(DAGQUEUEALLOC); - - for (node = sce->theDag->DagNode.first; node; node = node->next) { - node->color = DAG_WHITE; - } - - time = 1; - - rootnode = sce->theDag->DagNode.first; - rootnode->color = DAG_GRAY; - time++; - push_stack(nqueue, rootnode); - - while (nqueue->count) { - - skip = 0; - node = get_top_node_queue(nqueue); - - itA = node->child; - while (itA != NULL) { - if (itA->node->color == DAG_WHITE) { - itA->node->DFS_dvtm = time; - itA->node->color = DAG_GRAY; - - time++; - push_stack(nqueue, itA->node); - skip = 1; - break; - } - itA = itA->next; - } - - if (!skip) { - if (node) { - node = pop_queue(nqueue); - if (node->ob == sce) /* we are done */ - break; - node->color = DAG_BLACK; - - time++; - base = sce->base.first; - while (base && base->object != node->ob) - base = base->next; - if (base) { - BLI_remlink(&sce->base, base); - BLI_addhead(&tempbase, base); - } - } - } - } - - /* temporal correction for circular dependencies */ - base = sce->base.first; - while (base) { - BLI_remlink(&sce->base, base); - BLI_addhead(&tempbase, base); - //if (G.debug & G_DEBUG) - printf("cyclic %s\n", base->object->id.name); - base = sce->base.first; - } - - sce->base = tempbase; - queue_delete(nqueue); - - /* all groups with objects in this scene gets resorted too */ - scene_sort_groups(bmain, sce); - - if (G.debug & G_DEBUG) { - printf("\nordered\n"); - for (base = sce->base.first; base; base = base->next) { - printf(" %s\n", base->object->id.name); - } - } - - /* Make sure that new dependencies which came from invisible layers - * are tagged for update (if they're needed for objects which were - * tagged for update). - */ - dag_invisible_dependencies_check_flush(bmain, sce); -} - -/* clear all dependency graphs */ -void DAG_relations_tag_update(Main *bmain) -{ - if (DEG_depsgraph_use_legacy()) { - Scene *sce; - for (sce = bmain->scene.first; sce; sce = sce->id.next) { - dag_scene_tag_rebuild(sce); - } - } - else { - /* New dependency graph. */ - DEG_relations_tag_update(bmain); - } -} - -/* rebuild dependency graph only for a given scene */ -void DAG_scene_relations_rebuild(Main *bmain, Scene *sce) -{ - if (DEG_depsgraph_use_legacy()) { - dag_scene_free(sce); - DAG_scene_relations_update(bmain, sce); - } - else { - /* New dependency graph. */ - DEG_scene_relations_rebuild(bmain, sce); - } -} - -/* create dependency graph if it was cleared or didn't exist yet */ -void DAG_scene_relations_update(Main *bmain, Scene *sce) -{ - if (DEG_depsgraph_use_legacy()) { - if (!sce->theDag || sce->theDag->need_update) - dag_scene_build(bmain, sce); - } - else { - /* New dependency graph. */ - DEG_scene_relations_update(bmain, sce); - } -} - -void DAG_scene_relations_validate(Main *bmain, Scene *sce) -{ - if (!DEG_depsgraph_use_legacy()) { - DEG_debug_scene_relations_validate(bmain, sce); - } -} - -void DAG_scene_free(Scene *sce) -{ - if (DEG_depsgraph_use_legacy()) { - if (sce->theDag) { - free_forest(sce->theDag); - MEM_freeN(sce->theDag); - sce->theDag = NULL; - } - } - else { - if (sce->depsgraph) { - DEG_graph_free(sce->depsgraph); - sce->depsgraph = NULL; - } - } -} - -static void lib_id_recalc_tag(Main *bmain, ID *id) -{ - id->tag |= LIB_TAG_ID_RECALC; - DAG_id_type_tag(bmain, GS(id->name)); -} - -static void lib_id_recalc_data_tag(Main *bmain, ID *id) -{ - id->tag |= LIB_TAG_ID_RECALC_DATA; - DAG_id_type_tag(bmain, GS(id->name)); -} - -/* node was checked to have lasttime != curtime and is if type ID_OB */ -static void flush_update_node(Main *bmain, DagNode *node, unsigned int layer, int curtime) -{ - DagAdjList *itA; - Object *ob, *obc; - int oldflag; - bool changed = false; - unsigned int all_layer; - - node->lasttime = curtime; - - ob = node->ob; - if (ob && (ob->recalc & OB_RECALC_ALL)) { - all_layer = node->scelay; - - /* got an object node that changes, now check relations */ - for (itA = node->child; itA; itA = itA->next) { - all_layer |= itA->lay; - /* the relationship is visible */ - if ((itA->lay & layer)) { // XXX || (itA->node->ob == obedit) - if (itA->node->type == ID_OB) { - obc = itA->node->ob; - oldflag = obc->recalc; - - /* got a ob->obc relation, now check if flag needs flush */ - if (ob->recalc & OB_RECALC_OB) { - if (itA->type & DAG_RL_OB_OB) { - //printf("ob %s changes ob %s\n", ob->id.name, obc->id.name); - obc->recalc |= OB_RECALC_OB; - lib_id_recalc_tag(bmain, &obc->id); - } - if (itA->type & DAG_RL_OB_DATA) { - //printf("ob %s changes obdata %s\n", ob->id.name, obc->id.name); - obc->recalc |= OB_RECALC_DATA; - lib_id_recalc_data_tag(bmain, &obc->id); - } - } - if (ob->recalc & OB_RECALC_DATA) { - if (itA->type & DAG_RL_DATA_OB) { - //printf("obdata %s changes ob %s\n", ob->id.name, obc->id.name); - obc->recalc |= OB_RECALC_OB; - lib_id_recalc_tag(bmain, &obc->id); - } - if (itA->type & DAG_RL_DATA_DATA) { - //printf("obdata %s changes obdata %s\n", ob->id.name, obc->id.name); - obc->recalc |= OB_RECALC_DATA; - lib_id_recalc_data_tag(bmain, &obc->id); - } - } - if (oldflag != obc->recalc) changed = 1; - } - } - } - /* even nicer, we can clear recalc flags... */ - if ((all_layer & layer) == 0) { // XXX && (ob != obedit)) { - /* but existing displaylists or derivedmesh should be freed */ - if (ob->recalc & OB_RECALC_DATA) - BKE_object_free_derived_caches(ob); - - ob->recalc &= ~OB_RECALC_ALL; - } - } - - /* check case where child changes and parent forcing obdata to change */ - /* should be done regardless if this ob has recalc set */ - /* could merge this in with loop above...? (ton) */ - for (itA = node->child; itA; itA = itA->next) { - /* the relationship is visible */ - if ((itA->lay & layer)) { // XXX || (itA->node->ob == obedit) - if (itA->node->type == ID_OB) { - obc = itA->node->ob; - /* child moves */ - if ((obc->recalc & OB_RECALC_ALL) == OB_RECALC_OB) { - /* parent has deforming info */ - if (itA->type & (DAG_RL_OB_DATA | DAG_RL_DATA_DATA)) { - // printf("parent %s changes ob %s\n", ob->id.name, obc->id.name); - obc->recalc |= OB_RECALC_DATA; - lib_id_recalc_data_tag(bmain, &obc->id); - } - } - } - } - } - - /* we only go deeper if node not checked or something changed */ - for (itA = node->child; itA; itA = itA->next) { - if (changed || itA->node->lasttime != curtime) - flush_update_node(bmain, itA->node, layer, curtime); - } - -} - -/* node was checked to have lasttime != curtime, and is of type ID_OB */ -static unsigned int flush_layer_node(Scene *sce, DagNode *node, int curtime) -{ - DagAdjList *itA; - - node->lasttime = curtime; - node->lay = node->scelay; - - for (itA = node->child; itA; itA = itA->next) { - if (itA->node->type == ID_OB) { - if (itA->node->lasttime != curtime) { - itA->lay = flush_layer_node(sce, itA->node, curtime); /* lay is only set once for each relation */ - } - else { - itA->lay = itA->node->lay; - } - - node->lay |= itA->lay; - } - } - - return node->lay; -} - -/* node was checked to have lasttime != curtime, and is of type ID_OB */ -static void flush_pointcache_reset(Main *bmain, Scene *scene, DagNode *node, - int curtime, unsigned int lay, bool reset) -{ - DagAdjList *itA; - Object *ob; - - node->lasttime = curtime; - - for (itA = node->child; itA; itA = itA->next) { - if (itA->node->type == ID_OB) { - if (itA->node->lasttime != curtime) { - ob = (Object *)(itA->node->ob); - - if (reset || (ob->recalc & OB_RECALC_ALL)) { - if (BKE_ptcache_object_reset(scene, ob, PTCACHE_RESET_DEPSGRAPH)) { - /* Don't tag nodes which are on invisible layer. */ - if (itA->node->lay & lay) { - ob->recalc |= OB_RECALC_DATA; - lib_id_recalc_data_tag(bmain, &ob->id); - } - } - - flush_pointcache_reset(bmain, scene, itA->node, curtime, lay, true); - } - else - flush_pointcache_reset(bmain, scene, itA->node, curtime, lay, false); - } - } - } -} - -/* flush layer flags to dependencies */ -static void dag_scene_flush_layers(Scene *sce, int lay) -{ - DagNode *node, *firstnode; - DagAdjList *itA; - Base *base; - int lasttime; - - firstnode = sce->theDag->DagNode.first; /* always scene node */ - - for (itA = firstnode->child; itA; itA = itA->next) - itA->lay = 0; - - sce->theDag->time++; /* so we know which nodes were accessed */ - lasttime = sce->theDag->time; - - /* update layer flags in nodes */ - for (base = sce->base.first; base; base = base->next) { - node = dag_get_node(sce->theDag, base->object); - node->scelay = base->object->lay; - } - - /* ensure cameras are set as if they are on a visible layer, because - * they ared still used for rendering or setting the camera view - * - * XXX, this wont work for local view / unlocked camera's */ - if (sce->camera) { - node = dag_get_node(sce->theDag, sce->camera); - node->scelay |= lay; - } - -#ifdef DURIAN_CAMERA_SWITCH - { - TimeMarker *m; - - for (m = sce->markers.first; m; m = m->next) { - if (m->camera) { - node = dag_get_node(sce->theDag, m->camera); - node->scelay |= lay; - } - } - } -#endif - - /* flush layer nodes to dependencies */ - for (itA = firstnode->child; itA; itA = itA->next) - if (itA->node->lasttime != lasttime && itA->node->type == ID_OB) - flush_layer_node(sce, itA->node, lasttime); -} - -static void dag_tag_renderlayers(Scene *sce, unsigned int lay) -{ - if (sce->nodetree) { - bNode *node; - Base *base; - unsigned int lay_changed = 0; - - for (base = sce->base.first; base; base = base->next) - if (base->lay & lay) - if (base->object->recalc) - lay_changed |= base->lay; - - for (node = sce->nodetree->nodes.first; node; node = node->next) { - if (node->id == (ID *)sce) { - SceneRenderLayer *srl = BLI_findlink(&sce->r.layers, node->custom1); - if (srl && (srl->lay & lay_changed)) - nodeUpdate(sce->nodetree, node); - } - } - } -} - -/* flushes all recalc flags in objects down the dependency tree */ -void DAG_scene_flush_update(Main *bmain, Scene *sce, unsigned int lay, const short time) -{ - DagNode *firstnode; - DagAdjList *itA; - Object *ob; - int lasttime; - - if (!DEG_depsgraph_use_legacy()) { - return; - } - - if (sce->theDag == NULL || sce->theDag->need_update) { - printf("DAG zero... not allowed to happen!\n"); - DAG_scene_relations_update(bmain, sce); - } - - firstnode = sce->theDag->DagNode.first; /* always scene node */ - - /* first we flush the layer flags */ - dag_scene_flush_layers(sce, lay); - - /* then we use the relationships + layer info to flush update events */ - sce->theDag->time++; /* so we know which nodes were accessed */ - lasttime = sce->theDag->time; - for (itA = firstnode->child; itA; itA = itA->next) - if (itA->node->lasttime != lasttime && itA->node->type == ID_OB) - flush_update_node(bmain, itA->node, lay, lasttime); - - /* if update is not due to time change, do pointcache clears */ - if (!time) { - sce->theDag->time++; /* so we know which nodes were accessed */ - lasttime = sce->theDag->time; - for (itA = firstnode->child; itA; itA = itA->next) { - if (itA->node->lasttime != lasttime && itA->node->type == ID_OB) { - ob = (Object *)(itA->node->ob); - - if (ob->recalc & OB_RECALC_ALL) { - if (BKE_ptcache_object_reset(sce, ob, PTCACHE_RESET_DEPSGRAPH)) { - ob->recalc |= OB_RECALC_DATA; - lib_id_recalc_data_tag(bmain, &ob->id); - } - - flush_pointcache_reset(bmain, sce, itA->node, lasttime, - lay, true); - } - else - flush_pointcache_reset(bmain, sce, itA->node, lasttime, - lay, false); - } - } - } - - dag_tag_renderlayers(sce, lay); -} - -static bool modifier_nlastrips_use_time(ListBase *strips) -{ - NlaStrip *strip; - - if (strips) { - for (strip = strips->first; strip; strip = strip->next) { - if (modifier_nlastrips_use_time(&strip->strips)) { - return true; - } - else if (strip->act) { - FCurve *fcu; - - for (fcu = strip->act->curves.first; fcu; fcu = fcu->next) { - if (fcu->rna_path && strstr(fcu->rna_path, "modifiers[")) - return true; - } - } - } - } - - return false; -} - -static bool object_modifiers_use_time(Object *ob) -{ - ModifierData *md; - - /* check if a modifier in modifier stack needs time input */ - for (md = ob->modifiers.first; md; md = md->next) { - if (modifier_dependsOnTime(md)) - return true; - } - - /* check whether any modifiers are animated */ - if (ob->adt) { - AnimData *adt = ob->adt; - NlaTrack *nlt; - FCurve *fcu; - - /* action - check for F-Curves with paths containing 'modifiers[' */ - if (adt->action) { - for (fcu = adt->action->curves.first; fcu; fcu = fcu->next) { - if (fcu->rna_path && strstr(fcu->rna_path, "modifiers[")) - return true; - } - } - - /* This here allows modifier properties to get driven and still update properly - * - * Workaround to get [#26764] (e.g. subsurf levels not updating when animated/driven) - * working, without the updating problems ([#28525] [#28690] [#28774] [#28777]) caused - * by the RNA updates cache introduced in r.38649 - */ - for (fcu = adt->drivers.first; fcu; fcu = fcu->next) { - if (fcu->rna_path && strstr(fcu->rna_path, "modifiers[")) - return true; - } - - /* Also check NLA Strips... [#T45938] */ - for (nlt = adt->nla_tracks.first; nlt; nlt = nlt->next) { - if (modifier_nlastrips_use_time(&nlt->strips)) - return true; - } - } - - return false; -} - -static short animdata_use_time(AnimData *adt) -{ - NlaTrack *nlt; - - if (adt == NULL) return 0; - - /* check action - only if assigned, and it has anim curves */ - if (adt->action && adt->action->curves.first) - return 1; - - /* check NLA tracks + strips */ - for (nlt = adt->nla_tracks.first; nlt; nlt = nlt->next) { - if (nlt->strips.first) - return 1; - } - - /* If we have drivers, more likely than not, on a frame change - * they'll need updating because their owner changed - * - * This is kindof a hack to get around a whole host of problems - * involving drivers using non-object datablock data (which the - * depsgraph currently has no way of representing let alone correctly - * dependency sort+tagging). By doing this, at least we ensure that - * some commonly attempted drivers (such as scene -> current frame; - * see "Driver updates fail" thread on Bf-committers dated July 2) - * will work correctly, and that other non-object datablocks will have - * their drivers update at least on frame change. - * - * -- Aligorith, July 4 2011 - */ - if (adt->drivers.first) - return 1; - - return 0; -} - -static void dag_object_time_update_flags(Main *bmain, Scene *scene, Object *ob) -{ - if (ob->constraints.first) { - bConstraint *con; - for (con = ob->constraints.first; con; con = con->next) { - const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con); - ListBase targets = {NULL, NULL}; - bConstraintTarget *ct; - - if (cti) { - /* special case for camera tracking -- it doesn't use targets to define relations */ - if (ELEM(cti->type, - CONSTRAINT_TYPE_FOLLOWTRACK, - CONSTRAINT_TYPE_CAMERASOLVER, - CONSTRAINT_TYPE_OBJECTSOLVER, - CONSTRAINT_TYPE_TRANSFORM_CACHE)) - { - ob->recalc |= OB_RECALC_OB; - } - else if (cti->get_constraint_targets) { - cti->get_constraint_targets(con, &targets); - - for (ct = targets.first; ct; ct = ct->next) { - if (ct->tar) { - ob->recalc |= OB_RECALC_OB; - break; - } - } - - if (cti->flush_constraint_targets) - cti->flush_constraint_targets(con, &targets, 1); - } - - } - } - } - - if (ob->parent) { - /* motion path or bone child */ - if (ob->parent->type == OB_CURVE || ob->parent->type == OB_ARMATURE) ob->recalc |= OB_RECALC_OB; - } - -#if 0 // XXX old animation system - if (ob->nlastrips.first) { - if (ob->dup_group) { - bActionStrip *strip; - /* this case is for groups with nla, whilst nla target has no action or nla */ - for (strip = ob->nlastrips.first; strip; strip = strip->next) { - if (strip->object) - strip->object->recalc |= OB_RECALC_ALL; - } - } - } -#endif // XXX old animation system - - if (animdata_use_time(ob->adt)) { - ob->recalc |= OB_RECALC_OB; - ob->adt->recalc |= ADT_RECALC_ANIM; - } - - if ((ob->adt) && (ob->type == OB_ARMATURE)) ob->recalc |= OB_RECALC_DATA; - - if (object_modifiers_use_time(ob)) ob->recalc |= OB_RECALC_DATA; - if ((ob->pose) && (ob->pose->flag & POSE_CONSTRAINTS_TIMEDEPEND)) ob->recalc |= OB_RECALC_DATA; - - // XXX: scene here may not be the scene that contains the rigidbody world affecting this! - if (ob->rigidbody_object && BKE_scene_check_rigidbody_active(scene)) - ob->recalc |= OB_RECALC_OB; - - { - AnimData *adt = BKE_animdata_from_id((ID *)ob->data); - Mesh *me; - Curve *cu; - Lattice *lt; - - switch (ob->type) { - case OB_MESH: - me = ob->data; - if (me->key) { - if (!(ob->shapeflag & OB_SHAPE_LOCK)) { - ob->recalc |= OB_RECALC_DATA; - } - } - if (ob->particlesystem.first) - ob->recalc |= OB_RECALC_DATA; - break; - case OB_CURVE: - case OB_SURF: - cu = ob->data; - if (cu->key) { - if (!(ob->shapeflag & OB_SHAPE_LOCK)) { - ob->recalc |= OB_RECALC_DATA; - } - } - break; - case OB_FONT: - cu = ob->data; - if (BLI_listbase_is_empty(&cu->nurb) && cu->str && cu->vfont) - ob->recalc |= OB_RECALC_DATA; - break; - case OB_LATTICE: - lt = ob->data; - if (lt->key) { - if (!(ob->shapeflag & OB_SHAPE_LOCK)) { - ob->recalc |= OB_RECALC_DATA; - } - } - break; - case OB_MBALL: - if (ob->transflag & OB_DUPLI) ob->recalc |= OB_RECALC_DATA; - break; - case OB_EMPTY: - /* update animated images */ - if (ob->empty_drawtype == OB_EMPTY_IMAGE && ob->data) - if (BKE_image_is_animated(ob->data)) - ob->recalc |= OB_RECALC_DATA; - break; - } - - if (animdata_use_time(adt)) { - ob->recalc |= OB_RECALC_DATA; - adt->recalc |= ADT_RECALC_ANIM; - } - - if (ob->particlesystem.first) { - ParticleSystem *psys = ob->particlesystem.first; - - for (; psys; psys = psys->next) { - if (psys_check_enabled(ob, psys, G.is_rendering)) { - ob->recalc |= OB_RECALC_DATA; - break; - } - } - } - } - - if (ob->recalc & OB_RECALC_OB) - lib_id_recalc_tag(bmain, &ob->id); - if (ob->recalc & OB_RECALC_DATA) - lib_id_recalc_data_tag(bmain, &ob->id); - -} - -/* recursively update objects in groups, each group is done at most once */ -static void dag_group_update_flags(Main *bmain, Scene *scene, Group *group, const bool do_time) -{ - GroupObject *go; - - if (group->id.tag & LIB_TAG_DOIT) - return; - - group->id.tag |= LIB_TAG_DOIT; - - for (go = group->gobject.first; go; go = go->next) { - if (do_time) - dag_object_time_update_flags(bmain, scene, go->ob); - if (go->ob->dup_group) - dag_group_update_flags(bmain, scene, go->ob->dup_group, do_time); - } -} - -/* flag all objects that need recalc, for changes in time for example */ -/* do_time: make this optional because undo resets objects to their animated locations without this */ -void DAG_scene_update_flags(Main *bmain, Scene *scene, unsigned int lay, const bool do_time, const bool do_invisible_flush) -{ - Base *base; - Object *ob; - Group *group; - GroupObject *go; - Scene *sce_iter; - - BKE_main_id_tag_idcode(bmain, ID_GR, LIB_TAG_DOIT, false); - - /* set ob flags where animated systems are */ - for (SETLOOPER(scene, sce_iter, base)) { - ob = base->object; - - if (do_time) { - /* now if DagNode were part of base, the node->lay could be checked... */ - /* we do all now, since the scene_flush checks layers and clears recalc flags even */ - - /* NOTE: "sce_iter" not "scene" so that rigidbodies in background scenes work - * (i.e. muting + rbw availability can be checked and tagged properly) [#33970] - */ - dag_object_time_update_flags(bmain, sce_iter, ob); - } - - /* recursively tag groups with LIB_TAG_DOIT, and update flags for objects */ - if (ob->dup_group) - dag_group_update_flags(bmain, scene, ob->dup_group, do_time); - } - - for (sce_iter = scene; sce_iter; sce_iter = sce_iter->set) - DAG_scene_flush_update(bmain, sce_iter, lay, 1); - - if (do_time) { - /* test: set time flag, to disable baked systems to update */ - for (SETLOOPER(scene, sce_iter, base)) { - ob = base->object; - if (ob->recalc & OB_RECALC_ALL) - ob->recalc |= OB_RECALC_TIME; - } - - /* hrmf... an exception to look at once, for invisible camera object we do it over */ - if (scene->camera) - dag_object_time_update_flags(bmain, scene, scene->camera); - } - - /* and store the info in groupobject */ - for (group = bmain->group.first; group; group = group->id.next) { - if (group->id.tag & LIB_TAG_DOIT) { - for (go = group->gobject.first; go; go = go->next) { - go->recalc = go->ob->recalc; - // printf("ob %s recalc %d\n", go->ob->id.name, go->recalc); - } - group->id.tag &= ~LIB_TAG_DOIT; - } - } - - if (do_invisible_flush) { - dag_invisible_dependencies_check_flush(bmain, scene); - } -} - -/* struct returned by DagSceneLayer */ -typedef struct DagSceneLayer { - struct DagSceneLayer *next, *prev; - Scene *scene; - unsigned int layer; -} DagSceneLayer; - -/* returns visible scenes with valid DAG */ -static void dag_current_scene_layers(Main *bmain, ListBase *lb) -{ - wmWindowManager *wm; - wmWindow *win; - - BLI_listbase_clear(lb); - - /* if we have a windowmanager, look into windows */ - if ((wm = bmain->wm.first)) { - - BKE_main_id_flag_listbase(&bmain->scene, LIB_TAG_DOIT, 1); - - for (win = wm->windows.first; win; win = win->next) { - if (win->screen && win->screen->scene->theDag) { - Scene *scene = win->screen->scene; - DagSceneLayer *dsl; - - if (scene->id.tag & LIB_TAG_DOIT) { - dsl = MEM_mallocN(sizeof(DagSceneLayer), "dag scene layer"); - - BLI_addtail(lb, dsl); - - dsl->scene = scene; - dsl->layer = BKE_screen_visible_layers(win->screen, scene); - - scene->id.tag &= ~LIB_TAG_DOIT; - } - else { - /* It is possible that multiple windows shares the same scene - * and have different layers visible. - * - * Here we deal with such cases by squashing layers bits from - * multiple windoew to the DagSceneLayer. - * - * TODO(sergey): Such a lookup could be optimized perhaps, - * however should be fine for now since we usually have only - * few open windows. - */ - for (dsl = lb->first; dsl; dsl = dsl->next) { - if (dsl->scene == scene) { - dsl->layer |= BKE_screen_visible_layers(win->screen, scene); - break; - } - } - } - } - } - } - else { - /* if not, use the first sce */ - DagSceneLayer *dsl = MEM_mallocN(sizeof(DagSceneLayer), "dag scene layer"); - - BLI_addtail(lb, dsl); - - dsl->scene = bmain->scene.first; - dsl->layer = dsl->scene->lay; - - /* XXX for background mode, we should get the scene - * from somewhere, for the -S option, but it's in - * the context, how to get it here? */ - } -} - -static void dag_group_on_visible_update(Scene *scene, Group *group) -{ - GroupObject *go; - - if (group->id.tag & LIB_TAG_DOIT) - return; - - group->id.tag |= LIB_TAG_DOIT; - - for (go = group->gobject.first; go; go = go->next) { - if (ELEM(go->ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_FONT, OB_MBALL, OB_LATTICE)) { - go->ob->recalc |= OB_RECALC_DATA; - go->ob->id.tag |= LIB_TAG_DOIT; - lib_id_recalc_tag(G.main, &go->ob->id); - } - if (go->ob->proxy_from) { - go->ob->recalc |= OB_RECALC_OB; - go->ob->id.tag |= LIB_TAG_DOIT; - lib_id_recalc_tag(G.main, &go->ob->id); - } - - if (go->ob->dup_group) - dag_group_on_visible_update(scene, go->ob->dup_group); - } -} - -void DAG_on_visible_update(Main *bmain, const bool do_time) -{ - ListBase listbase; - DagSceneLayer *dsl; - - if (!DEG_depsgraph_use_legacy()) { - /* Inform new dependnecy graphs about visibility changes. */ - DEG_on_visible_update(bmain, do_time); - return; - } - - /* get list of visible scenes and layers */ - dag_current_scene_layers(bmain, &listbase); - - for (dsl = listbase.first; dsl; dsl = dsl->next) { - Scene *scene = dsl->scene; - Scene *sce_iter; - Base *base; - Object *ob; - DagNode *node; - unsigned int lay = dsl->layer, oblay; - - /* derivedmeshes and displists are not saved to file so need to be - * remade, tag them so they get remade in the scene update loop, - * note armature poses or object matrices are preserved and do not - * require updates, so we skip those */ - for (sce_iter = scene; sce_iter; sce_iter = sce_iter->set) - dag_scene_flush_layers(sce_iter, lay); - - BKE_main_id_tag_idcode(bmain, ID_GR, LIB_TAG_DOIT, false); - - for (SETLOOPER(scene, sce_iter, base)) { - ob = base->object; - node = (sce_iter->theDag) ? dag_get_node(sce_iter->theDag, ob) : NULL; - oblay = (node) ? node->lay : ob->lay; - - if ((oblay & lay) & ~scene->lay_updated) { - /* TODO(sergey): Why do we need armature here now but didn't need before? */ - if (ELEM(ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_FONT, OB_MBALL, OB_LATTICE, OB_ARMATURE)) { - ob->recalc |= OB_RECALC_DATA; - lib_id_recalc_tag(bmain, &ob->id); - } - /* This should not be needed here, but in some cases, like after a redo, we can end up with - * a wrong final matrix (see T42472). - * Quoting Sergey, this comes from BKE_object_handle_update_ex, which is calling - * BKE_object_where_is_calc_ex when it shouldn't, but that issue is not easily fixable. - */ - else { - ob->recalc |= OB_RECALC_OB; - lib_id_recalc_tag(bmain, &ob->id); - } - if (ob->proxy && (ob->proxy_group == NULL)) { - ob->proxy->recalc |= OB_RECALC_DATA; - lib_id_recalc_tag(bmain, &ob->id); - } - if (ob->dup_group) - dag_group_on_visible_update(scene, ob->dup_group); - } - } - - BKE_main_id_tag_idcode(bmain, ID_GR, LIB_TAG_DOIT, false); - - /* now tag update flags, to ensure deformers get calculated on redraw */ - DAG_scene_update_flags(bmain, scene, lay, do_time, true); - scene->lay_updated |= lay; - } - - BLI_freelistN(&listbase); - - /* hack to get objects updating on layer changes */ - DAG_id_type_tag(bmain, ID_OB); - - /* so masks update on load */ - if (bmain->mask.first) { - Mask *mask; - - for (mask = bmain->mask.first; mask; mask = mask->id.next) { - DAG_id_tag_update(&mask->id, 0); - } - } -} - -static void dag_id_flush_update__isDependentTexture( - void *userData, Object *UNUSED(ob), ID **idpoin, int UNUSED(cb_flag)) -{ - struct { ID *id; bool is_dependent; } *data = userData; - - if (*idpoin && GS((*idpoin)->name) == ID_TE) { - if (data->id == (*idpoin)) - data->is_dependent = 1; - } -} - -static void dag_id_flush_update(Main *bmain, Scene *sce, ID *id) -{ - Object *obt, *ob = NULL; - short idtype; - - /* here we flush a few things before actual scene wide flush, mostly - * due to only objects and not other datablocks being in the depsgraph */ - - /* set flags & pointcache for object */ - if (GS(id->name) == ID_OB) { - ob = (Object *)id; - BKE_ptcache_object_reset(sce, ob, PTCACHE_RESET_DEPSGRAPH); - - /* So if someone tagged object recalc directly, - * id_tag_update bit-field stays relevant - */ - if (ob->recalc & OB_RECALC_ALL) { - DAG_id_type_tag(bmain, GS(id->name)); - } - - if (ob->recalc & OB_RECALC_DATA) { - /* all users of this ob->data should be checked */ - id = ob->data; - - /* no point in trying in this cases */ - if (id && id->us <= 1) { - dag_editors_id_update(bmain, id); - id = NULL; - } - } - } - - /* set flags & pointcache for object data */ - if (id) { - idtype = GS(id->name); - - - if (OB_DATA_SUPPORT_ID(idtype)) { - for (obt = bmain->object.first; obt; obt = obt->id.next) { - if (!(ob && obt == ob) && obt->data == id) { - obt->recalc |= OB_RECALC_DATA; - lib_id_recalc_data_tag(bmain, &obt->id); - BKE_ptcache_object_reset(sce, obt, PTCACHE_RESET_DEPSGRAPH); - } - } - } - else if (idtype == ID_VF) { - for (obt = bmain->object.first; obt; obt = obt->id.next) { - if (obt->type == OB_FONT) { - Curve *cu = obt->data; - if (ELEM((struct VFont *)id, CURVE_VFONT_ANY(cu))) { - obt->recalc |= OB_RECALC_DATA; - lib_id_recalc_data_tag(bmain, &obt->id); - } - } - } - } - - /* set flags based on textures - can influence depgraph via modifiers */ - if (idtype == ID_TE) { - for (obt = bmain->object.first; obt; obt = obt->id.next) { - struct { ID *id; bool is_dependent; } data; - data.id = id; - data.is_dependent = 0; - - modifiers_foreachIDLink(obt, dag_id_flush_update__isDependentTexture, &data); - if (data.is_dependent) { - obt->recalc |= OB_RECALC_DATA; - lib_id_recalc_data_tag(bmain, &obt->id); - } - - /* particle settings can use the texture as well */ - if (obt->particlesystem.first) { - ParticleSystem *psys = obt->particlesystem.first; - MTex **mtexp, *mtex; - int a; - for (; psys; psys = psys->next) { - mtexp = psys->part->mtex; - for (a = 0; a < MAX_MTEX; a++, mtexp++) { - mtex = *mtexp; - if (mtex && mtex->tex == (Tex *)id) { - obt->recalc |= OB_RECALC_DATA; - lib_id_recalc_data_tag(bmain, &obt->id); - - if (mtex->mapto & PAMAP_INIT) - psys->recalc |= PSYS_RECALC_RESET; - if (mtex->mapto & PAMAP_CHILD) - psys->recalc |= PSYS_RECALC_CHILD; - - BKE_ptcache_object_reset(sce, obt, PTCACHE_RESET_DEPSGRAPH); - } - } - } - } - } - } - - /* set flags based on ShapeKey */ - if (idtype == ID_KE) { - for (obt = bmain->object.first; obt; obt = obt->id.next) { - Key *key = BKE_key_from_object(obt); - if (!(ob && obt == ob) && ((ID *)key == id)) { - obt->flag |= (OB_RECALC_OB | OB_RECALC_DATA); - lib_id_recalc_tag(bmain, &obt->id); - lib_id_recalc_data_tag(bmain, &obt->id); - BKE_ptcache_object_reset(sce, obt, PTCACHE_RESET_DEPSGRAPH); - } - } - } - - /* set flags based on particle settings */ - if (idtype == ID_PA) { - ParticleSystem *psys; - for (obt = bmain->object.first; obt; obt = obt->id.next) - for (psys = obt->particlesystem.first; psys; psys = psys->next) - if (&psys->part->id == id) - BKE_ptcache_object_reset(sce, obt, PTCACHE_RESET_DEPSGRAPH); - } - - if (ELEM(idtype, ID_MA, ID_TE)) { - obt = sce->basact ? sce->basact->object : NULL; - if (obt && obt->mode & OB_MODE_TEXTURE_PAINT) { - BKE_texpaint_slots_refresh_object(sce, obt); - BKE_paint_proj_mesh_data_check(sce, obt, NULL, NULL, NULL, NULL); - GPU_drawobject_free(obt->derivedFinal); - } - } - - if (idtype == ID_MC) { - MovieClip *clip = (MovieClip *) id; - - BKE_tracking_dopesheet_tag_update(&clip->tracking); - - for (obt = bmain->object.first; obt; obt = obt->id.next) { - bConstraint *con; - for (con = obt->constraints.first; con; con = con->next) { - const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con); - if (ELEM(cti->type, CONSTRAINT_TYPE_FOLLOWTRACK, CONSTRAINT_TYPE_CAMERASOLVER, - CONSTRAINT_TYPE_OBJECTSOLVER)) - { - obt->recalc |= OB_RECALC_OB; - lib_id_recalc_tag(bmain, &obt->id); - break; - } - } - } - - if (sce->nodetree) { - bNode *node; - - for (node = sce->nodetree->nodes.first; node; node = node->next) { - if (node->id == id) { - nodeUpdate(sce->nodetree, node); - } - } - } - } - - /* Not pretty to iterate all the nodes here, but it's as good as it - * could be with the current depsgraph design/ - */ - if (idtype == ID_IM) { - FOREACH_NODETREE(bmain, ntree, parent_id) { - if (ntree->type == NTREE_SHADER) { - bNode *node; - for (node = ntree->nodes.first; node; node = node->next) { - if (node->id == id) { - lib_id_recalc_tag(bmain, &ntree->id); - break; - } - } - } - } FOREACH_NODETREE_END - } - - if (idtype == ID_MSK) { - if (sce->nodetree) { - bNode *node; - - for (node = sce->nodetree->nodes.first; node; node = node->next) { - if (node->id == id) { - nodeUpdate(sce->nodetree, node); - } - } - } - } - - /* camera's matrix is used to orient reconstructed stuff, - * so it should happen tracking-related constraints recalculation - * when camera is changing (sergey) */ - if (sce->camera && &sce->camera->id == id) { - MovieClip *clip = BKE_object_movieclip_get(sce, sce->camera, true); - - if (clip) - dag_id_flush_update(bmain, sce, &clip->id); - } - - /* update editors */ - dag_editors_id_update(bmain, id); - } -} - -void DAG_ids_flush_tagged(Main *bmain) -{ - ListBase listbase; - DagSceneLayer *dsl; - ListBase *lbarray[MAX_LIBARRAY]; - int a; - bool do_flush = false; - - if (!DEG_depsgraph_use_legacy()) { - DEG_ids_flush_tagged(bmain); - return; - } - - /* get list of visible scenes and layers */ - dag_current_scene_layers(bmain, &listbase); - - if (BLI_listbase_is_empty(&listbase)) - return; - - /* loop over all ID types */ - a = set_listbasepointers(bmain, lbarray); - - while (a--) { - ListBase *lb = lbarray[a]; - ID *id = lb->first; - - if (id && bmain->id_tag_update[BKE_idcode_to_index(GS(id->name))]) { - for (; id; id = id->next) { - if (id->tag & (LIB_TAG_ID_RECALC | LIB_TAG_ID_RECALC_DATA)) { - - for (dsl = listbase.first; dsl; dsl = dsl->next) - dag_id_flush_update(bmain, dsl->scene, id); - - do_flush = true; - } - } - } - } - - /* flush changes to other objects */ - if (do_flush) { - for (dsl = listbase.first; dsl; dsl = dsl->next) - DAG_scene_flush_update(bmain, dsl->scene, dsl->layer, 0); - } - - BLI_freelistN(&listbase); -} - -void DAG_ids_check_recalc(Main *bmain, Scene *scene, bool time) -{ - ListBase *lbarray[MAX_LIBARRAY]; - int a; - bool updated = false; - - if (!DEG_depsgraph_use_legacy()) { - DEG_ids_check_recalc(bmain, scene, time); - return; - } - - /* loop over all ID types */ - a = set_listbasepointers(bmain, lbarray); - - while (a--) { - ListBase *lb = lbarray[a]; - ID *id = lb->first; - - if (id && bmain->id_tag_update[BKE_idcode_to_index(GS(id->name))]) { - updated = true; - break; - } - } - - dag_editors_scene_update(bmain, scene, (updated || time)); -} - -/* It is possible that scene_update_post and frame_update_post handlers - * will modify objects. The issue is that DAG_ids_clear_recalc is called - * just after callbacks, which leaves objects with recalc flags but no - * corresponding bit in ID recalc bitfield. This leads to some kind of - * regression when using ID type tag fields to check whether there objects - * to be updated internally comparing threaded DAG with legacy one. - * - * For now let's have a workaround which will preserve tag for ID_OB - * if there're objects with OB_RECALC_ALL bits. This keeps behavior - * unchanged comparing with 2.69 release. - * - * TODO(sergey): Need to get rid of such a workaround. - * - * - sergey - - */ - -#define POST_UPDATE_HANDLER_WORKAROUND - -void DAG_ids_clear_recalc(Main *bmain) -{ - ListBase *lbarray[MAX_LIBARRAY]; - bNodeTree *ntree; - int a; - -#ifdef POST_UPDATE_HANDLER_WORKAROUND - bool have_updated_objects = false; - - if (DAG_id_type_tagged(bmain, ID_OB)) { - ListBase listbase; - DagSceneLayer *dsl; - - /* We need to check all visible scenes, otherwise resetting - * OB_ID changed flag will only work fine for first scene of - * multiple visible and all the rest will skip update. - * - * This could also lead to wrong behavior scene update handlers - * because of missing ID datablock changed flags. - * - * This is a bit of a bummer to allocate list here, but likely - * it wouldn't become too much bad because it only happens when - * objects were actually changed. - */ - dag_current_scene_layers(bmain, &listbase); - - for (dsl = listbase.first; dsl; dsl = dsl->next) { - Scene *scene = dsl->scene; - DagNode *node; - for (node = scene->theDag->DagNode.first; - node != NULL && have_updated_objects == false; - node = node->next) - { - if (node->type == ID_OB) { - Object *object = (Object *) node->ob; - if (object->recalc & OB_RECALC_ALL) { - have_updated_objects = true; - break; - } - } - } - } - - BLI_freelistN(&listbase); - } -#endif - - /* loop over all ID types */ - a = set_listbasepointers(bmain, lbarray); - - while (a--) { - ListBase *lb = lbarray[a]; - ID *id = lb->first; - - if (id && bmain->id_tag_update[BKE_idcode_to_index(GS(id->name))]) { - for (; id; id = id->next) { - if (id->tag & (LIB_TAG_ID_RECALC | LIB_TAG_ID_RECALC_DATA)) - id->tag &= ~(LIB_TAG_ID_RECALC | LIB_TAG_ID_RECALC_DATA); - - /* some ID's contain semi-datablock nodetree */ - ntree = ntreeFromID(id); - if (ntree && (ntree->id.tag & (LIB_TAG_ID_RECALC | LIB_TAG_ID_RECALC_DATA))) - ntree->id.tag &= ~(LIB_TAG_ID_RECALC | LIB_TAG_ID_RECALC_DATA); - } - } - } - - memset(bmain->id_tag_update, 0, sizeof(bmain->id_tag_update)); - -#ifdef POST_UPDATE_HANDLER_WORKAROUND - if (have_updated_objects) { - DAG_id_type_tag(bmain, ID_OB); - } -#endif -} - -void DAG_id_tag_update_ex(Main *bmain, ID *id, short flag) -{ - if (!DEG_depsgraph_use_legacy()) { - DEG_id_tag_update_ex(bmain, id, flag); - return; - } - - if (id == NULL) return; - - if (G.debug & G_DEBUG_DEPSGRAPH) { - printf("%s: id=%s flag=%d\n", __func__, id->name, flag); - } - - /* tag ID for update */ - if (flag) { - if (flag & OB_RECALC_OB) - lib_id_recalc_tag(bmain, id); - if (flag & (OB_RECALC_DATA | PSYS_RECALC)) - lib_id_recalc_data_tag(bmain, id); - } - else - lib_id_recalc_tag(bmain, id); - - /* flag is for objects and particle systems */ - if (flag) { - Object *ob; - short idtype = GS(id->name); - - if (idtype == ID_OB) { - /* only quick tag */ - ob = (Object *)id; - ob->recalc |= (flag & OB_RECALC_ALL); - } - else if (idtype == ID_PA) { - ParticleSystem *psys; - /* this is weak still, should be done delayed as well */ - for (ob = bmain->object.first; ob; ob = ob->id.next) { - for (psys = ob->particlesystem.first; psys; psys = psys->next) { - if (&psys->part->id == id) { - ob->recalc |= (flag & OB_RECALC_ALL); - psys->recalc |= (flag & PSYS_RECALC); - lib_id_recalc_tag(bmain, &ob->id); - lib_id_recalc_data_tag(bmain, &ob->id); - } - } - } - } - else { - /* disable because this is called on various ID types automatically. - * where printing warning is not useful. for now just ignore */ - /* BLI_assert(!"invalid flag for this 'idtype'"); */ - } - } - else if (GS(id->name) == ID_CF) { - for (Object *ob = bmain->object.first; ob; ob = ob->id.next) { - ModifierData *md = modifiers_findByType(ob, eModifierType_MeshSequenceCache); - - if (md) { - MeshSeqCacheModifierData *mcmd = (MeshSeqCacheModifierData *)md; - - if (mcmd->cache_file && (&mcmd->cache_file->id == id)) { - ob->recalc |= OB_RECALC_ALL; - continue; - } - } - - for (bConstraint *con = ob->constraints.first; con; con = con->next) { - if (con->type != CONSTRAINT_TYPE_TRANSFORM_CACHE) { - continue; - } - - bTransformCacheConstraint *data = con->data; - - if (data->cache_file && (&data->cache_file->id == id)) { - ob->recalc |= OB_RECALC_ALL; - break; - } - } - } - } -} - -void DAG_id_tag_update(ID *id, short flag) -{ - DAG_id_tag_update_ex(G.main, id, flag); -} - -void DAG_id_type_tag(Main *bmain, short idtype) -{ - if (idtype == ID_NT) { - /* stupid workaround so parent datablocks of nested nodetree get looped - * over when we loop over tagged datablock types */ - DAG_id_type_tag(bmain, ID_MA); - DAG_id_type_tag(bmain, ID_TE); - DAG_id_type_tag(bmain, ID_LA); - DAG_id_type_tag(bmain, ID_WO); - DAG_id_type_tag(bmain, ID_SCE); - } - - bmain->id_tag_update[BKE_idcode_to_index(idtype)] = 1; -} - -int DAG_id_type_tagged(Main *bmain, short idtype) -{ - return bmain->id_tag_update[BKE_idcode_to_index(idtype)]; -} - -#if 0 // UNUSED -/* recursively descends tree, each node only checked once */ -/* node is checked to be of type object */ -static int parent_check_node(DagNode *node, int curtime) -{ - DagAdjList *itA; - - node->lasttime = curtime; - - if (node->color == DAG_GRAY) - return DAG_GRAY; - - for (itA = node->child; itA; itA = itA->next) { - if (itA->node->type == ID_OB) { - - if (itA->node->color == DAG_GRAY) - return DAG_GRAY; - - /* descend if not done */ - if (itA->node->lasttime != curtime) { - itA->node->color = parent_check_node(itA->node, curtime); - - if (itA->node->color == DAG_GRAY) - return DAG_GRAY; - } - } - } - - return DAG_WHITE; -} -#endif - -/* ******************* DAG FOR ARMATURE POSE ***************** */ - -/* we assume its an armature with pose */ -void DAG_pose_sort(Object *ob) -{ - bPose *pose = ob->pose; - bPoseChannel *pchan; - bConstraint *con; - DagNode *node; - DagNode *node2, *node3; - DagNode *rootnode; - DagForest *dag; - DagNodeQueue *nqueue; - DagAdjList *itA; - ListBase tempbase; - int skip = 0; - - dag = dag_init(); - dag->ugly_hack_sorry = false; /* no ID structs */ - - rootnode = dag_add_node(dag, NULL); /* node->ob becomes NULL */ - - /* we add the hierarchy and the constraints */ - for (pchan = pose->chanbase.first; pchan; pchan = pchan->next) { - int addtoroot = 1; - - node = dag_get_node(dag, pchan); - - if (pchan->parent) { - node2 = dag_get_node(dag, pchan->parent); - dag_add_relation(dag, node2, node, 0, "Parent Relation"); - addtoroot = 0; - } - for (con = pchan->constraints.first; con; con = con->next) { - const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con); - ListBase targets = {NULL, NULL}; - bConstraintTarget *ct; - - if (cti && cti->get_constraint_targets) { - cti->get_constraint_targets(con, &targets); - - for (ct = targets.first; ct; ct = ct->next) { - if (ct->tar == ob && ct->subtarget[0]) { - bPoseChannel *target = BKE_pose_channel_find_name(ob->pose, ct->subtarget); - if (target) { - node2 = dag_get_node(dag, target); - dag_add_relation(dag, node2, node, 0, "Pose Constraint"); - - if (con->type == CONSTRAINT_TYPE_KINEMATIC) { - bKinematicConstraint *data = (bKinematicConstraint *)con->data; - bPoseChannel *parchan; - int segcount = 0; - - /* exclude tip from chain? */ - if (!(data->flag & CONSTRAINT_IK_TIP)) - parchan = pchan->parent; - else - parchan = pchan; - - /* Walk to the chain's root */ - while (parchan) { - node3 = dag_get_node(dag, parchan); - dag_add_relation(dag, node2, node3, 0, "IK Constraint"); - - segcount++; - if (segcount == data->rootbone || segcount > 255) break; /* 255 is weak */ - parchan = parchan->parent; - } - } - } - } - } - - if (cti->flush_constraint_targets) - cti->flush_constraint_targets(con, &targets, 1); - } - } - if (addtoroot == 1) { - dag_add_relation(dag, rootnode, node, 0, "Root Bone Relation"); - } - } - - dag_check_cycle(dag); - - /* now we try to sort... */ - BLI_listbase_clear(&tempbase); - - nqueue = queue_create(DAGQUEUEALLOC); - - /* tag nodes unchecked */ - for (node = dag->DagNode.first; node; node = node->next) - node->color = DAG_WHITE; - - rootnode->color = DAG_GRAY; - push_stack(nqueue, rootnode); - - while (nqueue->count) { - - skip = 0; - node = get_top_node_queue(nqueue); - - itA = node->child; - while (itA != NULL) { - if (itA->node->color == DAG_WHITE) { - itA->node->color = DAG_GRAY; - push_stack(nqueue, itA->node); - skip = 1; - break; - } - itA = itA->next; - } - - if (!skip) { - if (node) { - node = pop_queue(nqueue); - if (node->ob == NULL) /* we are done */ - break; - node->color = DAG_BLACK; - - /* put node in new list */ - BLI_remlink(&pose->chanbase, node->ob); - BLI_addhead(&tempbase, node->ob); - } - } - } - - /* temporal correction for circular dependencies */ - while (pose->chanbase.first) { - pchan = pose->chanbase.first; - BLI_remlink(&pose->chanbase, pchan); - BLI_addhead(&tempbase, pchan); - - printf("cyclic %s\n", pchan->name); - } - - pose->chanbase = tempbase; - queue_delete(nqueue); - -// printf("\nordered\n"); -// for (pchan = pose->chanbase.first; pchan; pchan = pchan->next) { -// printf(" %s\n", pchan->name); -// } - - free_forest(dag); - MEM_freeN(dag); -} - -/* ************************ DAG FOR THREADED UPDATE ********************* */ - -/* Initialize run-time data in the graph needed for traversing it - * from multiple threads and start threaded tree traversal by adding - * the root node to the queue. - * - * This will mark DAG nodes as object/non-object and will calculate - * num_pending_parents of nodes (which is how many non-updated parents node - * have, which helps a lot checking whether node could be scheduled - * already or not). - */ -void DAG_threaded_update_begin(Scene *scene, - void (*func)(void *node, void *user_data), - void *user_data) -{ - DagNode *node; - - /* We reset num_pending_parents to zero first and tag node as not scheduled yet... */ - for (node = scene->theDag->DagNode.first; node; node = node->next) { - node->num_pending_parents = 0; - node->scheduled = false; - } - - /* ... and then iterate over all the nodes and - * increase num_pending_parents for node childs. - */ - for (node = scene->theDag->DagNode.first; node; node = node->next) { - DagAdjList *itA; - - for (itA = node->child; itA; itA = itA->next) { - if (itA->node != node) { - itA->node->num_pending_parents++; - } - } - } - - /* Add root nodes to the queue. */ - BLI_spin_lock(&threaded_update_lock); - for (node = scene->theDag->DagNode.first; node; node = node->next) { - if (node->num_pending_parents == 0) { - node->scheduled = true; - func(node, user_data); - } - } - BLI_spin_unlock(&threaded_update_lock); -} - -/* This function is called when handling node is done. - * - * This function updates num_pending_parents for all childs and - * schedules them if they're ready. - */ -void DAG_threaded_update_handle_node_updated(void *node_v, - void (*func)(void *node, void *user_data), - void *user_data) -{ - DagNode *node = node_v; - DagAdjList *itA; - - for (itA = node->child; itA; itA = itA->next) { - DagNode *child_node = itA->node; - if (child_node != node) { - atomic_sub_and_fetch_uint32(&child_node->num_pending_parents, 1); - - if (child_node->num_pending_parents == 0) { - bool need_schedule; - - BLI_spin_lock(&threaded_update_lock); - need_schedule = child_node->scheduled == false; - child_node->scheduled = true; - BLI_spin_unlock(&threaded_update_lock); - - if (need_schedule) { - func(child_node, user_data); - } - } - } - } -} - -/* ************************ DAG DEBUGGING ********************* */ - -void DAG_print_dependencies(Main *bmain, Scene *scene, Object *ob) -{ - /* utility for debugging dependencies */ - dag_print_dependencies = 1; - - if (ob && (ob->mode & OB_MODE_POSE)) { - printf("\nDEPENDENCY RELATIONS for %s\n\n", ob->id.name + 2); - DAG_pose_sort(ob); - } - else { - printf("\nDEPENDENCY RELATIONS for %s\n\n", scene->id.name + 2); - DAG_scene_relations_rebuild(bmain, scene); - } - - dag_print_dependencies = 0; -} - -/* ************************ DAG querying ********************* */ - -/* Will return Object ID if node represents Object, - * and will return NULL otherwise. - */ -Object *DAG_get_node_object(void *node_v) -{ - DagNode *node = node_v; - - if (node->type == ID_OB) { - return node->ob; - } - - return NULL; -} - -/* Returns node name, used for debug output only, atm. */ -const char *DAG_get_node_name(Scene *scene, void *node_v) -{ - DagNode *node = node_v; - - return dag_node_name(scene->theDag, node); -} - -short DAG_get_eval_flags_for_object(Scene *scene, void *object) -{ - DagNode *node; - - if (!DEG_depsgraph_use_legacy()) { - return DEG_get_eval_flags_for_id(scene->depsgraph, (ID *)object); - } - - if (scene->theDag == NULL) { - /* Happens when converting objects to mesh from a python script - * after modifying scene graph. - * - * Currently harmless because it's only called for temporary - * objects which are out of the DAG anyway. - */ - return 0; - } - - node = dag_find_node(scene->theDag, object); - - if (node) { - return node->eval_flags; - } - else { - /* Happens when external render engine exports temporary objects - * which are not in the DAG. - */ - - /* TODO(sergey): Doublecheck objects with Curve Deform exports all fine. */ - - /* TODO(sergey): Weak but currently we can't really access proper DAG from - * the modifiers stack. This is because in most cases modifier is to use - * the foreground scene, but to access evaluation flags we need to know - * active background scene, which we don't know. - */ - if (scene->set) { - return DAG_get_eval_flags_for_object(scene->set, object); - } - return 0; - } -} - -bool DAG_is_acyclic(Scene *scene) -{ - return scene->theDag->is_acyclic; -} - -#else - /* ********************************************************************* * Stubs to avoid linking issues and make sure legacy crap is not used * * ********************************************************************* @@ -3686,5 +338,3 @@ void DAG_print_dependencies(Main *UNUSED(bmain), { DEG_debug_graphviz(scene->depsgraph, stdout, "Depsgraph", false); } - -#endif diff --git a/source/blender/blenkernel/intern/dynamicpaint.c b/source/blender/blenkernel/intern/dynamicpaint.c index dc9f3b57f1f..39d06a13e6e 100644 --- a/source/blender/blenkernel/intern/dynamicpaint.c +++ b/source/blender/blenkernel/intern/dynamicpaint.c @@ -488,7 +488,7 @@ static void scene_setSubframe(Scene *scene, float subframe) static int surface_getBrushFlags(DynamicPaintSurface *surface, const Scene *scene) { - Base *base = NULL; + BaseLegacy *base = NULL; GroupObject *go = NULL; Object *brushObj = NULL; ModifierData *md = NULL; @@ -5780,7 +5780,7 @@ static int dynamicPaint_doStep(Scene *scene, Object *ob, DynamicPaintSurface *su * Loop through surface's target paint objects and do painting */ { - Base *base = NULL; + BaseLegacy *base = NULL; GroupObject *go = NULL; Object *brushObj = NULL; ModifierData *md = NULL; @@ -5846,8 +5846,6 @@ static int dynamicPaint_doStep(Scene *scene, Object *ob, DynamicPaintSurface *su dynamicPaint_updateBrushMaterials(brushObj, brush->mat, scene, &bMats); /* Apply brush on the surface depending on it's collision type */ - /* Particle brush: */ - if (brush->collision == MOD_DPAINT_COL_PSYS) { if (brush->psys && brush->psys->part && ELEM(brush->psys->part->type, PART_EMITTER, PART_FLUID) && psys_check_enabled(brushObj, brush->psys, G.is_rendering)) @@ -5857,9 +5855,8 @@ static int dynamicPaint_doStep(Scene *scene, Object *ob, DynamicPaintSurface *su BKE_scene_frame_get(scene), ADT_RECALC_ANIM); dynamicPaint_paintParticles(surface, brush->psys, brush, timescale); } - } /* Object center distance: */ - else if (brush->collision == MOD_DPAINT_COL_POINT && brushObj != ob) { + if (brush->collision == MOD_DPAINT_COL_POINT && brushObj != ob) { dynamicPaint_paintSinglePoint(surface, brushObj->loc, brush, brushObj, &bMats, scene, timescale); } /* Mesh volume/proximity: */ diff --git a/source/blender/blenkernel/intern/effect.c b/source/blender/blenkernel/intern/effect.c index fe8f5ebdca6..668d4d6c9e2 100644 --- a/source/blender/blenkernel/intern/effect.c +++ b/source/blender/blenkernel/intern/effect.c @@ -209,7 +209,7 @@ static void add_particles_to_effectors(ListBase **effectors, Scene *scene, Effec ListBase *pdInitEffectors(Scene *scene, Object *ob_src, ParticleSystem *psys_src, EffectorWeights *weights, bool for_simulation) { - Base *base; + BaseLegacy *base; unsigned int layer= ob_src->lay; ListBase *effectors = NULL; diff --git a/source/blender/blenkernel/intern/group.c b/source/blender/blenkernel/intern/group.c index 9b011dbb003..9c81a8b49be 100644 --- a/source/blender/blenkernel/intern/group.c +++ b/source/blender/blenkernel/intern/group.c @@ -130,18 +130,11 @@ static bool group_object_add_internal(Group *group, Object *ob) return true; } -bool BKE_group_object_add(Group *group, Object *object, Scene *scene, Base *base) +bool BKE_group_object_add(Group *group, Object *object) { if (group_object_add_internal(group, object)) { if ((object->flag & OB_FROMGROUP) == 0) { - - if (scene && base == NULL) - base = BKE_scene_base_find(scene, object); - object->flag |= OB_FROMGROUP; - - if (base) - base->flag |= OB_FROMGROUP; } return true; } @@ -208,18 +201,12 @@ bool BKE_group_object_cyclic_check(Main *bmain, Object *object, Group *group) return group_object_cyclic_check_internal(object, group); } -bool BKE_group_object_unlink(Group *group, Object *object, Scene *scene, Base *base) +bool BKE_group_object_unlink(Group *group, Object *object) { if (group_object_unlink_internal(group, object)) { /* object can be NULL */ if (object && BKE_group_object_find(NULL, object) == NULL) { - if (scene && base == NULL) - base = BKE_scene_base_find(scene, object); - object->flag &= ~OB_FROMGROUP; - - if (base) - base->flag &= ~OB_FROMGROUP; } return true; } diff --git a/source/blender/blenkernel/intern/icons.c b/source/blender/blenkernel/intern/icons.c index 7669c4ba112..70cf0d5a445 100644 --- a/source/blender/blenkernel/intern/icons.c +++ b/source/blender/blenkernel/intern/icons.c @@ -42,6 +42,7 @@ #include "DNA_material_types.h" #include "DNA_object_types.h" #include "DNA_scene_types.h" +#include "DNA_screen_types.h" #include "DNA_texture_types.h" #include "DNA_world_types.h" #include "DNA_brush_types.h" @@ -252,6 +253,7 @@ PreviewImage **BKE_previewimg_id_get_p(ID *id) ID_PRV_CASE(ID_OB, Object); ID_PRV_CASE(ID_GR, Group); ID_PRV_CASE(ID_SCE, Scene); + ID_PRV_CASE(ID_SCR, bScreen); #undef ID_PRV_CASE } diff --git a/source/blender/blenkernel/intern/layer.c b/source/blender/blenkernel/intern/layer.c new file mode 100644 index 00000000000..d5e3e211642 --- /dev/null +++ b/source/blender/blenkernel/intern/layer.c @@ -0,0 +1,1512 @@ +/* + * ***** 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. + * + * Contributor(s): Dalai Felinto + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/blenkernel/intern/layer.c + * \ingroup bke + */ + +#include <string.h> + +#include "BLI_listbase.h" +#include "BLI_string.h" +#include "BLI_string_utf8.h" +#include "BLI_string_utils.h" +#include "BLT_translation.h" + +#include "BKE_collection.h" +#include "BKE_layer.h" +#include "BKE_main.h" +#include "BKE_node.h" + +#include "DNA_ID.h" +#include "DNA_layer_types.h" +#include "DNA_object_types.h" +#include "DNA_node_types.h" +#include "DNA_scene_types.h" + +#include "DRW_engine.h" + +#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 CollectionEngineSettings *collection_engine_settings_create(struct CollectionEngineSettingsCB_Type *ces_type); +static void layer_collection_engine_settings_free(LayerCollection *lc); +static void layer_collection_create_engine_settings(LayerCollection *lc); +static void layer_collection_create_mode_settings(LayerCollection *lc); +static void scene_layer_engine_settings_update(SceneLayer *sl, Object *ob); +static void object_bases_Iterator_next(Iterator *iter, const int flag); + +/* RenderLayer */ + +/** + * Returns the SceneLayer to be used for rendering + * Most of the time BKE_scene_layer_context_active should be used instead + */ +SceneLayer *BKE_scene_layer_render_active(const Scene *scene) +{ + SceneLayer *sl = BLI_findlink(&scene->render_layers, scene->active_layer); + BLI_assert(sl); + return sl; +} + +/** + * Returns the SceneLayer to be used for drawing, outliner, and + * other context related areas. + */ +SceneLayer *BKE_scene_layer_context_active(Scene *scene) +{ + /* waiting for workspace to get the layer from context*/ + TODO_LAYER_CONTEXT; + return BKE_scene_layer_render_active(scene); +} + +/** + * Add a new renderlayer + * by default, a renderlayer has the master collection + */ +SceneLayer *BKE_scene_layer_add(Scene *scene, const char *name) +{ + if (!name) { + name = DATA_("Render Layer"); + } + + SceneLayer *sl = MEM_callocN(sizeof(SceneLayer), "Scene Layer"); + sl->flag |= SCENE_LAYER_RENDER; + + BLI_addtail(&scene->render_layers, sl); + + /* unique name */ + BLI_strncpy_utf8(sl->name, name, sizeof(sl->name)); + BLI_uniquename(&scene->render_layers, sl, DATA_("SceneLayer"), '.', offsetof(SceneLayer, name), sizeof(sl->name)); + + SceneCollection *sc = BKE_collection_master(scene); + layer_collection_add(sl, &sl->layer_collections, sc); + + return sl; +} + +bool BKE_scene_layer_remove(Main *bmain, Scene *scene, SceneLayer *sl) +{ + const int act = BLI_findindex(&scene->render_layers, sl); + + if (act == -1) { + return false; + } + else if ( (scene->render_layers.first == scene->render_layers.last) && + (scene->render_layers.first == sl)) + { + /* ensure 1 layer is kept */ + return false; + } + + BLI_remlink(&scene->render_layers, sl); + + BKE_scene_layer_free(sl); + MEM_freeN(sl); + + scene->active_layer = 0; + /* TODO WORKSPACE: set active_layer to 0 */ + + for (Scene *sce = bmain->scene.first; sce; sce = sce->id.next) { + if (sce->nodetree) { + BKE_nodetree_remove_layer_n(sce->nodetree, scene, act); + } + } + + return true; +} + +/** + * Free (or release) any data used by this SceneLayer (does not free the SceneLayer itself). + */ +void BKE_scene_layer_free(SceneLayer *sl) +{ + sl->basact = NULL; + BLI_freelistN(&sl->object_bases); + + for (LayerCollection *lc = sl->layer_collections.first; lc; lc = lc->next) { + layer_collection_free(NULL, lc); + } + BLI_freelistN(&sl->layer_collections); +} + +/** + * Set the render engine of a renderlayer + */ +void BKE_scene_layer_engine_set(SceneLayer *sl, const char *engine) +{ + BLI_strncpy_utf8(sl->engine, engine, sizeof(sl->engine)); +} + +/** + * Tag all the selected objects of a renderlayer + */ +void BKE_scene_layer_selected_objects_tag(SceneLayer *sl, const int tag) +{ + for (Base *base = sl->object_bases.first; base; base = base->next) { + if ((base->flag & BASE_SELECTED) != 0) { + base->object->flag |= tag; + } + else { + base->object->flag &= ~tag; + } + } +} + +static bool find_scene_collection_in_scene_collections(ListBase *lb, const LayerCollection *lc) +{ + for (LayerCollection *lcn = lb->first; lcn; lcn = lcn->next) { + if (lcn == lc) { + return true; + } + if (find_scene_collection_in_scene_collections(&lcn->layer_collections, lc)) { + return true; + } + } + return false; +} + +/** + * Find the SceneLayer a LayerCollection belongs to + */ +SceneLayer *BKE_scene_layer_find_from_collection(Scene *scene, LayerCollection *lc) +{ + for (SceneLayer *sl = scene->render_layers.first; sl; sl = sl->next) { + if (find_scene_collection_in_scene_collections(&sl->layer_collections, lc)) { + return sl; + } + } + return NULL; +} + +/* Base */ + +Base *BKE_scene_layer_base_find(SceneLayer *sl, Object *ob) +{ + return BLI_findptr(&sl->object_bases, ob, offsetof(Base, object)); +} + +void BKE_scene_layer_base_deselect_all(SceneLayer *sl) +{ + Base *base; + + for (base = sl->object_bases.first; base; base = base->next) { + base->flag &= ~BASE_SELECTED; + } +} + +void BKE_scene_layer_base_select(struct SceneLayer *sl, Base *selbase) +{ + sl->basact = selbase; + if ((selbase->flag & BASE_SELECTABLED) != 0) { + selbase->flag |= BASE_SELECTED; + } +} + +static void scene_layer_object_base_unref(SceneLayer *sl, Base *base) +{ + base->refcount--; + + /* It only exists in the RenderLayer */ + if (base->refcount == 0) { + if (sl->basact == base) { + sl->basact = NULL; + } + + BLI_remlink(&sl->object_bases, base); + MEM_freeN(base); + } +} + +static void layer_collection_base_flag_recalculate( + LayerCollection *lc, const bool tree_is_visible, const bool tree_is_selectable) +{ + bool is_visible = tree_is_visible && ((lc->flag & COLLECTION_VISIBLE) != 0); + /* an object can only be selected if it's visible */ + bool is_selectable = tree_is_selectable && is_visible && ((lc->flag & COLLECTION_SELECTABLE) != 0); + + for (LinkData *link = lc->object_bases.first; link; link = link->next) { + Base *base = link->data; + + if (is_visible) { + base->flag |= BASE_VISIBLED; + } + + if (is_selectable) { + base->flag |= BASE_SELECTABLED; + } + } + + for (LayerCollection *lcn = lc->layer_collections.first; lcn; lcn = lcn->next) { + layer_collection_base_flag_recalculate(lcn, is_visible, is_selectable); + } +} + +/** + * Re-evaluate the ObjectBase flags for SceneLayer + */ +void BKE_scene_layer_base_flag_recalculate(SceneLayer *sl) +{ + for (Base *base = sl->object_bases.first; base; base = base->next) { + base->flag &= ~(BASE_VISIBLED | BASE_SELECTABLED); + } + + for (LayerCollection *lc = sl->layer_collections.first; lc; lc = lc->next) { + layer_collection_base_flag_recalculate(lc, true, true); + } + + /* if base is not selectabled, clear select */ + for (Base *base = sl->object_bases.first; base; base = base->next) { + if ((base->flag & BASE_SELECTABLED) == 0) { + base->flag &= ~BASE_SELECTED; + } + } +} + +/** + * Tag Scene Layer to recalculation + * + * Temporary function, waiting for real depsgraph + */ +void BKE_scene_layer_engine_settings_recalculate(SceneLayer *sl) +{ + sl->flag |= SCENE_LAYER_ENGINE_DIRTY; + for (Base *base = sl->object_bases.first; base; base = base->next) { + base->flag |= BASE_DIRTY_ENGINE_SETTINGS; + } +} + +/** + * Tag Object in SceneLayer to recalculation + * + * Temporary function, waiting for real depsgraph + */ +void BKE_scene_layer_engine_settings_object_recalculate(SceneLayer *sl, Object *ob) +{ + Base *base = BLI_findptr(&sl->object_bases, ob, offsetof(Base, object)); + if (base) { + sl->flag |= SCENE_LAYER_ENGINE_DIRTY; + base->flag |= BASE_DIRTY_ENGINE_SETTINGS; + } +} + +/** + * Tag all Objects in LayerCollection to recalculation + * + * Temporary function, waiting for real depsgraph + */ +void BKE_scene_layer_engine_settings_collection_recalculate(SceneLayer *sl, LayerCollection *lc) +{ + sl->flag |= SCENE_LAYER_ENGINE_DIRTY; + + for (LinkData *link = lc->object_bases.first; link; link = link->next) { + Base *base = (Base *)link->data; + base->flag |= BASE_DIRTY_ENGINE_SETTINGS; + } + + for (LayerCollection *lcn = lc->layer_collections.first; lcn; lcn = lcn->next) { + BKE_scene_layer_engine_settings_collection_recalculate(sl, lcn); + } +} + +/** + * 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 */ + for (Base *base = sl->object_bases.first; base; base = base->next) { + if (((base->flag & BASE_DIRTY_ENGINE_SETTINGS) != 0) && \ + (base->flag & BASE_VISIBLED) != 0) + { + scene_layer_engine_settings_update(sl, base->object); + base->flag &= ~BASE_DIRTY_ENGINE_SETTINGS; + } + } + + sl->flag &= ~SCENE_LAYER_ENGINE_DIRTY; +} + +/** + * Return the base if existent, or create it if necessary + * Always bump the refcount + */ +static Base *object_base_add(SceneLayer *sl, Object *ob) +{ + Base *base; + base = BKE_scene_layer_base_find(sl, ob); + + if (base == NULL) { + base = MEM_callocN(sizeof(Base), "Object Base"); + + /* do not bump user count, leave it for SceneCollections */ + base->object = ob; + BLI_addtail(&sl->object_bases, base); + } + base->refcount++; + return base; +} + +/* LayerCollection */ + +/** + * When freeing the entire SceneLayer at once we don't bother with unref + * otherwise SceneLayer is passed to keep the syncing of the LayerCollection tree + */ +static void layer_collection_free(SceneLayer *sl, LayerCollection *lc) +{ + if (sl) { + for (LinkData *link = lc->object_bases.first; link; link = link->next) { + scene_layer_object_base_unref(sl, link->data); + } + } + + BLI_freelistN(&lc->object_bases); + BLI_freelistN(&lc->overrides); + layer_collection_engine_settings_free(lc); + + for (LayerCollection *nlc = lc->layer_collections.first; nlc; nlc = nlc->next) { + layer_collection_free(sl, nlc); + } + + BLI_freelistN(&lc->layer_collections); +} + +/** + * Free (or release) LayerCollection from SceneLayer + * (does not free the LayerCollection itself). + */ +void BKE_layer_collection_free(SceneLayer *sl, LayerCollection *lc) +{ + layer_collection_free(sl, lc); +} + +/* LayerCollection */ + +/** + * Recursively get the collection for a given index + */ +static LayerCollection *collection_from_index(ListBase *lb, const int number, int *i) +{ + for (LayerCollection *lc = lb->first; lc; lc = lc->next) { + if (*i == number) { + return lc; + } + + (*i)++; + + LayerCollection *lc_nested = collection_from_index(&lc->layer_collections, number, i); + if (lc_nested) { + return lc_nested; + } + } + return NULL; +} + +/** + * Get the active collection + */ +LayerCollection *BKE_layer_collection_active(SceneLayer *sl) +{ + int i = 0; + return collection_from_index(&sl->layer_collections, sl->active_collection, &i); +} + +/** + * Recursively get the count of collections + */ +static int collection_count(ListBase *lb) +{ + int i = 0; + for (LayerCollection *lc = lb->first; lc; lc = lc->next) { + i += collection_count(&lc->layer_collections) + 1; + } + return i; +} + +/** + * Get the total number of collections + * (including all the nested collections) + */ +int BKE_layer_collection_count(SceneLayer *sl) +{ + return collection_count(&sl->layer_collections); +} + +/** + * Recursively get the index for a given collection + */ +static int index_from_collection(ListBase *lb, LayerCollection *lc, int *i) +{ + for (LayerCollection *lcol = lb->first; lcol; lcol = lcol->next) { + if (lcol == lc) { + return *i; + } + + (*i)++; + + int i_nested = index_from_collection(&lcol->layer_collections, lc, i); + if (i_nested != -1) { + return i_nested; + } + } + return -1; +} + +/** + * Return -1 if not found + */ +int BKE_layer_collection_findindex(SceneLayer *sl, LayerCollection *lc) +{ + int i = 0; + return index_from_collection(&sl->layer_collections, lc, &i); +} + +/** + * Lookup the listbase that contains \a lc. + */ +static ListBase *layer_collection_listbase_find(ListBase *lb, LayerCollection *lc) +{ + for (LayerCollection *lc_iter = lb->first; lc_iter; lc_iter = lc_iter->next) { + if (lc_iter == lc) { + return lb; + } + + ListBase *lb_child_result; + if ((lb_child_result = layer_collection_listbase_find(&lc_iter->layer_collections, lc))) { + return lb_child_result; + } + } + + return NULL; +} + +/** + * Lookup the listbase that contains \a sc. + */ +static ListBase *scene_collection_listbase_find(ListBase *lb, SceneCollection *sc) +{ + for (SceneCollection *sc_iter = lb->first; sc_iter; sc_iter = sc_iter->next) { + if (sc_iter == sc) { + return lb; + } + + ListBase *lb_child_result; + if ((lb_child_result = scene_collection_listbase_find(&sc_iter->scene_collections, sc))) { + return lb_child_result; + } + } + + return NULL; +} + +/** + * Move \a lc_reinsert so that it follows \a lc_after. Both have to be stored in \a sl. + * \param lc_after: Can be NULL to reinsert \a lc_after as first collection of its own list. + */ +void BKE_layer_collection_reinsert_after( + const Scene *scene, SceneLayer *sl, LayerCollection *lc_reinsert, LayerCollection *lc_after) +{ + SceneCollection *sc_master = BKE_collection_master(scene); + SceneCollection *sc_reinsert = lc_reinsert->scene_collection; + ListBase *lc_reinsert_lb = layer_collection_listbase_find(&sl->layer_collections, lc_reinsert); + ListBase *sc_reinsert_lb = scene_collection_listbase_find(&sc_master->scene_collections, sc_reinsert); + + BLI_assert(BLI_findindex(lc_reinsert_lb, lc_reinsert) > -1); + BLI_assert(BLI_findindex(sc_reinsert_lb, sc_reinsert) > -1); + BLI_remlink(lc_reinsert_lb, lc_reinsert); + BLI_remlink(sc_reinsert_lb, sc_reinsert); + + /* insert after lc_after or */ + if (lc_after == NULL) { + BLI_addhead(lc_reinsert_lb, lc_reinsert); + BLI_addhead(sc_reinsert_lb, sc_reinsert); + } + else { + SceneCollection *sc_after = lc_after->scene_collection; + ListBase *lc_after_lb = layer_collection_listbase_find(&sl->layer_collections, lc_after); + ListBase *sc_after_lb = scene_collection_listbase_find(&sc_master->scene_collections, sc_after); + + BLI_insertlinkafter(lc_after_lb, lc_after, lc_reinsert); + BLI_insertlinkafter(sc_after_lb, sc_after, sc_reinsert); + } + + BKE_scene_layer_base_flag_recalculate(sl); + BKE_scene_layer_engine_settings_collection_recalculate(sl, lc_reinsert); +} + +/** + * Link a collection to a renderlayer + * The collection needs to be created separately + */ +LayerCollection *BKE_collection_link(SceneLayer *sl, SceneCollection *sc) +{ + LayerCollection *lc = layer_collection_add(sl, &sl->layer_collections, sc); + sl->active_collection = BKE_layer_collection_findindex(sl, lc); + return lc; +} + +/** + * Unlink a collection base from a renderlayer + * The corresponding collection is not removed from the master collection + */ +void BKE_collection_unlink(SceneLayer *sl, LayerCollection *lc) +{ + BKE_layer_collection_free(sl, lc); + BKE_scene_layer_base_flag_recalculate(sl); + BKE_scene_layer_engine_settings_collection_recalculate(sl, lc); + + BLI_remlink(&sl->layer_collections, lc); + MEM_freeN(lc); + sl->active_collection = 0; +} + +static void layer_collection_object_add(SceneLayer *sl, LayerCollection *lc, Object *ob) +{ + Base *base = object_base_add(sl, ob); + + /* only add an object once - prevent SceneCollection->objects and + * SceneCollection->filter_objects to add the same object */ + + if (BLI_findptr(&lc->object_bases, base, offsetof(LinkData, data))) { + return; + } + + BLI_addtail(&lc->object_bases, BLI_genericNodeN(base)); + + BKE_scene_layer_base_flag_recalculate(sl); + BKE_scene_layer_engine_settings_object_recalculate(sl, ob); +} + +static void layer_collection_object_remove(SceneLayer *sl, LayerCollection *lc, Object *ob) +{ + Base *base; + base = BKE_scene_layer_base_find(sl, ob); + + LinkData *link = BLI_findptr(&lc->object_bases, base, offsetof(LinkData, data)); + BLI_remlink(&lc->object_bases, link); + MEM_freeN(link); + + scene_layer_object_base_unref(sl, base); +} + +static void layer_collection_objects_populate(SceneLayer *sl, LayerCollection *lc, ListBase *objects) +{ + for (LinkData *link = objects->first; link; link = link->next) { + layer_collection_object_add(sl, lc, link->data); + } +} + +static void layer_collection_populate(SceneLayer *sl, LayerCollection *lc, SceneCollection *sc) +{ + layer_collection_objects_populate(sl, lc, &sc->objects); + layer_collection_objects_populate(sl, lc, &sc->filter_objects); + + for (SceneCollection *nsc = sc->scene_collections.first; nsc; nsc = nsc->next) { + layer_collection_add(sl, &lc->layer_collections, nsc); + } +} + +static LayerCollection *layer_collection_add(SceneLayer *sl, ListBase *lb, SceneCollection *sc) +{ + LayerCollection *lc = MEM_callocN(sizeof(LayerCollection), "Collection Base"); + BLI_addtail(lb, lc); + + lc->scene_collection = sc; + lc->flag = COLLECTION_VISIBLE + COLLECTION_SELECTABLE + COLLECTION_FOLDED; + + layer_collection_create_engine_settings(lc); + layer_collection_create_mode_settings(lc); + layer_collection_populate(sl, lc, sc); + return lc; +} + + +/* ---------------------------------------------------------------------- */ + +/** + * See if render layer has the scene collection linked directly, or indirectly (nested) + */ +bool BKE_scene_layer_has_collection(struct SceneLayer *sl, struct SceneCollection *sc) +{ + for (LayerCollection *lc = sl->layer_collections.first; lc; lc = lc->next) { + if (find_layer_collection_by_scene_collection(lc, sc) != NULL) { + return true; + } + } + return false; +} + +/** + * See if the object is in any of the scene layers of the scene + */ +bool BKE_scene_has_object(Scene *scene, Object *ob) +{ + for (SceneLayer *sl = scene->render_layers.first; sl; sl = sl->next) { + Base *base = BKE_scene_layer_base_find(sl, ob); + if (base) { + return true; + } + } + return false; +} + + +/* ---------------------------------------------------------------------- */ +/* Syncing */ + +static LayerCollection *find_layer_collection_by_scene_collection(LayerCollection *lc, const SceneCollection *sc) +{ + if (lc->scene_collection == sc) { + return lc; + } + + for (LayerCollection *nlc = lc->layer_collections.first; nlc; nlc = nlc->next) { + LayerCollection *found = find_layer_collection_by_scene_collection(nlc, sc); + if (found) { + return found; + } + } + return NULL; +} + +/** + * Add a new LayerCollection for all the SceneLayers that have sc_parent + */ +void BKE_layer_sync_new_scene_collection(Scene *scene, const SceneCollection *sc_parent, SceneCollection *sc) +{ + for (SceneLayer *sl = scene->render_layers.first; sl; sl = sl->next) { + for (LayerCollection *lc = sl->layer_collections.first; lc; lc = lc->next) { + LayerCollection *lc_parent = find_layer_collection_by_scene_collection(lc, sc_parent); + if (lc_parent) { + layer_collection_add(sl, &lc_parent->layer_collections, sc); + } + } + } +} + +/** + * Add a corresponding ObjectBase to all the equivalent LayerCollection + */ +void BKE_layer_sync_object_link(Scene *scene, SceneCollection *sc, Object *ob) +{ + for (SceneLayer *sl = scene->render_layers.first; sl; sl = sl->next) { + for (LayerCollection *lc = sl->layer_collections.first; lc; lc = lc->next) { + LayerCollection *found = find_layer_collection_by_scene_collection(lc, sc); + if (found) { + layer_collection_object_add(sl, found, ob); + } + } + } +} + +/** + * Remove the equivalent object base to all layers that have this collection + * also remove all reference to ob in the filter_objects + */ +void BKE_layer_sync_object_unlink(Scene *scene, SceneCollection *sc, Object *ob) +{ + for (SceneLayer *sl = scene->render_layers.first; sl; sl = sl->next) { + for (LayerCollection *lc = sl->layer_collections.first; lc; lc = lc->next) { + LayerCollection *found = find_layer_collection_by_scene_collection(lc, sc); + if (found) { + layer_collection_object_remove(sl, found, ob); + } + } + BKE_scene_layer_base_flag_recalculate(sl); + BKE_scene_layer_engine_settings_object_recalculate(sl, ob); + } +} + +/* ---------------------------------------------------------------------- */ +/* Override */ + +/** + * Add a new datablock override + */ +void BKE_collection_override_datablock_add(LayerCollection *UNUSED(lc), const char *UNUSED(data_path), ID *UNUSED(id)) +{ + TODO_LAYER_OVERRIDE; +} + +/* ---------------------------------------------------------------------- */ +/* Engine Settings */ + +ListBase R_engines_settings_callbacks = {NULL, NULL}; + +typedef struct CollectionEngineSettingsCB_Type { + struct CollectionEngineSettingsCB_Type *next, *prev; + + char name[MAX_NAME]; /* engine name */ + + CollectionEngineSettingsCB callback; + +} CollectionEngineSettingsCB_Type; + +static void create_engine_settings_layer_collection(LayerCollection *lc, CollectionEngineSettingsCB_Type *ces_type) +{ + if (BKE_layer_collection_engine_get(lc, COLLECTION_MODE_NONE, ces_type->name)) { + return; + } + + CollectionEngineSettings *ces = collection_engine_settings_create(ces_type); + BLI_addtail(&lc->engine_settings, ces); + + 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 CollectionEngineSettings *collection_engine_settings_create(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)); + + /* call callback */ + ces_type->callback(NULL, ces); + + return ces; +} + +/** + * Initialize a CollectionEngineSettings + * + * Usually we would pass LayerCollection->engine_settings + * But depsgraph uses this for Object->collection_settings + */ +CollectionEngineSettings *BKE_layer_collection_engine_settings_create(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); + + CollectionEngineSettings *ces = collection_engine_settings_create(ces_type); + return ces; +} + +/** + * Free the CollectionEngineSettings + */ +void BKE_layer_collection_engine_settings_free(CollectionEngineSettings *ces) +{ + BLI_freelistN(&ces->properties); +} + +static void layer_collection_engine_settings_free(LayerCollection *lc) +{ + for (CollectionEngineSettings *ces = lc->engine_settings.first; ces; ces = ces->next) { + BKE_layer_collection_engine_settings_free(ces); + } + BLI_freelistN(&lc->engine_settings); + + for (CollectionEngineSettings *ces = lc->mode_settings.first; ces; ces = ces->next) { + BKE_layer_collection_engine_settings_free(ces); + } + BLI_freelistN(&lc->mode_settings); +} + +/** + * 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); + } +} + +static void layer_collection_create_mode_settings_object(ListBase *lb) +{ + CollectionEngineSettings *ces; + + ces = MEM_callocN(sizeof(CollectionEngineSettings), "Object Mode Settings"); + BLI_strncpy_utf8(ces->name, "Object Mode", sizeof(ces->name)); + ces->type = COLLECTION_MODE_OBJECT; + + /* properties */ + OBJECT_collection_settings_create(ces); + + BLI_addtail(lb, ces); +} + +static void layer_collection_create_mode_settings_edit(ListBase *lb) +{ + CollectionEngineSettings *ces; + + ces = MEM_callocN(sizeof(CollectionEngineSettings), "Edit Mode Settings"); + BLI_strncpy_utf8(ces->name, "Edit Mode", sizeof(ces->name)); + ces->type = COLLECTION_MODE_EDIT; + + /* properties */ + EDIT_MESH_collection_settings_create(ces); + + BLI_addtail(lb, ces); +} + +static void collection_create_mode_settings(ListBase *lb) +{ + layer_collection_create_mode_settings_object(lb); + layer_collection_create_mode_settings_edit(lb); +} + +static void layer_collection_create_mode_settings(LayerCollection *lc) +{ + collection_create_mode_settings(&lc->mode_settings); +} + +/** + * Return collection enginne settings for either Object s of LayerCollection s + */ +static CollectionEngineSettings *collection_engine_get( + ListBase *lb_render, ListBase *lb_mode, const int type, const char *engine_name) +{ + if (type == COLLECTION_MODE_NONE) { + return BLI_findstring(lb_render, engine_name, offsetof(CollectionEngineSettings, name)); + } + else { + CollectionEngineSettings *ces; + for (ces = lb_mode->first; ces; ces = ces->next) { + if (ces->type == type) { + return ces; + } + } + } + BLI_assert(false); + return NULL; +} + +/** + * Return collection engine settings from Object for specified engine of mode + */ +CollectionEngineSettings *BKE_object_collection_engine_get(Object *ob, const int type, const char *engine_name) +{ + return collection_engine_get(&ob->collection_settings, &ob->collection_settings, type, engine_name); +} +/** + * Return layer collection engine settings for specified engine + */ +CollectionEngineSettings *BKE_layer_collection_engine_get(LayerCollection *lc, const int type, const char *engine_name) +{ + return collection_engine_get(&lc->engine_settings, &lc->mode_settings, type, engine_name); +} + +/* ---------------------------------------------------------------------- */ +/* 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); +} + +void BKE_collection_engine_property_add_bool(CollectionEngineSettings *ces, const char *name, bool value) +{ + CollectionEnginePropertyBool *prop; + prop = MEM_callocN(sizeof(CollectionEnginePropertyBool), "collection engine settings bool"); + prop->data.type = COLLECTION_PROP_TYPE_BOOL; + 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; +} + +bool BKE_collection_engine_property_value_get_bool(CollectionEngineSettings *ces, const char *name) +{ + CollectionEnginePropertyBool *prop; + prop = (CollectionEnginePropertyBool *)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; +} + +void BKE_collection_engine_property_value_set_bool(CollectionEngineSettings *ces, const char *name, bool value) +{ + CollectionEnginePropertyBool *prop; + prop = (CollectionEnginePropertyBool *)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; + } +} + +/* Engine Settings recalculate */ + +static void collection_engine_settings_init(ListBase *lb) +{ + CollectionEngineSettingsCB_Type *ces_type; + for (ces_type = R_engines_settings_callbacks.first; ces_type; ces_type = ces_type->next) { + CollectionEngineSettings *ces = collection_engine_settings_create(ces_type); + BLI_strncpy_utf8(ces->name, ces_type->name, sizeof(ces->name)); + BLI_addtail(lb, ces); + + /* call callback */ + ces_type->callback(NULL, ces); + } + + /* edit modes */ + collection_create_mode_settings(lb); +} + +static void collection_engine_settings_copy(ListBase *lb_dst, ListBase *lb_src) +{ + for (CollectionEngineSettings *ces_src = lb_src->first; ces_src; ces_src = ces_src->next) { + CollectionEngineSettings *ces_dst = MEM_callocN(sizeof(*ces_dst), "CollectionEngineSettings copy"); + + BLI_strncpy_utf8(ces_dst->name, ces_src->name, sizeof(ces_dst->name)); + ces_dst->type = ces_src->type; + BLI_addtail(lb_dst, ces_dst); + + for (CollectionEngineProperty *prop = ces_src->properties.first; prop; prop = prop->next) { + CollectionEngineProperty *prop_new = MEM_dupallocN(prop); + BLI_addtail(&ces_dst->properties, prop_new); + } + } +} + +/** + * Set a value from a CollectionProperty to another + */ +static void collection_engine_property_set (CollectionEngineProperty *prop_dst, CollectionEngineProperty *prop_src) +{ + if ((prop_src->flag & COLLECTION_PROP_USE) != 0) { + /* mark the property as used, so the engine knows if the value was ever set*/ + prop_dst->flag |= COLLECTION_PROP_USE; + switch (prop_src->type) { + case COLLECTION_PROP_TYPE_FLOAT: + ((CollectionEnginePropertyFloat *)prop_dst)->value = ((CollectionEnginePropertyFloat *)prop_src)->value; + break; + case COLLECTION_PROP_TYPE_INT: + ((CollectionEnginePropertyInt *)prop_dst)->value = ((CollectionEnginePropertyInt *)prop_src)->value; + break; + case COLLECTION_PROP_TYPE_BOOL: + ((CollectionEnginePropertyBool *)prop_dst)->value = ((CollectionEnginePropertyBool *)prop_src)->value; + break; + default: + BLI_assert(false); + break; + } + } +} + +static void collection_engine_settings_merge(ListBase *lb_dst, ListBase *lb_src) +{ + for (CollectionEngineSettings *ces_src = lb_src->first; ces_src; ces_src = ces_src->next) { + CollectionEngineSettings *ces_dst = collection_engine_get(lb_dst, lb_dst, ces_src->type, ces_src->name); + BLI_assert(ces_dst); + + CollectionEngineProperty *prop_dst, *prop_src; + for (prop_dst = ces_dst->properties.first; prop_dst; prop_dst = prop_dst->next) { + prop_src = BLI_findstring(&ces_src->properties, prop_dst->name, offsetof(CollectionEngineProperty, name)); + BLI_assert(prop_src); + collection_engine_property_set(prop_dst, prop_src); + } + } +} + +static void layer_collection_engine_settings_update( + LayerCollection *lc, ListBase *lb_parent, + Base *base, ListBase *lb_object) +{ + if ((lc->flag & COLLECTION_VISIBLE) == 0) { + return; + } + + ListBase lb_collection = {NULL}; + collection_engine_settings_copy(&lb_collection, lb_parent); + + collection_engine_settings_merge(&lb_collection, &lc->engine_settings); + collection_engine_settings_merge(&lb_collection, &lc->mode_settings); + + if (BLI_findptr(&lc->object_bases, base, offsetof(LinkData, data)) != NULL) { + collection_engine_settings_merge(lb_object, &lb_collection); + } + + /* do it recursively */ + for (LayerCollection *lcn = lc->layer_collections.first; lcn; lcn = lcn->next) { + layer_collection_engine_settings_update(lcn, &lb_collection, base, lb_object); + } + + BKE_layer_collection_engine_settings_list_free(&lb_collection); +} + +/** + * Empty all the CollectionEngineSettings in the list + */ +void BKE_layer_collection_engine_settings_list_free(struct ListBase *lb) +{ + for (CollectionEngineSettings *ces = lb->first; ces; ces = ces->next) { + BKE_layer_collection_engine_settings_free(ces); + } + BLI_freelistN(lb); +} + +/** + * Update the collection settings pointer allocated in the object + * This is to be flushed from the Depsgraph + */ +static void scene_layer_engine_settings_update(SceneLayer *sl, Object *ob) +{ + Base *base = BKE_scene_layer_base_find(sl, ob); + ListBase ces_layer = {NULL}; + + collection_engine_settings_init(&ces_layer); + + /* start fresh */ + BKE_layer_collection_engine_settings_list_free(&ob->collection_settings); + collection_engine_settings_init(&ob->collection_settings); + + for (LayerCollection *lc = sl->layer_collections.first; lc; lc = lc->next) { + layer_collection_engine_settings_update(lc, &ces_layer, base, &ob->collection_settings); + } + + BKE_layer_collection_engine_settings_list_free(&ces_layer); +} + +/* ---------------------------------------------------------------------- */ +/* Iterators */ + +static void object_bases_Iterator_begin(Iterator *iter, void *data_in, const int flag) +{ + SceneLayer *sl = data_in; + Base *base = sl->object_bases.first; + + /* when there are no objects */ + if (base == NULL) { + iter->valid = false; + return; + } + + iter->valid = true; + iter->data = base; + + if ((base->flag & flag) == 0) { + object_bases_Iterator_next(iter, flag); + } + else { + iter->current = base; + } +} + +static void object_bases_Iterator_next(Iterator *iter, const int flag) +{ + Base *base = ((Base *)iter->data)->next; + + while (base) { + if ((base->flag & flag) != 0) { + iter->current = base; + iter->data = base; + return; + } + base = base->next; + } + + iter->current = NULL; + iter->valid = false; +} + +static void objects_Iterator_begin(Iterator *iter, void *data_in, const int flag) +{ + object_bases_Iterator_begin(iter, data_in, flag); + + if (iter->valid) { + iter->current = ((Base *)iter->current)->object; + } +} + +static void objects_Iterator_next(Iterator *iter, const int flag) +{ + object_bases_Iterator_next(iter, flag); + + if (iter->valid) { + iter->current = ((Base *)iter->current)->object; + } +} + +void BKE_selected_objects_Iterator_begin(Iterator *iter, void *data_in) +{ + objects_Iterator_begin(iter, data_in, BASE_SELECTED); +} + +void BKE_selected_objects_Iterator_next(Iterator *iter) +{ + objects_Iterator_next(iter, BASE_SELECTED); +} + +void BKE_selected_objects_Iterator_end(Iterator *UNUSED(iter)) +{ + /* do nothing */ +} + +void BKE_visible_objects_Iterator_begin(Iterator *iter, void *data_in) +{ + objects_Iterator_begin(iter, data_in, BASE_VISIBLED); +} + +void BKE_visible_objects_Iterator_next(Iterator *iter) +{ + objects_Iterator_next(iter, BASE_VISIBLED); +} + +void BKE_visible_objects_Iterator_end(Iterator *UNUSED(iter)) +{ + /* do nothing */ +} + +void BKE_visible_bases_Iterator_begin(Iterator *iter, void *data_in) +{ + object_bases_Iterator_begin(iter, data_in, BASE_VISIBLED); +} + +void BKE_visible_bases_Iterator_next(Iterator *iter) +{ + object_bases_Iterator_next(iter, BASE_VISIBLED); +} + +void BKE_visible_bases_Iterator_end(Iterator *UNUSED(iter)) +{ + /* do nothing */ +} + + +/* ---------------------------------------------------------------------- */ +/* Doversion routine */ + +/** + * Merge CollectionEngineSettings + * + * \param ces_ref CollectionEngineSettings to use as reference + * \param ces CollectionEngineSettings to merge into + */ +static void scene_layer_doversion_merge_setings(const CollectionEngineSettings *ces_ref, CollectionEngineSettings *ces) +{ + CollectionEngineProperty *cep = ces->properties.first, *cep_ref; + + for (cep_ref = ces_ref->properties.first; cep_ref; cep_ref = cep_ref->next) { + cep = BLI_findstring(&ces->properties, cep_ref->name, offsetof(CollectionEngineProperty, name)); + + if (cep == NULL) { + cep = MEM_dupallocN(cep_ref); + BLI_addtail(&ces->properties, cep); + } + else if (cep->type != cep_ref->type) { + CollectionEngineProperty *prev = cep->prev, *next = cep->next; + MEM_freeN(cep); + cep = MEM_dupallocN(cep_ref); + + cep->prev = prev; + cep->next = next; + } + else { + /* keep the property as it is */ + } + } +} + +/** + * Merge ListBases of LayerCollections + * + * \param lb_ref ListBase of CollectionEngineSettings to use as reference + * \param lb ListBase of CollectionEngineSettings + */ +static void scene_layer_doversion_merge_layer_collection(const ListBase *lb_ref, ListBase *lb) +{ + CollectionEngineSettings *ces = lb->first, *ces_ref; + + for (ces_ref = lb_ref->first; ces_ref; ces_ref = ces_ref->next) { + ces = BLI_findstring(lb, ces_ref->name, offsetof(CollectionEngineSettings, name)); + + if (ces == NULL) { + ces = MEM_dupallocN(ces_ref); + BLI_duplicatelist(&ces->properties, &ces_ref->properties); + BLI_addtail(lb, ces); + } + else { + scene_layer_doversion_merge_setings(ces_ref, ces); + } + } +} + +/** + * Create or remove CollectionEngineSettings and CollectionEngineProperty + * based on reference LayerCollection + * + * \param lc_ref reference LayerCollection to merge missing settings from + * \param lb ListBase of LayerCollection + */ +static void scene_layer_doversion_update_collections(const LayerCollection *lc_ref, ListBase *lb) +{ + for (LayerCollection *lc = lb->first; lc; lc = lc->next) { + + scene_layer_doversion_merge_layer_collection(&lc_ref->engine_settings, &lc->engine_settings); + scene_layer_doversion_merge_layer_collection(&lc_ref->mode_settings, &lc->mode_settings); + + /* continue recursively */ + scene_layer_doversion_update_collections(lc_ref, &lc->layer_collections); + } +} + +/** + * Updates all the CollectionEngineSettings of all + * LayerCollection elements in Scene + * + * \param lc_ref reference LayerCollection to merge missing settings from + */ +static void scene_layer_doversion_update(const LayerCollection *lc_ref, Scene *scene) +{ + for (SceneLayer *sl = scene->render_layers.first; sl; sl = sl->next) { + scene_layer_doversion_update_collections(lc_ref, &sl->layer_collections); + } +} + +/** + * Return true at the first indicative that the listbases don't match + * + * It's fine if the individual properties values are different, as long + * as we have the same properties across them + * + * \param lb_ces ListBase of CollectionEngineSettings + * \param lb_ces_ref ListBase of CollectionEngineSettings + */ +static bool scene_layer_doversion_is_outdated_engines(ListBase *lb_ces, ListBase *lb_ces_ref) +{ + if (BLI_listbase_count(lb_ces) != BLI_listbase_count(lb_ces_ref)) { + return true; + } + + CollectionEngineSettings *ces, *ces_ref; + for (ces = lb_ces->first, ces_ref = lb_ces_ref->first; ces; ces = ces->next, ces_ref = ces_ref->next) { + if (BLI_listbase_count(&ces->properties) != BLI_listbase_count(&ces_ref->properties)) { + return true; + } + + CollectionEngineProperty *cep, *cep_ref; + for (cep = ces->properties.first, cep_ref = ces_ref->properties.first; + cep != NULL; + cep = cep->next, cep_ref = cep_ref->next) + { + if (cep->type != cep_ref->type) { + return true; + } + + if (STREQ(cep->name, cep_ref->name) == false) { + return true; + } + } + } + + return false; +} + +/** + * Get the first available LayerCollection + */ +static LayerCollection *scene_layer_doversion_collection_get(Main *bmain) +{ + for (Scene *scene = bmain->scene.first; scene; scene = scene->id.next) { + for (SceneLayer *sl = scene->render_layers.first; sl; sl = sl->next) { + for (LayerCollection *lc = sl->layer_collections.first; lc; lc = lc->next) { + return lc; + } + } + } + return NULL; +} + +/** + * See if a new LayerCollection have the same CollectionEngineSettings + * and properties of the saved LayerCollection + */ +static bool scene_layer_doversion_is_outdated(Main *bmain) +{ + LayerCollection *lc, lc_ref = {NULL}; + bool is_outdated = false; + + lc = scene_layer_doversion_collection_get(bmain); + + if (lc == NULL) { + return false; + } + + layer_collection_create_engine_settings(&lc_ref); + layer_collection_create_mode_settings(&lc_ref); + + if (scene_layer_doversion_is_outdated_engines(&lc->engine_settings, &lc_ref.engine_settings)) { + is_outdated = true; + } + + if (scene_layer_doversion_is_outdated_engines(&lc->mode_settings, &lc_ref.mode_settings)) { + is_outdated = true; + } + + layer_collection_engine_settings_free(&lc_ref); + return is_outdated; +} + +/** + * Handle doversion of files during the viewport development + * + * This is intended to prevent subversion bumping every time a new property + * is added to an engine, but it may be relevant in the future as a generic doversion + */ +void BKE_scene_layer_doversion_update(Main *bmain) +{ + /* if file not outdated, don't bother with the slow merging */ + if (scene_layer_doversion_is_outdated(bmain) == false) { + return; + } + + /* create a reference LayerCollection to merge missing settings from */ + LayerCollection lc_ref = {NULL}; + layer_collection_create_engine_settings(&lc_ref); + layer_collection_create_mode_settings(&lc_ref); + + /* bring all the missing properties for the LayerCollections */ + for (Scene *scene = bmain->scene.first; scene; scene = scene->id.next) { + scene_layer_doversion_update(&lc_ref, scene); + } + + layer_collection_engine_settings_free(&lc_ref); +} diff --git a/source/blender/blenkernel/intern/library.c b/source/blender/blenkernel/intern/library.c index 6b4b492b212..2398c6724ed 100644 --- a/source/blender/blenkernel/intern/library.c +++ b/source/blender/blenkernel/intern/library.c @@ -1214,41 +1214,41 @@ void BKE_main_free(Main *mainvar) /* errors freeing ID's can be hard to track down, * enable this so valgrind will give the line number in its error log */ switch (a) { - case 0: BKE_libblock_free_ex(mainvar, id, false, false); break; - case 1: BKE_libblock_free_ex(mainvar, id, false, false); break; - case 2: BKE_libblock_free_ex(mainvar, id, false, false); break; - case 3: BKE_libblock_free_ex(mainvar, id, false, false); break; - case 4: BKE_libblock_free_ex(mainvar, id, false, false); break; - case 5: BKE_libblock_free_ex(mainvar, id, false, false); break; - case 6: BKE_libblock_free_ex(mainvar, id, false, false); break; - case 7: BKE_libblock_free_ex(mainvar, id, false, false); break; - case 8: BKE_libblock_free_ex(mainvar, id, false, false); break; - case 9: BKE_libblock_free_ex(mainvar, id, false, false); break; - case 10: BKE_libblock_free_ex(mainvar, id, false, false); break; - case 11: BKE_libblock_free_ex(mainvar, id, false, false); break; - case 12: BKE_libblock_free_ex(mainvar, id, false, false); break; - case 13: BKE_libblock_free_ex(mainvar, id, false, false); break; - case 14: BKE_libblock_free_ex(mainvar, id, false, false); break; - case 15: BKE_libblock_free_ex(mainvar, id, false, false); break; - case 16: BKE_libblock_free_ex(mainvar, id, false, false); break; - case 17: BKE_libblock_free_ex(mainvar, id, false, false); break; - case 18: BKE_libblock_free_ex(mainvar, id, false, false); break; - case 19: BKE_libblock_free_ex(mainvar, id, false, false); break; - case 20: BKE_libblock_free_ex(mainvar, id, false, false); break; - case 21: BKE_libblock_free_ex(mainvar, id, false, false); break; - case 22: BKE_libblock_free_ex(mainvar, id, false, false); break; - case 23: BKE_libblock_free_ex(mainvar, id, false, false); break; - case 24: BKE_libblock_free_ex(mainvar, id, false, false); break; - case 25: BKE_libblock_free_ex(mainvar, id, false, false); break; - case 26: BKE_libblock_free_ex(mainvar, id, false, false); break; - case 27: BKE_libblock_free_ex(mainvar, id, false, false); break; - case 28: BKE_libblock_free_ex(mainvar, id, false, false); break; - case 29: BKE_libblock_free_ex(mainvar, id, false, false); break; - case 30: BKE_libblock_free_ex(mainvar, id, false, false); break; - case 31: BKE_libblock_free_ex(mainvar, id, false, false); break; - case 32: BKE_libblock_free_ex(mainvar, id, false, false); break; - case 33: BKE_libblock_free_ex(mainvar, id, false, false); break; - case 34: BKE_libblock_free_ex(mainvar, id, false, false); break; + case 0: BKE_libblock_free_ex(mainvar, id, false); break; + case 1: BKE_libblock_free_ex(mainvar, id, false); break; + case 2: BKE_libblock_free_ex(mainvar, id, false); break; + case 3: BKE_libblock_free_ex(mainvar, id, false); break; + case 4: BKE_libblock_free_ex(mainvar, id, false); break; + case 5: BKE_libblock_free_ex(mainvar, id, false); break; + case 6: BKE_libblock_free_ex(mainvar, id, false); break; + case 7: BKE_libblock_free_ex(mainvar, id, false); break; + case 8: BKE_libblock_free_ex(mainvar, id, false); break; + case 9: BKE_libblock_free_ex(mainvar, id, false); break; + case 10: BKE_libblock_free_ex(mainvar, id, false); break; + case 11: BKE_libblock_free_ex(mainvar, id, false); break; + case 12: BKE_libblock_free_ex(mainvar, id, false); break; + case 13: BKE_libblock_free_ex(mainvar, id, false); break; + case 14: BKE_libblock_free_ex(mainvar, id, false); break; + case 15: BKE_libblock_free_ex(mainvar, id, false); break; + case 16: BKE_libblock_free_ex(mainvar, id, false); break; + case 17: BKE_libblock_free_ex(mainvar, id, false); break; + case 18: BKE_libblock_free_ex(mainvar, id, false); break; + case 19: BKE_libblock_free_ex(mainvar, id, false); break; + case 20: BKE_libblock_free_ex(mainvar, id, false); break; + case 21: BKE_libblock_free_ex(mainvar, id, false); break; + case 22: BKE_libblock_free_ex(mainvar, id, false); break; + case 23: BKE_libblock_free_ex(mainvar, id, false); break; + case 24: BKE_libblock_free_ex(mainvar, id, false); break; + case 25: BKE_libblock_free_ex(mainvar, id, false); break; + case 26: BKE_libblock_free_ex(mainvar, id, false); break; + case 27: BKE_libblock_free_ex(mainvar, id, false); break; + case 28: BKE_libblock_free_ex(mainvar, id, false); break; + case 29: BKE_libblock_free_ex(mainvar, id, false); break; + case 30: BKE_libblock_free_ex(mainvar, id, false); break; + case 31: BKE_libblock_free_ex(mainvar, id, false); break; + case 32: BKE_libblock_free_ex(mainvar, id, false); break; + case 33: BKE_libblock_free_ex(mainvar, id, false); break; + case 34: BKE_libblock_free_ex(mainvar, id, false); break; default: BLI_assert(0); break; diff --git a/source/blender/blenkernel/intern/library_query.c b/source/blender/blenkernel/intern/library_query.c index 9685f1f5af6..c9853f791ce 100644 --- a/source/blender/blenkernel/intern/library_query.c +++ b/source/blender/blenkernel/intern/library_query.c @@ -68,6 +68,7 @@ #include "BLI_linklist_stack.h" #include "BKE_animsys.h" +#include "BKE_collection.h" #include "BKE_constraint.h" #include "BKE_fcurve.h" #include "BKE_library.h" @@ -354,7 +355,7 @@ void BKE_library_foreach_ID_link(Main *bmain, ID *id, LibraryIDLinkCallback call Scene *scene = (Scene *) id; ToolSettings *toolsett = scene->toolsettings; SceneRenderLayer *srl; - Base *base; + BaseLegacy *legacy_base; CALLBACK_INVOKE(scene->camera, IDWALK_CB_NOP); CALLBACK_INVOKE(scene->world, IDWALK_CB_USER); @@ -411,8 +412,27 @@ void BKE_library_foreach_ID_link(Main *bmain, ID *id, LibraryIDLinkCallback call CALLBACK_INVOKE(scene->gpd, IDWALK_CB_USER); - for (base = scene->base.first; base; base = base->next) { - CALLBACK_INVOKE(base->object, IDWALK_CB_USER); + for (legacy_base = scene->base.first; legacy_base; legacy_base = legacy_base->next) { + CALLBACK_INVOKE(legacy_base->object, IDWALK_CB_USER); + } + + FOREACH_SCENE_COLLECTION(scene, sc) + { + for (LinkData *link = sc->objects.first; link; link = link->next) { + CALLBACK_INVOKE_ID(link->data, IDWALK_CB_USER); + } + + for (LinkData *link = sc->filter_objects.first; link; link = link->next) { + CALLBACK_INVOKE_ID(link->data, IDWALK_CB_USER); + } + } + FOREACH_SCENE_COLLECTION_END + + SceneLayer *sl; + for (sl = scene->render_layers.first; sl; sl = sl->next) { + for (Base *base = sl->object_bases.first; base; base = base->next) { + CALLBACK_INVOKE(base->object, IDWALK_NOP); + } } for (TimeMarker *marker = scene->markers.first; marker; marker = marker->next) { diff --git a/source/blender/blenkernel/intern/library_remap.c b/source/blender/blenkernel/intern/library_remap.c index a408b498f18..76af032c37f 100644 --- a/source/blender/blenkernel/intern/library_remap.c +++ b/source/blender/blenkernel/intern/library_remap.c @@ -71,6 +71,7 @@ #include "BKE_brush.h" #include "BKE_camera.h" #include "BKE_cachefile.h" +#include "BKE_collection.h" #include "BKE_curve.h" #include "BKE_depsgraph.h" #include "BKE_fcurve.h" @@ -242,7 +243,7 @@ static int foreach_libblock_remap_callback(void *user_data, ID *id_self, ID **id /* Some reamapping unfortunately require extra and/or specific handling, tackle those here. */ static void libblock_remap_data_preprocess_scene_base_unlink( - IDRemap *r_id_remap_data, Scene *sce, Base *base, const bool skip_indirect, const bool is_indirect) + IDRemap *r_id_remap_data, Scene *sce, BaseLegacy *base, const bool skip_indirect, const bool is_indirect) { if (skip_indirect && is_indirect) { r_id_remap_data->skipped_indirect++; @@ -258,6 +259,22 @@ static void libblock_remap_data_preprocess_scene_base_unlink( } } +/* Some remapping unfortunately require extra and/or specific handling, tackle those here. */ +static void libblock_remap_data_preprocess_scene_object_unlink( + IDRemap *r_id_remap_data, Scene *sce, Object *ob, const bool skip_indirect, const bool is_indirect) +{ + if (skip_indirect && is_indirect) { + r_id_remap_data->skipped_indirect++; + r_id_remap_data->skipped_refcounted++; + } + else { + BKE_collections_object_remove(r_id_remap_data->bmain, sce, ob, false); + if (!is_indirect) { + r_id_remap_data->status |= ID_REMAP_IS_LINKED_DIRECT; + } + } +} + static void libblock_remap_data_preprocess(IDRemap *r_id_remap_data) { switch (GS(r_id_remap_data->id->name)) { @@ -272,7 +289,15 @@ static void libblock_remap_data_preprocess(IDRemap *r_id_remap_data) /* In case we are unlinking... */ if (!r_id_remap_data->old_id) { /* ... everything from scene. */ - Base *base, *base_next; + FOREACH_SCENE_OBJECT(sce, ob_iter) + { + libblock_remap_data_preprocess_scene_object_unlink( + r_id_remap_data, sce, ob_iter, skip_indirect, is_indirect); + } + FOREACH_SCENE_OBJECT_END + + + BaseLegacy *base, *base_next; for (base = sce->base.first; base; base = base_next) { base_next = base->next; libblock_remap_data_preprocess_scene_base_unlink( @@ -282,8 +307,11 @@ static void libblock_remap_data_preprocess(IDRemap *r_id_remap_data) else if (GS(r_id_remap_data->old_id->name) == ID_OB) { /* ... a specific object from scene. */ Object *old_ob = (Object *)r_id_remap_data->old_id; - Base *base = BKE_scene_base_find(sce, old_ob); + libblock_remap_data_preprocess_scene_object_unlink( + r_id_remap_data, sce, old_ob, skip_indirect, is_indirect); + + BaseLegacy *base = BKE_scene_base_find(sce, old_ob); if (base) { libblock_remap_data_preprocess_scene_base_unlink( r_id_remap_data, sce, base, skip_indirect, is_indirect); @@ -329,7 +357,7 @@ static void libblock_remap_data_postprocess_object_fromgroup_update(Main *bmain, } if (new_ob == NULL) { /* We need to remove NULL-ified groupobjects... */ for (Group *group = bmain->group.first; group; group = group->id.next) { - BKE_group_object_unlink(group, NULL, NULL, NULL); + BKE_group_object_unlink(group, NULL); } } else { @@ -342,23 +370,17 @@ static void libblock_remap_data_postprocess_group_scene_unlink(Main *UNUSED(bmai { /* Note that here we assume no object has no base (i.e. all objects are assumed instanced * in one scene...). */ - for (Base *base = sce->base.first; base; base = base->next) { - if (base->flag & OB_FROMGROUP) { - Object *ob = base->object; - - if (ob->flag & OB_FROMGROUP) { - Group *grp = BKE_group_object_find(NULL, ob); - - /* Unlinked group (old_id) is still in bmain... */ - if (grp && (&grp->id == old_id || grp->id.us == 0)) { - grp = BKE_group_object_find(grp, ob); - } - if (!grp) { - ob->flag &= ~OB_FROMGROUP; - } + for (BaseLegacy *base = sce->base.first; base; base = base->next) { + Object *ob = base->object; + if (ob->flag & OB_FROMGROUP) { + Group *grp = BKE_group_object_find(NULL, ob); + + /* Unlinked group (old_id) is still in bmain... */ + if (grp && (&grp->id == old_id || grp->id.us == 0)) { + grp = BKE_group_object_find(grp, ob); } - if (!(ob->flag & OB_FROMGROUP)) { - base->flag &= ~OB_FROMGROUP; + if (!grp) { + ob->flag &= ~OB_FROMGROUP; } } } 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/mball.c b/source/blender/blenkernel/intern/mball.c index 97033a9555d..2632acea58b 100644 --- a/source/blender/blenkernel/intern/mball.c +++ b/source/blender/blenkernel/intern/mball.c @@ -316,7 +316,7 @@ bool BKE_mball_is_basis_for(Object *ob1, Object *ob2) void BKE_mball_properties_copy(Scene *scene, Object *active_object) { Scene *sce_iter = scene; - Base *base; + BaseLegacy *base; Object *ob; MetaBall *active_mball = (MetaBall *)active_object->data; int basisnr, obnr; @@ -359,27 +359,25 @@ void BKE_mball_properties_copy(Scene *scene, Object *active_object) */ Object *BKE_mball_basis_find(Scene *scene, Object *basis) { - Scene *sce_iter = scene; - Base *base; - Object *ob, *bob = basis; + Object *bob = basis; int basisnr, obnr; char basisname[MAX_ID_NAME], obname[MAX_ID_NAME]; - SceneBaseIter iter; - EvaluationContext *eval_ctx = G.main->eval_ctx; BLI_split_name_num(basisname, &basisnr, basis->id.name + 2, '.'); - BKE_scene_base_iter_next(eval_ctx, &iter, &sce_iter, 0, NULL, NULL); - while (BKE_scene_base_iter_next(eval_ctx, &iter, &sce_iter, 1, &base, &ob)) { - if ((ob->type == OB_MBALL) && !(base->flag & OB_FROMDUPLI)) { - if (ob != bob) { - BLI_split_name_num(obname, &obnr, ob->id.name + 2, '.'); - - /* object ob has to be in same "group" ... it means, that it has to have same base of its name */ - if (STREQ(obname, basisname)) { - if (obnr < basisnr) { - basis = ob; - basisnr = obnr; + for (SceneLayer *sl = scene->render_layers.first; sl; sl = sl->next) { + for (Base *base = sl->object_bases.first; base; base = base->next) { + Object *ob = base->object; + if ((ob->type == OB_MBALL) && !(base->flag & OB_FROMDUPLI)) { + if (ob != bob) { + BLI_split_name_num(obname, &obnr, ob->id.name + 2, '.'); + + /* object ob has to be in same "group" ... it means, that it has to have same base of its name */ + if (STREQ(obname, basisname)) { + if (obnr < basisnr) { + basis = ob; + basisnr = obnr; + } } } } diff --git a/source/blender/blenkernel/intern/mball_tessellate.c b/source/blender/blenkernel/intern/mball_tessellate.c index 5c0b09f0ff0..144a885ffd4 100644 --- a/source/blender/blenkernel/intern/mball_tessellate.c +++ b/source/blender/blenkernel/intern/mball_tessellate.c @@ -1080,7 +1080,7 @@ static void polygonize(PROCESS *process) static void init_meta(EvaluationContext *eval_ctx, PROCESS *process, Scene *scene, Object *ob) { Scene *sce_iter = scene; - Base *base; + BaseLegacy *base; Object *bob; MetaBall *mb; const MetaElem *ml; @@ -1102,7 +1102,7 @@ static void init_meta(EvaluationContext *eval_ctx, PROCESS *process, Scene *scen zero_size = 0; ml = NULL; - if (bob == ob && (base->flag & OB_FROMDUPLI) == 0) { + if (bob == ob && (base->flag_legacy & OB_FROMDUPLI) == 0) { mb = ob->data; if (mb->editelems) ml = mb->editelems->first; diff --git a/source/blender/blenkernel/intern/mesh.c b/source/blender/blenkernel/intern/mesh.c index 918032b2df8..bbd3578eb33 100644 --- a/source/blender/blenkernel/intern/mesh.c +++ b/source/blender/blenkernel/intern/mesh.c @@ -50,6 +50,7 @@ #include "BKE_DerivedMesh.h" #include "BKE_global.h" #include "BKE_mesh.h" +#include "BKE_mesh_render.h" #include "BKE_displist.h" #include "BKE_library.h" #include "BKE_library_query.h" @@ -442,6 +443,8 @@ void BKE_mesh_free(Mesh *me) { BKE_animdata_free(&me->id, false); + BKE_mesh_batch_cache_free(me); + CustomData_free(&me->vdata, me->totvert); CustomData_free(&me->edata, me->totedge); CustomData_free(&me->fdata, me->totface); @@ -529,6 +532,7 @@ Mesh *BKE_mesh_copy(Main *bmain, Mesh *me) BKE_mesh_update_customdata_pointers(men, do_tessface); men->edit_btmesh = NULL; + men->batch_cache = NULL; men->mselect = MEM_dupallocN(men->mselect); men->bb = MEM_dupallocN(men->bb); diff --git a/source/blender/blenkernel/intern/mesh_render.c b/source/blender/blenkernel/intern/mesh_render.c new file mode 100644 index 00000000000..b62451c4db9 --- /dev/null +++ b/source/blender/blenkernel/intern/mesh_render.c @@ -0,0 +1,717 @@ +/* + * ***** 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) 2017 by Blender Foundation. + * All rights reserved. + * + * Contributor(s): Blender Foundation, Mike Erwin, Dalai Felinto + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/blenkernel/intern/mesh_render.c + * \ingroup bke + * + * \brief Mesh API for render engines + */ + +#include "MEM_guardedalloc.h" + +#include "BLI_math_vector.h" + +#include "DNA_mesh_types.h" +#include "DNA_meshdata_types.h" + +#include "BKE_customdata.h" +#include "BKE_depsgraph.h" +#include "BKE_DerivedMesh.h" +#include "BKE_editmesh.h" +#include "BKE_mesh.h" +#include "BKE_mesh_render.h" + +#include "GPU_batch.h" + +/* ---------------------------------------------------------------------- */ +/* Mesh Interface */ + +#define MESH_RENDER_FUNCTION(func_name) \ + if (me->edit_btmesh && me->edit_btmesh->derivedFinal) { \ + return mesh_bmesh_##func_name(me); \ + } \ + else { \ + return mesh_struct_##func_name(me); \ + } + + +/* Mesh Implementation */ + +static int mesh_struct_get_num_edges(Mesh *me) +{ + return me->totedge; +} + +static int mesh_struct_get_num_verts(Mesh *me) +{ + return me->totvert; +} + +static int mesh_struct_get_num_faces(Mesh *me) +{ + BKE_mesh_tessface_ensure(me); + return me->totface; +} + +static int mesh_struct_get_num_polys(Mesh *me) +{ + return me->totpoly; +} + +static int mesh_struct_get_num_loops(Mesh *me) +{ + return me->totloop; +} + +static MEdge *mesh_struct_get_array_edge(Mesh *me) +{ + return CustomData_get_layer(&me->edata, CD_MEDGE); +} + +static MFace *mesh_struct_get_array_face(Mesh *me) +{ + BKE_mesh_tessface_ensure(me); + return CustomData_get_layer(&me->fdata, CD_MFACE); +} + +static MLoop *mesh_struct_get_array_loop(Mesh *me) +{ + return me->mloop; +} + +static MPoly *mesh_struct_get_array_poly(Mesh *me) +{ + return me->mpoly; +} + +static MVert *mesh_struct_get_array_vert(Mesh *me) +{ + return CustomData_get_layer(&me->vdata, CD_MVERT); +} + +/* BMesh Implementation */ + +/* NOTE: we may want to get rid of Derived Mesh and + * access BMesh directly */ + +static int mesh_bmesh_get_num_verts(Mesh *me) +{ + BMEditMesh *bm = me->edit_btmesh; + DerivedMesh *dm = bm->derivedFinal; + return dm->getNumVerts(dm); +} + +static int mesh_bmesh_get_num_edges(Mesh *me) +{ + BMEditMesh *bm = me->edit_btmesh; + DerivedMesh *dm = bm->derivedFinal; + return dm->getNumEdges(dm); +} + +static int mesh_bmesh_get_num_faces(Mesh *me) +{ + BMEditMesh *bm = me->edit_btmesh; + DerivedMesh *dm = bm->derivedFinal; + return dm->getNumTessFaces(dm); +} + +static int mesh_bmesh_get_num_polys(Mesh *me) +{ + BMEditMesh *bm = me->edit_btmesh; + DerivedMesh *dm = bm->derivedFinal; + return dm->getNumPolys(dm); +} + +static int mesh_bmesh_get_num_loops(Mesh *me) +{ + BMEditMesh *bm = me->edit_btmesh; + DerivedMesh *dm = bm->derivedFinal; + return dm->getNumLoops(dm); +} + +static MEdge *mesh_bmesh_get_array_edge(Mesh *me) +{ + BMEditMesh *bm = me->edit_btmesh; + DerivedMesh *dm = bm->derivedFinal; + return dm->getEdgeArray(dm); +} + +static MFace *mesh_bmesh_get_array_face(Mesh *me) +{ + BMEditMesh *bm = me->edit_btmesh; + DerivedMesh *dm = bm->derivedFinal; + return dm->getTessFaceArray(dm); +} + +static MLoop *mesh_bmesh_get_array_loop(Mesh *me) +{ + BMEditMesh *bm = me->edit_btmesh; + DerivedMesh *dm = bm->derivedFinal; + return dm->getLoopArray(dm); +} + +static MPoly *mesh_bmesh_get_array_poly(Mesh *me) +{ + BMEditMesh *bm = me->edit_btmesh; + DerivedMesh *dm = bm->derivedFinal; + return dm->getPolyArray(dm); +} + +static MVert *mesh_bmesh_get_array_vert(Mesh *me) +{ + BMEditMesh *bm = me->edit_btmesh; + DerivedMesh *dm = bm->derivedFinal; + return dm->getVertArray(dm); +} + +/* Mesh API */ + +static int mesh_render_get_num_edges(Mesh *me) +{ + MESH_RENDER_FUNCTION(get_num_edges); +} + +static int mesh_render_get_num_faces(Mesh *me) +{ + MESH_RENDER_FUNCTION(get_num_faces); +} + +static int mesh_render_get_num_loops(Mesh *me) +{ + MESH_RENDER_FUNCTION(get_num_loops); +} + +static int mesh_render_get_num_polys(Mesh *me) +{ + MESH_RENDER_FUNCTION(get_num_polys); +} + +static int mesh_render_get_num_verts(Mesh *me) +{ + MESH_RENDER_FUNCTION(get_num_verts); +} + +static MEdge *mesh_render_get_array_edge(Mesh *me) +{ + MESH_RENDER_FUNCTION(get_array_edge); +} + +static MFace *mesh_render_get_array_face(Mesh *me) +{ + MESH_RENDER_FUNCTION(get_array_face); +} + +static MLoop *mesh_render_get_array_loop(Mesh *me) +{ + MESH_RENDER_FUNCTION(get_array_loop); +} + +static MPoly *mesh_render_get_array_poly(Mesh *me) +{ + MESH_RENDER_FUNCTION(get_array_poly); +} + +static MVert *mesh_render_get_array_vert(Mesh *me) +{ + MESH_RENDER_FUNCTION(get_array_vert); +} + +/* ---------------------------------------------------------------------- */ +/* Mesh Batch Cache */ + +typedef struct MeshBatchCache { + VertexBuffer *pos_in_order; + ElementList *edges_in_order; + ElementList *triangles_in_order; + + Batch *all_verts; + Batch *all_edges; + Batch *all_triangles; + + Batch *triangles_with_normals; /* owns its vertex buffer */ + Batch *fancy_edges; /* owns its vertex buffer (not shared) */ + Batch *overlay_edges; /* owns its vertex buffer */ + + /* settings to determine if cache is invalid */ + bool is_dirty; + int tot_edges; + int tot_faces; + int tot_polys; + int tot_verts; + bool is_editmode; +} MeshBatchCache; + +static bool mesh_batch_cache_valid(Mesh *me) +{ + MeshBatchCache *cache = me->batch_cache; + + if (cache == NULL) { + return false; + } + + if (cache->is_editmode != (me->edit_btmesh != NULL)) { + return false; + } + + if (cache->is_dirty == false) { + return true; + } + else { + if (cache->is_editmode) { + return false; + } + else if ((cache->tot_edges != mesh_render_get_num_edges(me)) || + (cache->tot_faces != mesh_render_get_num_faces(me)) || + (cache->tot_polys != mesh_render_get_num_polys(me)) || + (cache->tot_verts != mesh_render_get_num_verts(me))) + { + return false; + } + } + + return true; +} + +static void mesh_batch_cache_init(Mesh *me) +{ + MeshBatchCache *cache = me->batch_cache; + cache->is_editmode = me->edit_btmesh != NULL; + + if (cache->is_editmode == false) { + cache->tot_edges = mesh_render_get_num_edges(me); + cache->tot_faces = mesh_render_get_num_faces(me); + cache->tot_polys = mesh_render_get_num_polys(me); + cache->tot_verts = mesh_render_get_num_verts(me); + } + + cache->is_dirty = false; +} + +static MeshBatchCache *mesh_batch_cache_get(Mesh *me) +{ + if (!mesh_batch_cache_valid(me)) { + BKE_mesh_batch_cache_free(me); + me->batch_cache = MEM_callocN(sizeof(MeshBatchCache), "MeshBatchCache"); + mesh_batch_cache_init(me); + } + return me->batch_cache; +} + +static VertexBuffer *mesh_batch_cache_get_pos_in_order(Mesh *me) +{ + MeshBatchCache *cache = mesh_batch_cache_get(me); + + if (cache->pos_in_order == NULL) { + static VertexFormat format = { 0 }; + static unsigned pos_id; + if (format.attrib_ct == 0) { + /* initialize vertex format */ + pos_id = add_attrib(&format, "pos", GL_FLOAT, 3, KEEP_FLOAT); + } + + const int vertex_ct = mesh_render_get_num_verts(me); + const MVert *verts = mesh_render_get_array_vert(me); + + cache->pos_in_order = VertexBuffer_create_with_format(&format); + VertexBuffer_allocate_data(cache->pos_in_order, vertex_ct); +#if 0 + const unsigned stride = (verts + 1) - verts; /* or sizeof(MVert) */ + fillAttribStride(cache->pos_in_order, pos_id, stride, &verts[0].co); +#else + for (int i = 0; i < vertex_ct; ++i) { + setAttrib(cache->pos_in_order, pos_id, i, &verts[i].co); + } +#endif + } + + return cache->pos_in_order; +} + +static ElementList *mesh_batch_cache_get_edges_in_order(Mesh *me) +{ + MeshBatchCache *cache = mesh_batch_cache_get(me); + + if (cache->edges_in_order == NULL) { + const int vertex_ct = mesh_render_get_num_verts(me); + const int edge_ct = mesh_render_get_num_edges(me); + const MEdge *edges = mesh_render_get_array_edge(me); + + ElementListBuilder elb; + ElementListBuilder_init(&elb, GL_LINES, edge_ct, vertex_ct); + for (int i = 0; i < edge_ct; ++i) { + const MEdge *edge = edges + i; + add_line_vertices(&elb, edge->v1, edge->v2); + } + cache->edges_in_order = ElementList_build(&elb); + } + + return cache->edges_in_order; +} + +static ElementList *mesh_batch_cache_get_triangles_in_order(Mesh *me) +{ + MeshBatchCache *cache = mesh_batch_cache_get(me); + + if (cache->triangles_in_order == NULL) { + const int vertex_ct = mesh_render_get_num_verts(me); + const int tessface_ct = mesh_render_get_num_faces(me); + MFace *tessfaces = mesh_render_get_array_face(me); + + ElementListBuilder elb; + ElementListBuilder_init(&elb, GL_TRIANGLES, tessface_ct * 2, vertex_ct); /* up to 2 triangles per tessface */ + for (int i = 0; i < tessface_ct; ++i) { + const MFace *tess = tessfaces + i; + add_triangle_vertices(&elb, tess->v1, tess->v2, tess->v3); + + if (tess->v4) { + add_triangle_vertices(&elb, tess->v1, tess->v3, tess->v4); + } + } + cache->triangles_in_order = ElementList_build(&elb); + } + + /* NOTE: we are reallocating, it would be interesting to reallocating the memory once we + * know the exactly triangle count (like in BKE_mesh_batch_cache_get_overlay_edges) */ + + return cache->triangles_in_order; +} + +void BKE_mesh_batch_cache_dirty(struct Mesh *me) +{ + MeshBatchCache *cache = me->batch_cache; + if (cache) { + cache->is_dirty = true; + } +} + +void BKE_mesh_batch_cache_free(Mesh *me) +{ + MeshBatchCache *cache = me->batch_cache; + if (!cache) { + return; + } + + if (cache->all_verts) Batch_discard(cache->all_verts); + if (cache->all_edges) Batch_discard(cache->all_edges); + if (cache->all_triangles) Batch_discard(cache->all_triangles); + + if (cache->pos_in_order) VertexBuffer_discard(cache->pos_in_order); + if (cache->edges_in_order) ElementList_discard(cache->edges_in_order); + if (cache->triangles_in_order) ElementList_discard(cache->triangles_in_order); + + if (cache->triangles_with_normals) { + Batch_discard_all(cache->triangles_with_normals); + } + + if (cache->fancy_edges) { + Batch_discard_all(cache->fancy_edges); + } + + if (cache->overlay_edges) { + Batch_discard_all(cache->overlay_edges); + } + + MEM_freeN(cache); + me->batch_cache = NULL; +} + +Batch *BKE_mesh_batch_cache_get_all_edges(Mesh *me) +{ + MeshBatchCache *cache = mesh_batch_cache_get(me); + + if (cache->all_edges == NULL) { + /* create batch from Mesh */ + cache->all_edges = Batch_create(GL_LINES, mesh_batch_cache_get_pos_in_order(me), mesh_batch_cache_get_edges_in_order(me)); + } + + return cache->all_edges; +} + +Batch *BKE_mesh_batch_cache_get_all_triangles(Mesh *me) +{ + MeshBatchCache *cache = mesh_batch_cache_get(me); + + if (cache->all_triangles == NULL) { + /* create batch from DM */ + cache->all_triangles = Batch_create(GL_TRIANGLES, mesh_batch_cache_get_pos_in_order(me), mesh_batch_cache_get_triangles_in_order(me)); + } + + return cache->all_triangles; +} + +Batch *BKE_mesh_batch_cache_get_triangles_with_normals(Mesh *me) +{ + MeshBatchCache *cache = mesh_batch_cache_get(me); + + if (cache->triangles_with_normals == NULL) { + unsigned int vidx = 0, nidx = 0; + float face_no[3]; + short face_no_short[3]; + unsigned int mpoly_prev = UINT_MAX; + + static VertexFormat format = { 0 }; + static unsigned pos_id, nor_id; + if (format.attrib_ct == 0) { + /* initialize vertex format */ + pos_id = add_attrib(&format, "pos", GL_FLOAT, 3, KEEP_FLOAT); + nor_id = add_attrib(&format, "nor", GL_SHORT, 3, NORMALIZE_INT_TO_FLOAT); + } + const MVert *verts = mesh_render_get_array_vert(me); + const MLoop *loops = mesh_render_get_array_loop(me); + const MPoly *polys = mesh_render_get_array_poly(me); + const int totpoly = mesh_render_get_num_polys(me); + const int totloop = mesh_render_get_num_loops(me); + + const int tottri = poly_to_tri_count(totpoly,totloop); + MLoopTri *looptri = MEM_mallocN(sizeof(*looptri) * tottri, __func__); + + BKE_mesh_recalc_looptri(loops, polys, verts, totloop, totpoly, looptri); + + VertexBuffer *vbo = VertexBuffer_create_with_format(&format); + VertexBuffer_allocate_data(vbo, tottri * 3); + + for (int i = 0; i < tottri; i++) { + const MLoopTri *lt = &looptri[i]; + const MPoly *mp = &polys[lt->poly]; + + /* Calc Normal */ + if (lt->poly != mpoly_prev) { + BKE_mesh_calc_poly_normal(mp, &loops[mp->loopstart], verts, face_no); + mpoly_prev = lt->poly; + } + + if ((mp->flag & ME_SMOOTH) == 0) { + normal_float_to_short_v3(face_no_short, face_no); + setAttrib(vbo, nor_id, nidx++, face_no_short); + setAttrib(vbo, nor_id, nidx++, face_no_short); + setAttrib(vbo, nor_id, nidx++, face_no_short); + } + else { + setAttrib(vbo, nor_id, nidx++, &verts[loops[lt->tri[0]].v].no); + setAttrib(vbo, nor_id, nidx++, &verts[loops[lt->tri[1]].v].no); + setAttrib(vbo, nor_id, nidx++, &verts[loops[lt->tri[2]].v].no); + } + + setAttrib(vbo, pos_id, vidx++, &verts[loops[lt->tri[0]].v].co); + setAttrib(vbo, pos_id, vidx++, &verts[loops[lt->tri[1]].v].co); + setAttrib(vbo, pos_id, vidx++, &verts[loops[lt->tri[2]].v].co); + } + + cache->triangles_with_normals = Batch_create(GL_TRIANGLES, vbo, NULL); + + MEM_freeN(looptri); + } + + return cache->triangles_with_normals; +} + +Batch *BKE_mesh_batch_cache_get_all_verts(Mesh *me) +{ + MeshBatchCache *cache = mesh_batch_cache_get(me); + + if (cache->all_verts == NULL) { + /* create batch from DM */ + cache->all_verts = Batch_create(GL_POINTS, mesh_batch_cache_get_pos_in_order(me), NULL); + Batch_set_builtin_program(cache->all_verts, GPU_SHADER_3D_POINT_FIXED_SIZE_UNIFORM_COLOR); + } + + return cache->all_verts; +} + +Batch *BKE_mesh_batch_cache_get_fancy_edges(Mesh *me) +{ + MeshBatchCache *cache = mesh_batch_cache_get(me); + + if (cache->fancy_edges == NULL) { + /* create batch from DM */ + static VertexFormat format = { 0 }; + static unsigned pos_id, n1_id, n2_id; + if (format.attrib_ct == 0) { + /* initialize vertex format */ + pos_id = add_attrib(&format, "pos", COMP_F32, 3, KEEP_FLOAT); + +#if USE_10_10_10 /* takes 1/3 the space */ + n1_id = add_attrib(&format, "N1", COMP_I10, 3, NORMALIZE_INT_TO_FLOAT); + n2_id = add_attrib(&format, "N2", COMP_I10, 3, NORMALIZE_INT_TO_FLOAT); +#else + n1_id = add_attrib(&format, "N1", COMP_F32, 3, KEEP_FLOAT); + n2_id = add_attrib(&format, "N2", COMP_F32, 3, KEEP_FLOAT); +#endif + } + VertexBuffer *vbo = VertexBuffer_create_with_format(&format); + + const MVert *verts = mesh_render_get_array_vert(me); + const MEdge *edges = mesh_render_get_array_edge(me); + const MPoly *polys = mesh_render_get_array_poly(me); + const MLoop *loops = mesh_render_get_array_loop(me); + const int edge_ct = mesh_render_get_num_edges(me); + const int poly_ct = mesh_render_get_num_polys(me); + + /* need normal of each face, and which faces are adjacent to each edge */ + typedef struct { + int count; + int face_index[2]; + } AdjacentFaces; + + float (*face_normal)[3] = MEM_mallocN(poly_ct * 3 * sizeof(float), "face_normal"); + AdjacentFaces *adj_faces = MEM_callocN(edge_ct * sizeof(AdjacentFaces), "adj_faces"); + + for (int i = 0; i < poly_ct; ++i) { + const MPoly *poly = polys + i; + + BKE_mesh_calc_poly_normal(poly, loops + poly->loopstart, verts, face_normal[i]); + + for (int j = poly->loopstart; j < (poly->loopstart + poly->totloop); ++j) { + AdjacentFaces *adj = adj_faces + loops[j].e; + if (adj->count < 2) + adj->face_index[adj->count] = i; + adj->count++; + } + } + + const int vertex_ct = edge_ct * 2; /* these are GL_LINE verts, not mesh verts */ + VertexBuffer_allocate_data(vbo, vertex_ct); + for (int i = 0; i < edge_ct; ++i) { + const MEdge *edge = edges + i; + const AdjacentFaces *adj = adj_faces + i; + +#if USE_10_10_10 + PackedNormal n1value = { .x = 0, .y = 0, .z = +511 }; + PackedNormal n2value = { .x = 0, .y = 0, .z = -511 }; + + if (adj->count == 2) { + n1value = convert_i10_v3(face_normal[adj->face_index[0]]); + n2value = convert_i10_v3(face_normal[adj->face_index[1]]); + } + + const PackedNormal *n1 = &n1value; + const PackedNormal *n2 = &n2value; +#else + const float dummy1[3] = { 0.0f, 0.0f, +1.0f }; + const float dummy2[3] = { 0.0f, 0.0f, -1.0f }; + + const float *n1 = (adj->count == 2) ? face_normal[adj->face_index[0]] : dummy1; + const float *n2 = (adj->count == 2) ? face_normal[adj->face_index[1]] : dummy2; +#endif + + setAttrib(vbo, pos_id, 2 * i, &verts[edge->v1].co); + setAttrib(vbo, n1_id, 2 * i, n1); + setAttrib(vbo, n2_id, 2 * i, n2); + + setAttrib(vbo, pos_id, 2 * i + 1, &verts[edge->v2].co); + setAttrib(vbo, n1_id, 2 * i + 1, n1); + setAttrib(vbo, n2_id, 2 * i + 1, n2); + } + + MEM_freeN(adj_faces); + MEM_freeN(face_normal); + + cache->fancy_edges = Batch_create(GL_LINES, vbo, NULL); + } + + return cache->fancy_edges; +} + +static bool edge_is_real(const MEdge *edges, int edge_ct, int v1, int v2) +{ + /* TODO: same thing, except not ridiculously slow */ + + for (int e = 0; e < edge_ct; ++e) { + const MEdge *edge = edges + e; + if ((edge->v1 == v1 && edge->v2 == v2) || (edge->v1 == v2 && edge->v2 == v1)) { + return true; + } + } + + return false; +} + +static void add_overlay_tri( + VertexBuffer *vbo, unsigned pos_id, unsigned edgeMod_id, const MVert *verts, + const MEdge *edges, int edge_ct, int v1, int v2, int v3, int base_vert_idx) +{ + const float edgeMods[2] = { 0.0f, 1.0f }; + + const float *pos = verts[v1].co; + setAttrib(vbo, pos_id, base_vert_idx + 0, pos); + setAttrib(vbo, edgeMod_id, base_vert_idx + 0, edgeMods + (edge_is_real(edges, edge_ct, v2, v3) ? 1 : 0)); + + pos = verts[v2].co; + setAttrib(vbo, pos_id, base_vert_idx + 1, pos); + setAttrib(vbo, edgeMod_id, base_vert_idx + 1, edgeMods + (edge_is_real(edges, edge_ct, v3, v1) ? 1 : 0)); + + pos = verts[v3].co; + setAttrib(vbo, pos_id, base_vert_idx + 2, pos); + setAttrib(vbo, edgeMod_id, base_vert_idx + 2, edgeMods + (edge_is_real(edges, edge_ct, v1, v2) ? 1 : 0)); +} + +Batch *BKE_mesh_batch_cache_get_overlay_edges(Mesh *me) +{ + MeshBatchCache *cache = mesh_batch_cache_get(me); + + if (cache->overlay_edges == NULL) { + /* create batch from DM */ + static VertexFormat format = { 0 }; + static unsigned pos_id, edgeMod_id; + + if (format.attrib_ct == 0) { + /* initialize vertex format */ + pos_id = add_attrib(&format, "pos", GL_FLOAT, 3, KEEP_FLOAT); + edgeMod_id = add_attrib(&format, "edgeWidthModulator", GL_FLOAT, 1, KEEP_FLOAT); + } + VertexBuffer *vbo = VertexBuffer_create_with_format(&format); + + const int edge_ct = mesh_render_get_num_edges(me); + const int tessface_ct = mesh_render_get_num_faces(me); + const MVert *verts = mesh_render_get_array_vert(me); + const MEdge *edges = mesh_render_get_array_edge(me); + const MFace *tessfaces = mesh_render_get_array_face(me); + + VertexBuffer_allocate_data(vbo, tessface_ct * 6); /* up to 2 triangles per tessface */ + + int gpu_vert_idx = 0; + for (int i = 0; i < tessface_ct; ++i) { + const MFace *tess = tessfaces + i; + add_overlay_tri(vbo, pos_id, edgeMod_id, verts, edges, edge_ct, tess->v1, tess->v2, tess->v3, gpu_vert_idx); + gpu_vert_idx += 3; + /* tessface can be triangle or quad */ + if (tess->v4) { + add_overlay_tri(vbo, pos_id, edgeMod_id, verts, edges, edge_ct, tess->v3, tess->v2, tess->v4, gpu_vert_idx); + gpu_vert_idx += 3; + } + } + + /* in some cases all the faces are quad, so no need to reallocate */ + if (vbo->vertex_ct != gpu_vert_idx) { + VertexBuffer_resize_data(vbo, gpu_vert_idx); + } + + cache->overlay_edges = Batch_create(GL_TRIANGLES, vbo, NULL); + } + + return cache->overlay_edges; +} + +#undef MESH_RENDER_FUNCTION diff --git a/source/blender/blenkernel/intern/node.c b/source/blender/blenkernel/intern/node.c index 3f3b4896653..05422a01dbf 100644 --- a/source/blender/blenkernel/intern/node.c +++ b/source/blender/blenkernel/intern/node.c @@ -3776,3 +3776,20 @@ bool BKE_node_tree_iter_step(struct NodeTreeIterStore *ntreeiter, return true; } + +/* -------------------------------------------------------------------- */ +/* NodeTree kernel functions */ + +void BKE_nodetree_remove_layer_n(bNodeTree *ntree, Scene *scene, const int layer_index) +{ + for (bNode *node = ntree->nodes.first; node; node = node->next) { + if (node->type == CMP_NODE_R_LAYERS && (Scene *)node->id == scene) { + if (node->custom1 == layer_index) { + node->custom1 = 0; + } + else if (node->custom1 > layer_index) { + node->custom1--; + } + } + } +} diff --git a/source/blender/blenkernel/intern/object.c b/source/blender/blenkernel/intern/object.c index 6e754755cf3..ad0ce3fef9b 100644 --- a/source/blender/blenkernel/intern/object.c +++ b/source/blender/blenkernel/intern/object.c @@ -91,6 +91,7 @@ #include "BKE_icons.h" #include "BKE_key.h" #include "BKE_lamp.h" +#include "BKE_layer.h" #include "BKE_lattice.h" #include "BKE_library.h" #include "BKE_library_query.h" @@ -153,7 +154,7 @@ void BKE_object_workob_clear(Object *workob) void BKE_object_update_base_layer(struct Scene *scene, Object *ob) { - Base *base = scene->base.first; + BaseLegacy *base = scene->base.first; while (base) { if (base->object == ob) base->lay = ob->lay; @@ -458,6 +459,8 @@ void BKE_object_free(Object *ob) } BKE_previewimg_free(&ob->preview); + + BKE_layer_collection_engine_settings_list_free(&ob->collection_settings); } /* actual check for internal data, not context or flags */ @@ -677,23 +680,25 @@ Object *BKE_object_add_only_object(Main *bmain, int type, const char *name) /* general add: to scene, with layer from area and default name */ /* creates minimum required data, but without vertices etc. */ Object *BKE_object_add( - Main *bmain, Scene *scene, + Main *bmain, Scene *scene, SceneLayer *sl, int type, const char *name) { Object *ob; Base *base; + LayerCollection *lc; ob = BKE_object_add_only_object(bmain, type, name); ob->data = BKE_object_obdata_add_from_type(bmain, type, name); - ob->lay = scene->lay; - - base = BKE_scene_base_add(scene, ob); - BKE_scene_base_deselect_all(scene); - BKE_scene_base_select(scene, base); - DAG_id_tag_update_ex(bmain, &ob->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME); + lc = BKE_layer_collection_active(sl); + BKE_collection_object_add(scene, lc->scene_collection, ob); + base = BKE_scene_layer_base_find(sl, ob); + BKE_scene_layer_base_deselect_all(sl); + BKE_scene_layer_base_select(sl, base); + + DAG_id_tag_update_ex(bmain, &ob->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME); return ob; } @@ -2482,11 +2487,11 @@ void BKE_scene_foreach_display_point( Scene *scene, View3D *v3d, const short flag, void (*func_cb)(const float[3], void *), void *user_data) { - Base *base; + BaseLegacy *base; Object *ob; for (base = FIRSTBASE; base; base = base->next) { - if (BASE_VISIBLE_BGMODE(v3d, scene, base) && (base->flag & flag) == flag) { + if (BASE_VISIBLE_BGMODE(v3d, scene, base) && (base->flag_legacy & flag) == flag) { ob = base->object; if ((ob->transflag & OB_DUPLI) == 0) { @@ -3291,7 +3296,7 @@ LinkNode *BKE_object_relational_superset(struct Scene *scene, eObjectSet objectS { LinkNode *links = NULL; - Base *base; + BaseLegacy *base; /* Remove markers from all objects */ for (base = scene->base.first; base; base = base->next) { @@ -3335,7 +3340,7 @@ LinkNode *BKE_object_relational_superset(struct Scene *scene, eObjectSet objectS /* child relationship */ if (includeFilter & (OB_REL_CHILDREN | OB_REL_CHILDREN_RECURSIVE)) { - Base *local_base; + BaseLegacy *local_base; for (local_base = scene->base.first; local_base; local_base = local_base->next) { if (BASE_EDITABLE_BGMODE(((View3D *)NULL), scene, local_base)) { @@ -3381,18 +3386,11 @@ struct LinkNode *BKE_object_groups(Object *ob) return group_linknode; } -void BKE_object_groups_clear(Scene *scene, Base *base, Object *object) +void BKE_object_groups_clear(Object *ob) { Group *group = NULL; - - BLI_assert((base == NULL) || (base->object == object)); - - if (scene && base == NULL) { - base = BKE_scene_base_find(scene, object); - } - - while ((group = BKE_group_object_find(group, base->object))) { - BKE_group_object_unlink(group, object, scene, base); + while ((group = BKE_group_object_find(group, ob))) { + BKE_group_object_unlink(group, ob); } } diff --git a/source/blender/blenkernel/intern/object_dupli.c b/source/blender/blenkernel/intern/object_dupli.c index e3b801b3193..26af1c48afb 100644 --- a/source/blender/blenkernel/intern/object_dupli.c +++ b/source/blender/blenkernel/intern/object_dupli.c @@ -241,7 +241,7 @@ static void make_child_duplis(const DupliContext *ctx, void *userdata, MakeChild else { unsigned int lay = ctx->scene->lay; int baseid = 0; - Base *base; + BaseLegacy *base; for (base = ctx->scene->base.first; base; base = base->next, baseid++) { Object *ob = base->object; diff --git a/source/blender/blenkernel/intern/object_update.c b/source/blender/blenkernel/intern/object_update.c index 5cb704e4737..46e6d09294d 100644 --- a/source/blender/blenkernel/intern/object_update.c +++ b/source/blender/blenkernel/intern/object_update.c @@ -51,6 +51,7 @@ #include "BKE_key.h" #include "BKE_lamp.h" #include "BKE_lattice.h" +#include "BKE_mesh_render.h" #include "BKE_editmesh.h" #include "BKE_object.h" #include "BKE_particle.h" @@ -60,11 +61,7 @@ #include "DEG_depsgraph.h" -#ifdef WITH_LEGACY_DEPSGRAPH -# define DEBUG_PRINT if (!DEG_depsgraph_use_legacy() && G.debug & G_DEBUG_DEPSGRAPH) printf -#else -# define DEBUG_PRINT if (G.debug & G_DEBUG_DEPSGRAPH) printf -#endif +#define DEBUG_PRINT if (G.debug & G_DEBUG_DEPSGRAPH) printf static ThreadMutex material_lock = BLI_MUTEX_INITIALIZER; @@ -347,3 +344,11 @@ void BKE_object_eval_uber_data(EvaluationContext *eval_ctx, ob->recalc &= ~(OB_RECALC_DATA | OB_RECALC_TIME); } + +void BKE_object_eval_shading(EvaluationContext *UNUSED(eval_ctx), Object *ob) +{ + DEBUG_PRINT("%s on %s\n", __func__, ob->id.name); + if (ob->type == OB_MESH) { + BKE_mesh_batch_cache_dirty(ob->data); + } +} diff --git a/source/blender/blenkernel/intern/particle_system.c b/source/blender/blenkernel/intern/particle_system.c index 943dc781246..8531c7c9df9 100644 --- a/source/blender/blenkernel/intern/particle_system.c +++ b/source/blender/blenkernel/intern/particle_system.c @@ -2896,7 +2896,7 @@ static void psys_update_path_cache(ParticleSimulationData *sim, float cfra, cons ParticleSystem *psys = sim->psys; ParticleSettings *part = psys->part; ParticleEditSettings *pset = &sim->scene->toolsettings->particle; - Base *base; + BaseLegacy *base; int distr=0, alloc=0, skip=0; if ((psys->part->childtype && psys->totchild != psys_get_tot_child(sim->scene, psys)) || psys->recalc&PSYS_RECALC_RESET) diff --git a/source/blender/blenkernel/intern/rigidbody.c b/source/blender/blenkernel/intern/rigidbody.c index 5353cc26295..73fe5ae6cb8 100644 --- a/source/blender/blenkernel/intern/rigidbody.c +++ b/source/blender/blenkernel/intern/rigidbody.c @@ -1589,7 +1589,7 @@ void BKE_rigidbody_do_simulation(Scene *scene, float ctime) } /* advance simulation, we can only step one frame forward */ - if (can_simulate) { + if (ctime == rbw->ltime + 1) { /* write cache for first frame when on second frame */ if (rbw->ltime == startframe && (cache->flag & PTCACHE_OUTDATED || cache->last_exact == 0)) { BKE_ptcache_write(&pid, startframe); diff --git a/source/blender/blenkernel/intern/scene.c b/source/blender/blenkernel/intern/scene.c index 56bfe5d7ff1..8f3783bc4a3 100644 --- a/source/blender/blenkernel/intern/scene.c +++ b/source/blender/blenkernel/intern/scene.c @@ -67,6 +67,7 @@ #include "BKE_action.h" #include "BKE_armature.h" #include "BKE_cachefile.h" +#include "BKE_collection.h" #include "BKE_colortools.h" #include "BKE_depsgraph.h" #include "BKE_editmesh.h" @@ -78,6 +79,7 @@ #include "BKE_icons.h" #include "BKE_idprop.h" #include "BKE_image.h" +#include "BKE_layer.h" #include "BKE_library.h" #include "BKE_library_remap.h" #include "BKE_linestyle.h" @@ -107,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) @@ -154,13 +157,66 @@ static void remove_sequencer_fcurves(Scene *sce) } } +/* copy SceneCollection tree but keep pointing to the same objects */ +static void scene_collection_copy(SceneCollection *scn, SceneCollection *sc) +{ + BLI_duplicatelist(&scn->objects, &sc->objects); + for (LinkData *link = scn->objects.first; link; link = link->next) { + id_us_plus(link->data); + } + + BLI_duplicatelist(&scn->filter_objects, &sc->filter_objects); + for (LinkData *link = scn->filter_objects.first; link; link = link->next) { + id_us_plus(link->data); + } + + BLI_duplicatelist(&scn->scene_collections, &sc->scene_collections); + SceneCollection *nscn = scn->scene_collections.first; /* nested SceneCollection new */ + for (SceneCollection *nsc = sc->scene_collections.first; nsc; nsc = nsc->next) { + scene_collection_copy(nscn, nsc); + nscn = nscn->next; + } +} + +/* Find the equivalent SceneCollection in the new tree */ +static SceneCollection *scene_collection_from_new_tree(SceneCollection *sc_reference, SceneCollection *scn, SceneCollection *sc) +{ + if (sc == sc_reference) { + return scn; + } + + SceneCollection *nscn = scn->scene_collections.first; /* nested master collection new */ + for (SceneCollection *nsc = sc->scene_collections.first; nsc; nsc = nsc->next) { + + SceneCollection *found = scene_collection_from_new_tree(sc_reference, nscn, nsc); + if (found) { + return found; + } + nscn = nscn->next; + } + return NULL; +} + +/* recreate the LayerCollection tree */ +static void layer_collections_recreate(SceneLayer *sl, ListBase *lb, SceneCollection *mcn, SceneCollection *mc) +{ + for (LayerCollection *lc = lb->first; lc; lc = lc->next) { + + SceneCollection *sc = scene_collection_from_new_tree(lc->scene_collection, mcn, mc); + BLI_assert(sc); + + /* instead of syncronizing both trees we simply re-create it */ + BKE_collection_link(sl, sc); + } +} + Scene *BKE_scene_copy(Main *bmain, Scene *sce, int type) { Scene *scen; SceneRenderLayer *srl, *new_srl; FreestyleLineSet *lineset; ToolSettings *ts; - Base *base, *obase; + BaseLegacy *legacy_base, *olegacy_base; if (type == SCE_COPY_EMPTY) { ListBase rl, rv; @@ -214,14 +270,14 @@ Scene *BKE_scene_copy(Main *bmain, Scene *sce, int type) BKE_libblock_relink_ex(bmain, scen->nodetree, &sce->id, &scen->id, false); } - obase = sce->base.first; - base = scen->base.first; - while (base) { - id_us_plus(&base->object->id); - if (obase == sce->basact) scen->basact = base; + olegacy_base = sce->base.first; + legacy_base = scen->base.first; + while (legacy_base) { + id_us_plus(&legacy_base->object->id); + if (olegacy_base == sce->basact) scen->basact = legacy_base; - obase = obase->next; - base = base->next; + olegacy_base = olegacy_base->next; + legacy_base = legacy_base->next; } /* copy action and remove animation used by sequencer */ @@ -244,6 +300,36 @@ Scene *BKE_scene_copy(Main *bmain, Scene *sce, int type) } new_srl = new_srl->next; } + + /* layers and collections */ + scen->collection = MEM_dupallocN(sce->collection); + SceneCollection *mcn = BKE_collection_master(scen); + SceneCollection *mc = BKE_collection_master(sce); + + /* recursively creates a new SceneCollection tree */ + scene_collection_copy(mcn, mc); + + BLI_duplicatelist(&scen->render_layers, &sce->render_layers); + SceneLayer *new_sl = scen->render_layers.first; + for (SceneLayer *sl = sce->render_layers.first; sl; sl = sl->next) { + + /* we start fresh with no overrides and no visibility flags set + * instead of syncing both trees we simply unlink and relink the scene collection */ + BLI_listbase_clear(&new_sl->layer_collections); + BLI_listbase_clear(&new_sl->object_bases); + layer_collections_recreate(new_sl, &sl->layer_collections, mcn, mc); + + if (sl->basact) { + Object *active_ob = sl->basact->object; + for (Base *base = new_sl->object_bases.first; base; base = base->next) { + if (base->object == active_ob) { + new_sl->basact = base; + break; + } + } + } + new_sl = new_sl->next; + } } /* copy color management settings */ @@ -471,6 +557,23 @@ void BKE_scene_free(Scene *sce) BKE_previewimg_free(&sce->preview); curvemapping_free_data(&sce->r.mblur_shutter_curve); + + for (SceneLayer *sl = sce->render_layers.first; sl; sl = sl->next) { + BKE_scene_layer_free(sl); + } + BLI_freelistN(&sce->render_layers); + + /* Master Collection */ + 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) @@ -820,6 +923,12 @@ void BKE_scene_init(Scene *sce) sce->toolsettings->gpencil_v2d_align = GP_PROJECT_VIEWSPACE; sce->toolsettings->gpencil_seq_align = GP_PROJECT_VIEWSPACE; sce->toolsettings->gpencil_ima_align = GP_PROJECT_VIEWSPACE; + + /* Master Collection */ + sce->collection = MEM_callocN(sizeof(SceneCollection), "Master Collection"); + BLI_strncpy(sce->collection->name, "Master Collection", sizeof(sce->collection->name)); + + BKE_scene_layer_add(sce, "Render Layer"); } Scene *BKE_scene_add(Main *bmain, const char *name) @@ -835,9 +944,9 @@ Scene *BKE_scene_add(Main *bmain, const char *name) return sce; } -Base *BKE_scene_base_find_by_name(struct Scene *scene, const char *name) +BaseLegacy *BKE_scene_base_find_by_name(struct Scene *scene, const char *name) { - Base *base; + BaseLegacy *base; for (base = scene->base.first; base; base = base->next) { if (STREQ(base->object->id.name + 2, name)) { @@ -848,9 +957,9 @@ Base *BKE_scene_base_find_by_name(struct Scene *scene, const char *name) return base; } -Base *BKE_scene_base_find(Scene *scene, Object *ob) +BaseLegacy *BKE_scene_base_find(Scene *scene, Object *ob) { - return BLI_findptr(&scene->base, ob, offsetof(Base, object)); + return BLI_findptr(&scene->base, ob, offsetof(BaseLegacy, object)); } /** @@ -861,11 +970,10 @@ Base *BKE_scene_base_find(Scene *scene, Object *ob) void BKE_scene_set_background(Main *bmain, Scene *scene) { Scene *sce; - Base *base; + BaseLegacy *base; Object *ob; Group *group; GroupObject *go; - int flag; /* check for cyclic sets, for reading old files but also for definite security (py?) */ BKE_scene_validate_setscene(bmain, scene); @@ -897,13 +1005,7 @@ void BKE_scene_set_background(Main *bmain, Scene *scene) ob->lay = base->lay; /* group patch... */ - base->flag &= ~(OB_FROMGROUP); - flag = ob->flag & (OB_FROMGROUP); - base->flag |= flag; - - /* not too nice... for recovering objects with lost data */ - //if (ob->pose == NULL) base->flag &= ~OB_POSEMODE; - ob->flag = base->flag; + BKE_scene_base_flag_sync_from_base(base); } /* no full animation update, this to enable render code to work (render code calls own animation updates) */ } @@ -924,7 +1026,7 @@ Scene *BKE_scene_set_name(Main *bmain, const char *name) /* Used by metaballs, return *all* objects (including duplis) existing in the scene (including scene's sets) */ int BKE_scene_base_iter_next(EvaluationContext *eval_ctx, SceneBaseIter *iter, - Scene **scene, int val, Base **base, Object **ob) + Scene **scene, int val, BaseLegacy **base, Object **ob) { bool run_again = true; @@ -1006,7 +1108,7 @@ int BKE_scene_base_iter_next(EvaluationContext *eval_ctx, SceneBaseIter *iter, } /* handle dupli's */ if (iter->dupob) { - (*base)->flag |= OB_FROMDUPLI; + (*base)->flag_legacy |= OB_FROMDUPLI; *ob = iter->dupob->ob; iter->phase = F_DUPLI; @@ -1025,7 +1127,7 @@ int BKE_scene_base_iter_next(EvaluationContext *eval_ctx, SceneBaseIter *iter, } else if (iter->phase == F_DUPLI) { iter->phase = F_SCENE; - (*base)->flag &= ~OB_FROMDUPLI; + (*base)->flag_legacy &= ~OB_FROMDUPLI; if (iter->dupli_refob) { /* Restore last object's real matrix. */ @@ -1052,7 +1154,7 @@ int BKE_scene_base_iter_next(EvaluationContext *eval_ctx, SceneBaseIter *iter, Object *BKE_scene_camera_find(Scene *sc) { - Base *base; + BaseLegacy *base; for (base = sc->base.first; base; base = base->next) if (base->object->type == OB_CAMERA) @@ -1154,47 +1256,54 @@ char *BKE_scene_find_last_marker_name(Scene *scene, int frame) return best_marker ? best_marker->name : NULL; } +void BKE_scene_remove_rigidbody_object(Scene *scene, Object *ob) +{ + /* remove rigid body constraint from world before removing object */ + if (ob->rigidbody_constraint) + BKE_rigidbody_remove_constraint(scene, ob); + /* remove rigid body object from world before removing object */ + if (ob->rigidbody_object) + BKE_rigidbody_remove_object(scene, ob); +} -Base *BKE_scene_base_add(Scene *sce, Object *ob) +BaseLegacy *BKE_scene_base_add(Scene *sce, Object *ob) { - Base *b = MEM_callocN(sizeof(*b), __func__); + BaseLegacy *b = MEM_callocN(sizeof(*b), __func__); BLI_addhead(&sce->base, b); b->object = ob; - b->flag = ob->flag; + b->flag_legacy = ob->flag; b->lay = ob->lay; return b; } -void BKE_scene_base_unlink(Scene *sce, Base *base) +void BKE_scene_base_unlink(Scene *sce, BaseLegacy *base) { - /* remove rigid body constraint from world before removing object */ - if (base->object->rigidbody_constraint) - BKE_rigidbody_remove_constraint(sce, base->object); - /* remove rigid body object from world before removing object */ - if (base->object->rigidbody_object) - BKE_rigidbody_remove_object(sce, base->object); - + BKE_scene_remove_rigidbody_object(sce, base->object); + BLI_remlink(&sce->base, base); if (sce->basact == base) sce->basact = NULL; } +/* deprecated, use BKE_scene_layer_base_deselect_all */ void BKE_scene_base_deselect_all(Scene *sce) { - Base *b; + BaseLegacy *b; for (b = sce->base.first; b; b = b->next) { - b->flag &= ~SELECT; - b->object->flag = b->flag; + b->flag_legacy &= ~SELECT; + int flag = b->object->flag & (OB_FROMGROUP); + b->object->flag = b->flag_legacy; + b->object->flag |= flag; } } -void BKE_scene_base_select(Scene *sce, Base *selbase) +void BKE_scene_base_select(Scene *sce, BaseLegacy *selbase) { - selbase->flag |= SELECT; - selbase->object->flag = selbase->flag; + selbase->flag_legacy |= SELECT; + selbase->object->flag = selbase->flag_legacy; sce->basact = selbase; } @@ -1248,109 +1357,6 @@ void BKE_scene_frame_set(struct Scene *scene, double cfra) scene->r.cfra = (int)intpart; } -#ifdef WITH_LEGACY_DEPSGRAPH -/* drivers support/hacks - * - this method is called from scene_update_tagged_recursive(), so gets included in viewport + render - * - these are always run since the depsgraph can't handle non-object data - * - these happen after objects are all done so that we can read in their final transform values, - * though this means that objects can't refer to scene info for guidance... - */ -static void scene_update_drivers(Main *UNUSED(bmain), Scene *scene) -{ - SceneRenderLayer *srl; - float ctime = BKE_scene_frame_get(scene); - - /* scene itself */ - if (scene->adt && scene->adt->drivers.first) { - BKE_animsys_evaluate_animdata(scene, &scene->id, scene->adt, ctime, ADT_RECALC_DRIVERS); - } - - /* world */ - /* TODO: what about world textures? but then those have nodes too... */ - if (scene->world) { - ID *wid = (ID *)scene->world; - AnimData *adt = BKE_animdata_from_id(wid); - - if (adt && adt->drivers.first) - BKE_animsys_evaluate_animdata(scene, wid, adt, ctime, ADT_RECALC_DRIVERS); - } - - /* nodes */ - if (scene->nodetree) { - ID *nid = (ID *)scene->nodetree; - AnimData *adt = BKE_animdata_from_id(nid); - - if (adt && adt->drivers.first) - BKE_animsys_evaluate_animdata(scene, nid, adt, ctime, ADT_RECALC_DRIVERS); - } - - /* world nodes */ - if (scene->world && scene->world->nodetree) { - ID *nid = (ID *)scene->world->nodetree; - AnimData *adt = BKE_animdata_from_id(nid); - - if (adt && adt->drivers.first) - BKE_animsys_evaluate_animdata(scene, nid, adt, ctime, ADT_RECALC_DRIVERS); - } - - /* freestyle */ - for (srl = scene->r.layers.first; srl; srl = srl->next) { - FreestyleConfig *config = &srl->freestyleConfig; - FreestyleLineSet *lineset; - - for (lineset = config->linesets.first; lineset; lineset = lineset->next) { - if (lineset->linestyle) { - ID *lid = &lineset->linestyle->id; - AnimData *adt = BKE_animdata_from_id(lid); - - if (adt && adt->drivers.first) - BKE_animsys_evaluate_animdata(scene, lid, adt, ctime, ADT_RECALC_DRIVERS); - } - } - } -} - -/* deps hack - do extra recalcs at end */ -static void scene_depsgraph_hack(EvaluationContext *eval_ctx, Scene *scene, Scene *scene_parent) -{ - Base *base; - - scene->customdata_mask = scene_parent->customdata_mask; - - /* sets first, we allow per definition current scene to have - * dependencies on sets, but not the other way around. */ - if (scene->set) - scene_depsgraph_hack(eval_ctx, scene->set, scene_parent); - - for (base = scene->base.first; base; base = base->next) { - Object *ob = base->object; - - if (ob->depsflag) { - int recalc = 0; - // printf("depshack %s\n", ob->id.name + 2); - - if (ob->depsflag & OB_DEPS_EXTRA_OB_RECALC) - recalc |= OB_RECALC_OB; - if (ob->depsflag & OB_DEPS_EXTRA_DATA_RECALC) - recalc |= OB_RECALC_DATA; - - ob->recalc |= recalc; - BKE_object_handle_update(eval_ctx, scene_parent, ob); - - if (ob->dup_group && (ob->transflag & OB_DUPLIGROUP)) { - GroupObject *go; - - for (go = ob->dup_group->gobject.first; go; go = go->next) { - if (go->ob) - go->ob->recalc |= recalc; - } - BKE_group_handle_recalc_and_update(eval_ctx, scene_parent, ob, ob->dup_group); - } - } - } -} -#endif /* WITH_LEGACY_DEPSGRAPH */ - /* That's like really a bummer, because currently animation data for armatures * might want to use pose, and pose might be missing on the object. * This happens when changing visible layers, which leads to situations when @@ -1379,350 +1385,6 @@ static void scene_armature_depsgraph_workaround(Main *bmain) } #endif -#ifdef WITH_LEGACY_DEPSGRAPH -static void scene_rebuild_rbw_recursive(Scene *scene, float ctime) -{ - if (scene->set) - scene_rebuild_rbw_recursive(scene->set, ctime); - - if (BKE_scene_check_rigidbody_active(scene)) - BKE_rigidbody_rebuild_world(scene, ctime); -} - -static void scene_do_rb_simulation_recursive(Scene *scene, float ctime) -{ - if (scene->set) - scene_do_rb_simulation_recursive(scene->set, ctime); - - if (BKE_scene_check_rigidbody_active(scene)) - BKE_rigidbody_do_simulation(scene, ctime); -} -#endif - -/* Used to visualize CPU threads activity during threaded object update, - * would pollute STDERR with whole bunch of timing information which then - * could be parsed and nicely visualized. - */ -#ifdef WITH_LEGACY_DEPSGRAPH -# undef DETAILED_ANALYSIS_OUTPUT -#else -/* ALWAYS KEEY DISABLED! */ -# undef DETAILED_ANALYSIS_OUTPUT -#endif - -/* Mballs evaluation uses BKE_scene_base_iter_next which calls - * duplilist for all objects in the scene. This leads to conflict - * accessing and writing same data from multiple threads. - * - * Ideally Mballs shouldn't do such an iteration and use DAG - * queries instead. For the time being we've got new DAG - * let's keep it simple and update mballs in a single thread. - */ -#define MBALL_SINGLETHREAD_HACK - -#ifdef WITH_LEGACY_DEPSGRAPH -typedef struct StatisicsEntry { - struct StatisicsEntry *next, *prev; - Object *object; - double start_time; - double duration; -} StatisicsEntry; - -typedef struct ThreadedObjectUpdateState { - /* TODO(sergey): We might want this to be per-thread object. */ - EvaluationContext *eval_ctx; - Scene *scene; - Scene *scene_parent; - double base_time; - -#ifdef MBALL_SINGLETHREAD_HACK - bool has_mballs; -#endif - - /* Execution statistics */ - bool has_updated_objects; - ListBase *statistics; -} ThreadedObjectUpdateState; - -static void scene_update_object_add_task(void *node, void *user_data); - -static void scene_update_all_bases(EvaluationContext *eval_ctx, Scene *scene, Scene *scene_parent) -{ - Base *base; - - for (base = scene->base.first; base; base = base->next) { - Object *object = base->object; - - BKE_object_handle_update_ex(eval_ctx, scene_parent, object, scene->rigidbody_world, true); - - if (object->dup_group && (object->transflag & OB_DUPLIGROUP)) - BKE_group_handle_recalc_and_update(eval_ctx, scene_parent, object, object->dup_group); - - /* always update layer, so that animating layers works (joshua july 2010) */ - /* XXX commented out, this has depsgraph issues anyway - and this breaks setting scenes - * (on scene-set, the base-lay is copied to ob-lay (ton nov 2012) */ - // base->lay = ob->lay; - } -} - -static void scene_update_object_func(TaskPool * __restrict pool, void *taskdata, int threadid) -{ -/* Disable print for now in favor of summary statistics at the end of update. */ -#define PRINT if (false) printf - - ThreadedObjectUpdateState *state = (ThreadedObjectUpdateState *) BLI_task_pool_userdata(pool); - void *node = taskdata; - Object *object = DAG_get_node_object(node); - EvaluationContext *eval_ctx = state->eval_ctx; - Scene *scene = state->scene; - Scene *scene_parent = state->scene_parent; - -#ifdef MBALL_SINGLETHREAD_HACK - if (object && object->type == OB_MBALL) { - state->has_mballs = true; - } - else -#endif - if (object) { - double start_time = 0.0; - bool add_to_stats = false; - - if (G.debug & G_DEBUG_DEPSGRAPH) { - if (object->recalc & OB_RECALC_ALL) { - printf("Thread %d: update object %s\n", threadid, object->id.name); - } - - start_time = PIL_check_seconds_timer(); - - if (object->recalc & OB_RECALC_ALL) { - state->has_updated_objects = true; - add_to_stats = true; - } - } - - /* We only update object itself here, dupli-group will be updated - * separately from main thread because of we've got no idea about - * dependencies inside the group. - */ - BKE_object_handle_update_ex(eval_ctx, scene_parent, object, scene->rigidbody_world, false); - - /* Calculate statistics. */ - if (add_to_stats) { - StatisicsEntry *entry; - - BLI_assert(threadid < BLI_pool_get_num_threads(pool)); - - entry = MEM_mallocN(sizeof(StatisicsEntry), "update thread statistics"); - entry->object = object; - entry->start_time = start_time; - entry->duration = PIL_check_seconds_timer() - start_time; - - BLI_addtail(&state->statistics[threadid], entry); - } - } - else { - PRINT("Threda %d: update node %s\n", threadid, - DAG_get_node_name(scene, node)); - } - - /* Update will decrease child's valency and schedule child with zero valency. */ - DAG_threaded_update_handle_node_updated(node, scene_update_object_add_task, pool); - -#undef PRINT -} - -static void scene_update_object_add_task(void *node, void *user_data) -{ - TaskPool *task_pool = user_data; - - BLI_task_pool_push(task_pool, scene_update_object_func, node, false, TASK_PRIORITY_LOW); -} - -static void print_threads_statistics(ThreadedObjectUpdateState *state) -{ - int i, tot_thread; - double finish_time; - - if ((G.debug & G_DEBUG_DEPSGRAPH) == 0) { - return; - } - -#ifdef DETAILED_ANALYSIS_OUTPUT - if (state->has_updated_objects) { - tot_thread = BLI_system_thread_count(); - - fprintf(stderr, "objects update base time %f\n", state->base_time); - - for (i = 0; i < tot_thread; i++) { - StatisicsEntry *entry; - for (entry = state->statistics[i].first; - entry; - entry = entry->next) - { - fprintf(stderr, "thread %d object %s start_time %f duration %f\n", - i, entry->object->id.name + 2, - entry->start_time, entry->duration); - } - BLI_freelistN(&state->statistics[i]); - } - } -#else - finish_time = PIL_check_seconds_timer(); - tot_thread = BLI_system_thread_count(); - int total_objects = 0; - - for (i = 0; i < tot_thread; i++) { - int thread_total_objects = 0; - double thread_total_time = 0.0; - StatisicsEntry *entry; - - if (state->has_updated_objects) { - /* Don't pollute output if no objects were updated. */ - for (entry = state->statistics[i].first; - entry; - entry = entry->next) - { - thread_total_objects++; - thread_total_time += entry->duration; - } - - printf("Thread %d: total %d objects in %f sec.\n", - i, - thread_total_objects, - thread_total_time); - - for (entry = state->statistics[i].first; - entry; - entry = entry->next) - { - printf(" %s in %f sec\n", entry->object->id.name + 2, entry->duration); - } - - total_objects += thread_total_objects; - } - - BLI_freelistN(&state->statistics[i]); - } - if (state->has_updated_objects) { - printf("Scene updated %d objects in %f sec\n", - total_objects, - finish_time - state->base_time); - } -#endif -} - -static bool scene_need_update_objects(Main *bmain) -{ - return - /* Object datablocks themselves (for OB_RECALC_OB) */ - DAG_id_type_tagged(bmain, ID_OB) || - - /* Objects data datablocks (for OB_RECALC_DATA) */ - DAG_id_type_tagged(bmain, ID_ME) || /* Mesh */ - DAG_id_type_tagged(bmain, ID_CU) || /* Curve */ - DAG_id_type_tagged(bmain, ID_MB) || /* MetaBall */ - DAG_id_type_tagged(bmain, ID_LA) || /* Lamp */ - DAG_id_type_tagged(bmain, ID_LT) || /* Lattice */ - DAG_id_type_tagged(bmain, ID_CA) || /* Camera */ - DAG_id_type_tagged(bmain, ID_KE) || /* KE */ - DAG_id_type_tagged(bmain, ID_SPK) || /* Speaker */ - DAG_id_type_tagged(bmain, ID_AR); /* Armature */ -} - -static void scene_update_objects(EvaluationContext *eval_ctx, Main *bmain, Scene *scene, Scene *scene_parent) -{ - TaskScheduler *task_scheduler = BLI_task_scheduler_get(); - TaskPool *task_pool; - ThreadedObjectUpdateState state; - bool need_singlethread_pass; - - /* Early check for whether we need to invoke all the task-based - * things (spawn new ppol, traverse dependency graph and so on). - * - * Basically if there's no ID datablocks tagged for update which - * corresponds to object->recalc flags (which are checked in - * BKE_object_handle_update() then we do nothing here. - */ - if (!scene_need_update_objects(bmain)) { - return; - } - - state.eval_ctx = eval_ctx; - state.scene = scene; - state.scene_parent = scene_parent; - - /* Those are only needed when blender is run with --debug argument. */ - if (G.debug & G_DEBUG_DEPSGRAPH) { - const int tot_thread = BLI_task_scheduler_num_threads(task_scheduler); - state.statistics = MEM_callocN(tot_thread * sizeof(*state.statistics), - "scene update objects stats"); - state.has_updated_objects = false; - state.base_time = PIL_check_seconds_timer(); - } - -#ifdef MBALL_SINGLETHREAD_HACK - state.has_mballs = false; -#endif - - task_pool = BLI_task_pool_create(task_scheduler, &state); - if (G.debug & G_DEBUG_DEPSGRAPH_NO_THREADS) { - BLI_pool_set_num_threads(task_pool, 1); - } - - DAG_threaded_update_begin(scene, scene_update_object_add_task, task_pool); - BLI_task_pool_work_and_wait(task_pool); - BLI_task_pool_free(task_pool); - - if (G.debug & G_DEBUG_DEPSGRAPH) { - print_threads_statistics(&state); - MEM_freeN(state.statistics); - } - - /* We do single thread pass to update all the objects which are in cyclic dependency. - * Such objects can not be handled by a generic DAG traverse and it's really tricky - * to detect whether cycle could be solved or not. - * - * In this situation we simply update all remaining objects in a single thread and - * it'll happen in the same exact order as it was in single-threaded DAG. - * - * We couldn't use threaded update for objects which are in cycle because they might - * access data of each other which is being re-evaluated. - * - * Also, as was explained above, for now we also update all the mballs in single thread. - * - * - sergey - - */ - need_singlethread_pass = DAG_is_acyclic(scene) == false; -#ifdef MBALL_SINGLETHREAD_HACK - need_singlethread_pass |= state.has_mballs; -#endif - - if (need_singlethread_pass) { - scene_update_all_bases(eval_ctx, scene, scene_parent); - } -} - -static void scene_update_tagged_recursive(EvaluationContext *eval_ctx, Main *bmain, Scene *scene, Scene *scene_parent) -{ - scene->customdata_mask = scene_parent->customdata_mask; - - /* sets first, we allow per definition current scene to have - * dependencies on sets, but not the other way around. */ - if (scene->set) - scene_update_tagged_recursive(eval_ctx, bmain, scene->set, scene_parent); - - /* scene objects */ - scene_update_objects(eval_ctx, bmain, scene, scene_parent); - - /* scene drivers... */ - scene_update_drivers(bmain, scene); - - /* update masking curves */ - BKE_mask_update_scene(bmain, scene); - -} -#endif /* WITH_LEGACY_DEPSGRAPH */ - static bool check_rendered_viewport_visible(Main *bmain) { wmWindowManager *wm = bmain->wm.first; @@ -1773,9 +1435,6 @@ static void prepare_mesh_for_viewport_render(Main *bmain, Scene *scene) void BKE_scene_update_tagged(EvaluationContext *eval_ctx, Main *bmain, Scene *scene) { Scene *sce_iter; -#ifdef WITH_LEGACY_DEPSGRAPH - bool use_new_eval = !DEG_depsgraph_use_legacy(); -#endif /* keep this first */ BLI_callback_exec(bmain, &scene->id, BLI_CB_EVT_SCENE_UPDATE_PRE); @@ -1785,12 +1444,7 @@ void BKE_scene_update_tagged(EvaluationContext *eval_ctx, Main *bmain, Scene *sc DAG_scene_relations_update(bmain, sce_iter); /* Uncomment this to check if graph was properly tagged for update. */ #if 0 -#ifdef WITH_LEGACY_DEPSGRAPH - if (use_new_eval) -#endif - { - DAG_scene_relations_validate(bmain, sce_iter); - } + DAG_scene_relations_validate(bmain, sce_iter); #endif } @@ -1813,17 +1467,9 @@ void BKE_scene_update_tagged(EvaluationContext *eval_ctx, Main *bmain, Scene *sc * * in the future this should handle updates for all datablocks, not * only objects and scenes. - brecht */ -#ifdef WITH_LEGACY_DEPSGRAPH - if (!use_new_eval) { - scene_update_tagged_recursive(eval_ctx, bmain, scene, scene); - } - else -#endif - { - DEG_evaluate_on_refresh(eval_ctx, scene->depsgraph, scene); - /* TODO(sergey): This is to beocme a node in new depsgraph. */ - BKE_mask_update_scene(bmain, scene); - } + DEG_evaluate_on_refresh(eval_ctx, scene->depsgraph, scene); + /* TODO(sergey): This is to beocme a node in new depsgraph. */ + BKE_mask_update_scene(bmain, scene); /* update sound system animation (TODO, move to depsgraph) */ BKE_sound_update_scene(bmain, scene); @@ -1837,40 +1483,6 @@ void BKE_scene_update_tagged(EvaluationContext *eval_ctx, Main *bmain, Scene *sc BKE_animsys_evaluate_animdata(scene, &scene->id, adt, ctime, 0); } - /* Extra call here to recalc material animation. - * - * Need to do this so changing material settings from the graph/dopesheet - * will update stuff in the viewport. - */ -#ifdef WITH_LEGACY_DEPSGRAPH - if (!use_new_eval && DAG_id_type_tagged(bmain, ID_MA)) { - Material *material; - float ctime = BKE_scene_frame_get(scene); - - for (material = bmain->mat.first; - material; - material = material->id.next) - { - AnimData *adt = BKE_animdata_from_id(&material->id); - if (adt && (adt->recalc & ADT_RECALC_ANIM)) - BKE_animsys_evaluate_animdata(scene, &material->id, adt, ctime, 0); - } - } - - /* Also do the same for node trees. */ - if (!use_new_eval && DAG_id_type_tagged(bmain, ID_NT)) { - float ctime = BKE_scene_frame_get(scene); - - FOREACH_NODETREE(bmain, ntree, id) - { - AnimData *adt = BKE_animdata_from_id(&ntree->id); - if (adt && (adt->recalc & ADT_RECALC_ANIM)) - BKE_animsys_evaluate_animdata(scene, &ntree->id, adt, ctime, 0); - } - FOREACH_NODETREE_END - } -#endif - /* notify editors and python about recalc */ BLI_callback_exec(bmain, &scene->id, BLI_CB_EVT_SCENE_UPDATE_POST); @@ -1887,19 +1499,10 @@ void BKE_scene_update_for_newframe(EvaluationContext *eval_ctx, Main *bmain, Sce BKE_scene_update_for_newframe_ex(eval_ctx, bmain, sce, lay, false); } -void BKE_scene_update_for_newframe_ex(EvaluationContext *eval_ctx, Main *bmain, Scene *sce, unsigned int lay, bool do_invisible_flush) +void BKE_scene_update_for_newframe_ex(EvaluationContext *eval_ctx, Main *bmain, Scene *sce, unsigned int lay, bool UNUSED(do_invisible_flush)) { float ctime = BKE_scene_frame_get(sce); Scene *sce_iter; -#ifdef DETAILED_ANALYSIS_OUTPUT - double start_time = PIL_check_seconds_timer(); -#endif -#ifdef WITH_LEGACY_DEPSGRAPH - bool use_new_eval = !DEG_depsgraph_use_legacy(); -#else - /* TODO(sergey): Pass to evaluation routines instead of storing layer in the graph? */ - (void) do_invisible_flush; -#endif DAG_editors_update_pre(bmain, sce, true); @@ -1910,38 +1513,15 @@ void BKE_scene_update_for_newframe_ex(EvaluationContext *eval_ctx, Main *bmain, /* update animated image textures for particles, modifiers, gpu, etc, * call this at the start so modifiers with textures don't lag 1 frame */ BKE_image_update_frame(bmain, sce->r.cfra); - -#ifdef WITH_LEGACY_DEPSGRAPH - /* rebuild rigid body worlds before doing the actual frame update - * this needs to be done on start frame but animation playback usually starts one frame later - * we need to do it here to avoid rebuilding the world on every simulation change, which can be very expensive - */ - if (!use_new_eval) { - scene_rebuild_rbw_recursive(sce, ctime); - } -#endif - + BKE_sound_set_cfra(sce->r.cfra); - + /* clear animation overrides */ /* XXX TODO... */ for (sce_iter = sce; sce_iter; sce_iter = sce_iter->set) DAG_scene_relations_update(bmain, sce_iter); -#ifdef WITH_LEGACY_DEPSGRAPH - if (!use_new_eval) { - /* flush recalc flags to dependencies, if we were only changing a frame - * this would not be necessary, but if a user or a script has modified - * some datablock before BKE_scene_update_tagged was called, we need the flush */ - DAG_ids_flush_tagged(bmain); - - /* Following 2 functions are recursive - * so don't call within 'scene_update_tagged_recursive' */ - DAG_scene_update_flags(bmain, sce, lay, true, do_invisible_flush); // only stuff that moves or needs display still - } -#endif - BKE_mask_evaluate_all_masks(bmain, ctime, true); /* Update animated cache files for modifiers. */ @@ -1951,54 +1531,18 @@ void BKE_scene_update_for_newframe_ex(EvaluationContext *eval_ctx, Main *bmain, scene_armature_depsgraph_workaround(bmain); #endif - /* All 'standard' (i.e. without any dependencies) animation is handled here, - * with an 'local' to 'macro' order of evaluation. This should ensure that - * settings stored nestled within a hierarchy (i.e. settings in a Texture block - * can be overridden by settings from Scene, which owns the Texture through a hierarchy - * such as Scene->World->MTex/Texture) can still get correctly overridden. - */ -#ifdef WITH_LEGACY_DEPSGRAPH - if (!use_new_eval) { - BKE_animsys_evaluate_all_animation(bmain, sce, ctime); - /*...done with recursive funcs */ - } -#endif - /* clear "LIB_TAG_DOIT" flag from all materials, to prevent infinite recursion problems later * when trying to find materials with drivers that need evaluating [#32017] */ BKE_main_id_tag_idcode(bmain, ID_MA, LIB_TAG_DOIT, false); BKE_main_id_tag_idcode(bmain, ID_LA, LIB_TAG_DOIT, false); - /* run rigidbody sim */ - /* NOTE: current position is so that rigidbody sim affects other objects, might change in the future */ -#ifdef WITH_LEGACY_DEPSGRAPH - if (!use_new_eval) { - scene_do_rb_simulation_recursive(sce, ctime); - } -#endif - /* BKE_object_handle_update() on all objects, groups and sets */ -#ifdef WITH_LEGACY_DEPSGRAPH - if (use_new_eval) { - DEG_evaluate_on_framechange(eval_ctx, bmain, sce->depsgraph, ctime, lay); - } - else { - scene_update_tagged_recursive(eval_ctx, bmain, sce, sce); - } -#else DEG_evaluate_on_framechange(eval_ctx, bmain, sce->depsgraph, ctime, lay); -#endif /* update sound system animation (TODO, move to depsgraph) */ BKE_sound_update_scene(bmain, sce); -#ifdef WITH_LEGACY_DEPSGRAPH - if (!use_new_eval) { - scene_depsgraph_hack(eval_ctx, sce, sce); - } -#endif - /* notify editors and python about recalc */ BLI_callback_exec(bmain, &sce->id, BLI_CB_EVT_SCENE_UPDATE_POST); BLI_callback_exec(bmain, &sce->id, BLI_CB_EVT_FRAME_CHANGE_POST); @@ -2008,10 +1552,6 @@ void BKE_scene_update_for_newframe_ex(EvaluationContext *eval_ctx, Main *bmain, /* clear recalc flags */ DAG_ids_clear_recalc(bmain); - -#ifdef DETAILED_ANALYSIS_OUTPUT - fprintf(stderr, "frame update start_time %f duration %f\n", start_time, PIL_check_seconds_timer() - start_time); -#endif } /* return default layer, also used to patch old files */ @@ -2061,15 +1601,7 @@ bool BKE_scene_remove_render_layer(Main *bmain, Scene *scene, SceneRenderLayer * for (sce = bmain->scene.first; sce; sce = sce->id.next) { if (sce->nodetree) { - bNode *node; - for (node = sce->nodetree->nodes.first; node; node = node->next) { - if (node->type == CMP_NODE_R_LAYERS && (Scene *)node->id == scene) { - if (node->custom1 == act) - node->custom1 = 0; - else if (node->custom1 > act) - node->custom1--; - } - } + BKE_nodetree_remove_layer_n(sce->nodetree, scene, act); } } @@ -2156,21 +1688,37 @@ float get_render_aosss_error(const RenderData *r, float error) return error; } -/* helper function for the SETLOOPER macro */ +/** + * Helper function for the SETLOOPER macro + * + * It iterates over the bases of the active layer and then the bases + * of the active layer of the background (set) scenes recursively. + */ Base *_setlooper_base_step(Scene **sce_iter, Base *base) { if (base && base->next) { /* common case, step to the next */ return base->next; } - else if (base == NULL && (*sce_iter)->base.first) { + else if (base == NULL) { /* first time looping, return the scenes first base */ - return (Base *)(*sce_iter)->base.first; + + /* for the first loop we should get the layer from context */ + SceneLayer *sl = BKE_scene_layer_context_active((*sce_iter)); + + if (sl->object_bases.first) { + return (Base *)sl->object_bases.first; + } + /* no base on this scene layer */ + goto next_set; } else { +next_set: /* reached the end, get the next base in the set */ while ((*sce_iter = (*sce_iter)->set)) { - base = (Base *)(*sce_iter)->base.first; + SceneLayer *sl = BKE_scene_layer_render_active((*sce_iter)); + base = (Base *)sl->object_bases.first; + if (base) { return base; } @@ -2215,23 +1763,55 @@ bool BKE_scene_uses_blender_game(const Scene *scene) return STREQ(scene->r.engine, RE_engine_id_BLENDER_GAME); } -void BKE_scene_base_flag_to_objects(struct Scene *scene) +void BKE_scene_base_flag_to_objects(SceneLayer *sl) { - Base *base = scene->base.first; + Base *base = sl->object_bases.first; while (base) { - base->object->flag = base->flag; + BKE_scene_object_base_flag_sync_from_base(base); base = base->next; } } -void BKE_scene_base_flag_from_objects(struct Scene *scene) +void BKE_scene_base_flag_sync_from_base(BaseLegacy *base) { - Base *base = scene->base.first; + BKE_scene_object_base_flag_sync_from_base(base); +} - while (base) { - base->flag = base->object->flag; - base = base->next; +void BKE_scene_base_flag_sync_from_object(BaseLegacy *base) +{ + BKE_scene_object_base_flag_sync_from_object(base); +} + +void BKE_scene_object_base_flag_sync_from_base(Base *base) +{ + Object *ob = base->object; + + /* keep the object only flags untouched */ + int flag = ob->flag & OB_FROMGROUP; + + ob->flag = base->flag; + ob->flag |= flag; + + if ((base->flag & BASE_SELECTED) != 0) { + ob->flag |= SELECT; + } + else { + ob->flag &= ~SELECT; + } +} + +void BKE_scene_object_base_flag_sync_from_object(Base *base) +{ + Object *ob = base->object; + base->flag = ob->flag; + + if ((ob->flag & SELECT) != 0) { + base->flag |= BASE_SELECTED; + BLI_assert((base->flag & BASE_SELECTABLED) != 0); + } + else { + base->flag &= ~BASE_SELECTED; } } diff --git a/source/blender/blenkernel/intern/screen.c b/source/blender/blenkernel/intern/screen.c index 857bd5447c8..c5d00d63b6d 100644 --- a/source/blender/blenkernel/intern/screen.c +++ b/source/blender/blenkernel/intern/screen.c @@ -50,6 +50,7 @@ #include "BLI_utildefines.h" #include "BLI_rect.h" +#include "BKE_icons.h" #include "BKE_idprop.h" #include "BKE_screen.h" @@ -180,6 +181,7 @@ ARegion *BKE_area_region_copy(SpaceType *st, ARegion *ar) BLI_listbase_clear(&newar->panels_category_active); BLI_listbase_clear(&newar->ui_lists); newar->swinid = 0; + newar->manipulator_map = NULL; newar->regiontimer = NULL; /* use optional regiondata callback */ @@ -288,6 +290,17 @@ void BKE_spacedata_id_unref(struct ScrArea *sa, struct SpaceLink *sl, struct ID } } + +/** + * Avoid bad-level calls to #WM_manipulatormap_delete. + */ +static void (*region_free_manipulatormap_callback)(struct wmManipulatorMap *) = NULL; + +void BKE_region_callback_free_manipulatormap_set(void (*callback)(struct wmManipulatorMap *)) +{ + region_free_manipulatormap_callback = callback; +} + /* not region itself */ void BKE_area_region_free(SpaceType *st, ARegion *ar) { @@ -337,6 +350,8 @@ void BKE_area_region_free(SpaceType *st, ARegion *ar) MEM_freeN(uilst->properties); } } + + region_free_manipulatormap_callback(ar->manipulator_map); BLI_freelistN(&ar->ui_lists); BLI_freelistN(&ar->ui_previews); BLI_freelistN(&ar->panels_category); @@ -380,6 +395,8 @@ void BKE_screen_free(bScreen *sc) BLI_freelistN(&sc->vertbase); BLI_freelistN(&sc->edgebase); BLI_freelistN(&sc->areabase); + + BKE_previewimg_free(&sc->preview); } /* for depsgraph */ diff --git a/source/blender/blenkernel/intern/smoke.c b/source/blender/blenkernel/intern/smoke.c index d0ef5cfc092..f1ce69d3945 100644 --- a/source/blender/blenkernel/intern/smoke.c +++ b/source/blender/blenkernel/intern/smoke.c @@ -698,7 +698,7 @@ static float calc_voxel_transp(float *result, float *input, int res[3], int *pix static int get_lamp(Scene *scene, float *light) { - Base *base_tmp = NULL; + BaseLegacy *base_tmp = NULL; int found_lamp = 0; // try to find a lamp, preferably local diff --git a/source/blender/blenkernel/intern/softbody.c b/source/blender/blenkernel/intern/softbody.c index 03cf33083da..e7df1d810c9 100644 --- a/source/blender/blenkernel/intern/softbody.c +++ b/source/blender/blenkernel/intern/softbody.c @@ -530,7 +530,7 @@ static void ccd_build_deflector_hash(Scene *scene, Group *group, Object *vertexo } } else { - for (Base *base = scene->base.first; base; base = base->next) { + for (BaseLegacy *base = scene->base.first; base; base = base->next) { /*Only proceed for mesh object in same layer */ if (base->object->type == OB_MESH && (base->lay & vertexowner->lay)) { ob= base->object; @@ -576,7 +576,7 @@ static void ccd_update_deflector_hash(Scene *scene, Group *group, Object *vertex } } else { - for (Base *base = scene->base.first; base; base = base->next) { + for (BaseLegacy *base = scene->base.first; base; base = base->next) { /*Only proceed for mesh object in same layer */ if (base->object->type == OB_MESH && (base->lay & vertexowner->lay)) { ob= base->object; @@ -986,7 +986,7 @@ static bool are_there_deflectors(Scene *scene, Group *group, unsigned int layer) } } else { - for (Base *base = scene->base.first; base; base= base->next) { + for (BaseLegacy *base = scene->base.first; base; base= base->next) { if ( (base->lay & layer) && base->object->pd) { if (base->object->pd->deflect) return 1; @@ -3650,7 +3650,6 @@ void sbObjectStep(Scene *scene, Object *ob, float cfra, float (*vertexCos)[3], i float dtime, timescale; int framedelta, framenr, startframe, endframe; int cache_result; - cache= sb->pointcache; framenr= (int)cfra; @@ -3719,7 +3718,7 @@ void sbObjectStep(Scene *scene, Object *ob, float cfra, float (*vertexCos)[3], i } /* try to read from cache */ - bool can_simulate = (framenr == sb->last_frame+1) && !(cache->flag & PTCACHE_BAKED); + bool can_simulate = (framenr == sb->last_frame + 1) && !(cache->flag & PTCACHE_BAKED); cache_result = BKE_ptcache_read(&pid, (float)framenr+scene->r.subframe, can_simulate); diff --git a/source/blender/blenlib/BLI_ghash.h b/source/blender/blenlib/BLI_ghash.h index 7e3a009ede8..068c188e336 100644 --- a/source/blender/blenlib/BLI_ghash.h +++ b/source/blender/blenlib/BLI_ghash.h @@ -32,6 +32,7 @@ * \ingroup bli */ +#include "BLI_blenlib.h" #include "BLI_sys_types.h" /* for bool */ #include "BLI_compiler_attrs.h" diff --git a/source/blender/blenlib/BLI_iterator.h b/source/blender/blenlib/BLI_iterator.h new file mode 100644 index 00000000000..26d2728d432 --- /dev/null +++ b/source/blender/blenlib/BLI_iterator.h @@ -0,0 +1,55 @@ +/* + * ***** 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. + * + * Contributor(s): Dalai Felinto + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#ifndef __BLI_ITERATOR_H__ +#define __BLI_ITERATOR_H__ + +/** \file BLI_iterator.h + * \ingroup bli + */ + +typedef struct Iterator { + void *current; /* current pointer we iterate over */ + void *data; /* stored data required for this iterator */ + bool valid; +} Iterator; + +typedef void (*IteratorCb)(Iterator *iter); +typedef void (*IteratorBeginCb)(Iterator *iter, void *data_in); + +#define ITER_BEGIN(callback_begin, callback_next, callback_end, _data_in, _type, _instance) \ +{ \ + _type _instance; \ + IteratorCb callback_end_func = callback_end; \ + Iterator iter_macro; \ + for (callback_begin(&iter_macro, (_data_in)); \ + iter_macro.valid; \ + callback_next(&iter_macro)) \ + { \ + _instance = (_type ) iter_macro.current; + +#define ITER_END \ + } \ + callback_end_func(&iter_macro); \ +} + +#endif /* __BLI_ITERATOR_H__ */ diff --git a/source/blender/blenlib/BLI_math_color.h b/source/blender/blenlib/BLI_math_color.h index 5e6b1256d30..34fc52c12c0 100644 --- a/source/blender/blenlib/BLI_math_color.h +++ b/source/blender/blenlib/BLI_math_color.h @@ -141,7 +141,11 @@ MINLINE void float_to_byte_dither_v3(unsigned char b[3], const float f[3], float #define rgba_char_args_set_fl(col, r, g, b, a) \ rgba_char_args_set(col, (r) * 255, (g) * 255, (b) * 255, (a) * 255) +#define rgba_float_args_set_ch(col, r, g, b, a) \ + rgba_float_args_set(col, (r) / 255.0f, (g) / 255.0f, (b) / 255.0f, (a) / 255.0f) + MINLINE void rgba_char_args_set(char col[4], const char r, const char g, const char b, const char a); +MINLINE void rgba_float_args_set(float col[4], const float r, const float g, const float b, const float a); MINLINE void rgba_char_args_test_set(char col[4], const char r, const char g, const char b, const char a); MINLINE void cpack_cpy_3ub(unsigned char r_col[3], const unsigned int pack); diff --git a/source/blender/blenlib/BLI_math_matrix.h b/source/blender/blenlib/BLI_math_matrix.h index d0dfad2a02f..029f6872b04 100644 --- a/source/blender/blenlib/BLI_math_matrix.h +++ b/source/blender/blenlib/BLI_math_matrix.h @@ -46,31 +46,43 @@ void unit_m2(float R[2][2]); void unit_m3(float R[3][3]); void unit_m4(float R[4][4]); -void copy_m2_m2(float R[2][2], float A[2][2]); -void copy_m3_m3(float R[3][3], float A[3][3]); -void copy_m4_m4(float R[4][4], float A[4][4]); -void copy_m3_m4(float R[3][3], float A[4][4]); -void copy_m4_m3(float R[4][4], float A[3][3]); +void copy_m2_m2(float R[2][2], const float A[2][2]); +void copy_m3_m3(float R[3][3], const float A[3][3]); +void copy_m4_m4(float R[4][4], const float A[4][4]); +void copy_m3_m4(float R[3][3], const float A[4][4]); +void copy_m4_m3(float R[4][4], const float A[3][3]); /* double->float */ -void copy_m3_m3d(float R[3][3], double A[3][3]); +void copy_m3_m3d(float R[3][3], const double A[3][3]); void swap_m3m3(float A[3][3], float B[3][3]); void swap_m4m4(float A[4][4], float B[4][4]); /******************************** Arithmetic *********************************/ -void add_m3_m3m3(float R[3][3], float A[3][3], float B[3][3]); -void add_m4_m4m4(float R[4][4], float A[4][4], float B[4][4]); +void add_m3_m3m3(float R[3][3], const float A[3][3], const float B[3][3]); +void add_m4_m4m4(float R[4][4], const float A[4][4], const float B[4][4]); -void sub_m3_m3m3(float R[3][3], float A[3][3], float B[3][3]); -void sub_m4_m4m4(float R[4][4], float A[4][4], float B[4][4]); +void sub_m3_m3m3(float R[3][3], const float A[3][3], const float B[3][3]); +void sub_m4_m4m4(float R[4][4], const float A[4][4], const float B[4][4]); -void mul_m3_m3m3(float R[3][3], float A[3][3], float B[3][3]); -void mul_m4_m3m4(float R[4][4], float A[3][3], float B[4][4]); -void mul_m4_m4m3(float R[4][4], float A[4][4], float B[3][3]); -void mul_m4_m4m4(float R[4][4], float A[4][4], float B[4][4]); -void mul_m3_m3m4(float R[3][3], float A[4][4], float B[3][3]); +void mul_m3_m3m3(float R[3][3], const float A[3][3], const float B[3][3]); +void mul_m4_m3m4(float R[4][4], const float A[3][3], const float B[4][4]); +void mul_m4_m4m3(float R[4][4], const float A[4][4], const float B[3][3]); +void mul_m4_m4m4(float R[4][4], const float A[4][4], const float B[4][4]); +void mul_m3_m3m4(float R[3][3], const float A[4][4], const float B[3][3]); + +/* special matrix multiplies + * uniq: R <-- AB, R is neither A nor B + * pre: R <-- AR + * post: R <-- RB + */ +void mul_m3_m3m3_uniq(float R[3][3], const float A[3][3], const float B[3][3]); +void mul_m3_m3_pre(float R[3][3], const float A[3][3]); +void mul_m3_m3_post(float R[3][3], const float B[3][3]); +void mul_m4_m4m4_uniq(float R[4][4], const float A[4][4], const float B[4][4]); +void mul_m4_m4_pre(float R[4][4], const float A[4][4]); +void mul_m4_m4_post(float R[4][4], const float B[4][4]); /* mul_m3_series */ void _va_mul_m3_series_3(float R[3][3], float M1[3][3], float M2[3][3]) ATTR_NONNULL(); @@ -100,27 +112,28 @@ void _va_mul_m4_series_9(float R[4][4], float M1[4][4], float M2[4][4], float M3 #define mul_m3_series(...) VA_NARGS_CALL_OVERLOAD(_va_mul_m3_series_, __VA_ARGS__) #define mul_m4_series(...) VA_NARGS_CALL_OVERLOAD(_va_mul_m4_series_, __VA_ARGS__) -void mul_m4_v3(float M[4][4], float r[3]); -void mul_v3_m4v3(float r[3], float M[4][4], const float v[3]); -void mul_v2_m4v3(float r[2], float M[4][4], const float v[3]); -void mul_v2_m2v2(float r[2], float M[2][2], const float v[2]); -void mul_m2v2(float M[2][2], float v[2]); -void mul_mat3_m4_v3(float M[4][4], float r[3]); -void mul_v3_mat3_m4v3(float r[3], float M[4][4], const float v[3]); -void mul_m4_v4(float M[4][4], float r[4]); -void mul_v4_m4v4(float r[4], float M[4][4], const float v[4]); -void mul_project_m4_v3(float M[4][4], float vec[3]); -void mul_v3_project_m4_v3(float r[3], float mat[4][4], const float vec[3]); -void mul_v2_project_m4_v3(float r[2], float M[4][4], const float vec[3]); - -void mul_m3_v2(float m[3][3], float r[2]); -void mul_v2_m3v2(float r[2], float m[3][3], float v[2]); -void mul_m3_v3(float M[3][3], float r[3]); -void mul_v3_m3v3(float r[3], float M[3][3], const float a[3]); -void mul_v2_m3v3(float r[2], float M[3][3], const float a[3]); -void mul_transposed_m3_v3(float M[3][3], float r[3]); -void mul_transposed_mat3_m4_v3(float M[4][4], float r[3]); -void mul_m3_v3_double(float M[3][3], double r[3]); +void mul_m4_v3(const float M[4][4], float r[3]); +void mul_v3_m4v3(float r[3], const float M[4][4], const float v[3]); +void mul_v2_m4v3(float r[2], const float M[4][4], const float v[3]); +void mul_v2_m2v2(float r[2], const float M[2][2], const float v[2]); +void mul_m2v2(const float M[2][2], float v[2]); +void mul_mat3_m4_v3(const float M[4][4], float r[3]); +void mul_v3_mat3_m4v3(float r[3], const float M[4][4], const float v[3]); +void mul_m4_v4(const float M[4][4], float r[4]); +void mul_v4_m4v4(float r[4], const float M[4][4], const float v[4]); +void mul_v4_m4v3(float r[4], const float M[4][4], const float v[3]); /* v has implicit w = 1.0f */ +void mul_project_m4_v3(const float M[4][4], float vec[3]); +void mul_v3_project_m4_v3(float r[3], const float mat[4][4], const float vec[3]); +void mul_v2_project_m4_v3(float r[2], const float M[4][4], const float vec[3]); + +void mul_m3_v2(const float m[3][3], float r[2]); +void mul_v2_m3v2(float r[2], const float m[3][3], const float v[2]); +void mul_m3_v3(const float M[3][3], float r[3]); +void mul_v3_m3v3(float r[3], const float M[3][3], const float a[3]); +void mul_v2_m3v3(float r[2], const float M[3][3], const float a[3]); +void mul_transposed_m3_v3(const float M[3][3], float r[3]); +void mul_transposed_mat3_m4_v3(const float M[4][4], float r[3]); +void mul_m3_v3_double(const float M[3][3], double r[3]); void mul_m3_fl(float R[3][3], float f); void mul_m4_fl(float R[4][4], float f); @@ -131,102 +144,102 @@ void negate_mat3_m4(float R[4][4]); void negate_m4(float R[4][4]); bool invert_m3_ex(float m[3][3], const float epsilon); -bool invert_m3_m3_ex(float m1[3][3], float m2[3][3], const float epsilon); +bool invert_m3_m3_ex(float m1[3][3], const float m2[3][3], const float epsilon); bool invert_m3(float R[3][3]); -bool invert_m3_m3(float R[3][3], float A[3][3]); +bool invert_m3_m3(float R[3][3], const float A[3][3]); bool invert_m4(float R[4][4]); -bool invert_m4_m4(float R[4][4], float A[4][4]); +bool invert_m4_m4(float R[4][4], const float A[4][4]); /* double arithmetic (mixed float/double) */ -void mul_m4_v4d(float M[4][4], double r[4]); -void mul_v4d_m4v4d(double r[4], float M[4][4], double v[4]); +void mul_m4_v4d(const float M[4][4], double r[4]); +void mul_v4d_m4v4d(double r[4], const float M[4][4], const double v[4]); /* double matrix functions (no mixing types) */ -void mul_v3_m3v3_db(double r[3], double M[3][3], const double a[3]); -void mul_m3_v3_db(double M[3][3], double r[3]); +void mul_v3_m3v3_db(double r[3], const double M[3][3], const double a[3]); +void mul_m3_v3_db(const double M[3][3], double r[3]); /****************************** Linear Algebra *******************************/ void transpose_m3(float R[3][3]); -void transpose_m3_m3(float R[3][3], float A[3][3]); -void transpose_m3_m4(float R[3][3], float A[4][4]); +void transpose_m3_m3(float R[3][3], const float A[3][3]); +void transpose_m3_m4(float R[3][3], const float A[4][4]); void transpose_m4(float R[4][4]); -void transpose_m4_m4(float R[4][4], float A[4][4]); +void transpose_m4_m4(float R[4][4], const float A[4][4]); -int compare_m4m4(float mat1[4][4], float mat2[4][4], float limit); +int compare_m4m4(const float mat1[4][4], const float mat2[4][4], float limit); void normalize_m3_ex(float R[3][3], float r_scale[3]) ATTR_NONNULL(); void normalize_m3(float R[3][3]) ATTR_NONNULL(); -void normalize_m3_m3_ex(float R[3][3], float A[3][3], float r_scale[3]) ATTR_NONNULL(); -void normalize_m3_m3(float R[3][3], float A[3][3]) ATTR_NONNULL(); +void normalize_m3_m3_ex(float R[3][3], const float A[3][3], float r_scale[3]) ATTR_NONNULL(); +void normalize_m3_m3(float R[3][3], const float A[3][3]) ATTR_NONNULL(); void normalize_m4_ex(float R[4][4], float r_scale[3]) ATTR_NONNULL(); void normalize_m4(float R[4][4]) ATTR_NONNULL(); -void normalize_m4_m4_ex(float R[4][4], float A[4][4], float r_scale[3]) ATTR_NONNULL(); -void normalize_m4_m4(float R[4][4], float A[4][4]) ATTR_NONNULL(); +void normalize_m4_m4_ex(float R[4][4], const float A[4][4], float r_scale[3]) ATTR_NONNULL(); +void normalize_m4_m4(float R[4][4],const float A[4][4]) ATTR_NONNULL(); void orthogonalize_m3(float R[3][3], int axis); void orthogonalize_m4(float R[4][4], int axis); -bool is_orthogonal_m3(float mat[3][3]); -bool is_orthogonal_m4(float mat[4][4]); -bool is_orthonormal_m3(float mat[3][3]); -bool is_orthonormal_m4(float mat[4][4]); +bool is_orthogonal_m3(const float mat[3][3]); +bool is_orthogonal_m4(const float mat[4][4]); +bool is_orthonormal_m3(const float mat[3][3]); +bool is_orthonormal_m4(const float mat[4][4]); -bool is_uniform_scaled_m3(float mat[3][3]); -bool is_uniform_scaled_m4(float m[4][4]); +bool is_uniform_scaled_m3(const float mat[3][3]); +bool is_uniform_scaled_m4(const float m[4][4]); /* Note: 'adjoint' here means the adjugate (adjunct, "classical adjoint") matrix! * Nowadays 'adjoint' usually refers to the conjugate transpose, * which for real-valued matrices is simply the transpose. */ -void adjoint_m2_m2(float R[2][2], float A[2][2]); -void adjoint_m3_m3(float R[3][3], float A[3][3]); -void adjoint_m4_m4(float R[4][4], float A[4][4]); +void adjoint_m2_m2(float R[2][2], const float A[2][2]); +void adjoint_m3_m3(float R[3][3], const float A[3][3]); +void adjoint_m4_m4(float R[4][4], const float A[4][4]); float determinant_m2(float a, float b, float c, float d); float determinant_m3(float a, float b, float c, float d, float e, float f, float g, float h, float i); -float determinant_m3_array(float m[3][3]); -float determinant_m4(float A[4][4]); +float determinant_m3_array(const float m[3][3]); +float determinant_m4(const float A[4][4]); #define PSEUDOINVERSE_EPSILON 1e-8f void svd_m4(float U[4][4], float s[4], float V[4][4], float A[4][4]); -void pseudoinverse_m4_m4(float Ainv[4][4], float A[4][4], float epsilon); -void pseudoinverse_m3_m3(float Ainv[3][3], float A[3][3], float epsilon); +void pseudoinverse_m4_m4(float Ainv[4][4], const float A[4][4], float epsilon); +void pseudoinverse_m3_m3(float Ainv[3][3], const float A[3][3], float epsilon); -bool has_zero_axis_m4(float matrix[4][4]); +bool has_zero_axis_m4(const float matrix[4][4]); -void invert_m4_m4_safe(float Ainv[4][4], float A[4][4]); +void invert_m4_m4_safe(float Ainv[4][4], const float A[4][4]); /****************************** Transformations ******************************/ void scale_m3_fl(float R[3][3], float scale); void scale_m4_fl(float R[4][4], float scale); -float mat3_to_scale(float M[3][3]); -float mat4_to_scale(float M[4][4]); +float mat3_to_scale(const float M[3][3]); +float mat4_to_scale(const float M[4][4]); void size_to_mat3(float R[3][3], const float size[3]); void size_to_mat4(float R[4][4], const float size[3]); -void mat3_to_size(float r[3], float M[3][3]); -void mat4_to_size(float r[3], float M[4][4]); +void mat3_to_size(float r[3], const float M[3][3]); +void mat4_to_size(float r[3], const float M[4][4]); void translate_m4(float mat[4][4], float tx, float ty, float tz); void rotate_m4(float mat[4][4], const char axis, const float angle); void transform_pivot_set_m4(float mat[4][4], const float pivot[3]); -void mat3_to_rot_size(float rot[3][3], float size[3], float mat3[3][3]); -void mat4_to_loc_rot_size(float loc[3], float rot[3][3], float size[3], float wmat[4][4]); -void mat4_to_loc_quat(float loc[3], float quat[4], float wmat[4][4]); -void mat4_decompose(float loc[3], float quat[4], float size[3], float wmat[4][4]); +void mat3_to_rot_size(float rot[3][3], float size[3], const float mat3[3][3]); +void mat4_to_loc_rot_size(float loc[3], float rot[3][3], float size[3], const float wmat[4][4]); +void mat4_to_loc_quat(float loc[3], float quat[4], const float wmat[4][4]); +void mat4_decompose(float loc[3], float quat[4], float size[3], const float wmat[4][4]); -void mat3_polar_decompose(float mat3[3][3], float r_U[3][3], float r_P[3][3]); +void mat3_polar_decompose(const float mat3[3][3], float r_U[3][3], float r_P[3][3]); void loc_eul_size_to_mat4(float R[4][4], const float loc[3], const float eul[3], const float size[3]); @@ -237,20 +250,20 @@ void loc_quat_size_to_mat4(float R[4][4], void loc_axisangle_size_to_mat4(float R[4][4], const float loc[3], const float axis[4], const float angle, const float size[3]); -void blend_m3_m3m3(float R[3][3], float A[3][3], float B[3][3], const float t); -void blend_m4_m4m4(float R[4][4], float A[4][4], float B[4][4], const float t); +void blend_m3_m3m3(float R[3][3], const float A[3][3], const float B[3][3], const float t); +void blend_m4_m4m4(float R[4][4], const float A[4][4], const float B[4][4], const float t); -void interp_m3_m3m3(float R[3][3], float A[3][3], float B[3][3], const float t); -void interp_m4_m4m4(float R[4][4], float A[4][4], float B[4][4], const float t); +void interp_m3_m3m3(float R[3][3], const float A[3][3], const float B[3][3], const float t); +void interp_m4_m4m4(float R[4][4], const float A[4][4], const float B[4][4], const float t); -bool is_negative_m3(float mat[3][3]); -bool is_negative_m4(float mat[4][4]); +bool is_negative_m3(const float mat[3][3]); +bool is_negative_m4(const float mat[4][4]); -bool is_zero_m3(float mat[3][3]); -bool is_zero_m4(float mat[4][4]); +bool is_zero_m3(const float mat[3][3]); +bool is_zero_m4(const float mat[4][4]); -bool equals_m3m3(float mat1[3][3], float mat2[3][3]); -bool equals_m4m4(float mat1[4][4], float mat2[4][4]); +bool equals_m3m3(const float mat1[3][3], const float mat2[3][3]); +bool equals_m4m4(const float mat1[4][4], const float mat2[4][4]); /* SpaceTransform helper */ typedef struct SpaceTransform { @@ -259,8 +272,8 @@ typedef struct SpaceTransform { } SpaceTransform; -void BLI_space_transform_from_matrices(struct SpaceTransform *data, float local[4][4], float target[4][4]); -void BLI_space_transform_global_from_matrices(struct SpaceTransform *data, float local[4][4], float target[4][4]); +void BLI_space_transform_from_matrices(struct SpaceTransform *data, const float local[4][4], const float target[4][4]); +void BLI_space_transform_global_from_matrices(struct SpaceTransform *data, const float local[4][4], const float target[4][4]); void BLI_space_transform_apply(const struct SpaceTransform *data, float co[3]); void BLI_space_transform_invert(const struct SpaceTransform *data, float co[3]); void BLI_space_transform_apply_normal(const struct SpaceTransform *data, float no[3]); @@ -271,8 +284,8 @@ void BLI_space_transform_invert_normal(const struct SpaceTransform *data, float /*********************************** Other ***********************************/ -void print_m3(const char *str, float M[3][3]); -void print_m4(const char *str, float M[4][4]); +void print_m3(const char *str, const float M[3][3]); +void print_m4(const char *str, const float M[4][4]); #define print_m3_id(M) print_m3(STRINGIFY(M), M) #define print_m4_id(M) print_m4(STRINGIFY(M), M) diff --git a/source/blender/blenlib/BLI_math_vector.h b/source/blender/blenlib/BLI_math_vector.h index 8e0884ba347..dc9432fef64 100644 --- a/source/blender/blenlib/BLI_math_vector.h +++ b/source/blender/blenlib/BLI_math_vector.h @@ -123,7 +123,7 @@ MINLINE void mul_v4_fl(float r[4], float f); MINLINE void mul_v4_v4fl(float r[3], const float a[3], float f); MINLINE void mul_v2_v2_cw(float r[2], const float mat[2], const float vec[2]); MINLINE void mul_v2_v2_ccw(float r[2], const float mat[2], const float vec[2]); -MINLINE float mul_project_m4_v3_zfac(float mat[4][4], const float co[3]) ATTR_WARN_UNUSED_RESULT; +MINLINE float mul_project_m4_v3_zfac(const float mat[4][4], const float co[3]) ATTR_WARN_UNUSED_RESULT; MINLINE float dot_m3_v3_row_x(float M[3][3], const float a[3]) ATTR_WARN_UNUSED_RESULT; MINLINE float dot_m3_v3_row_y(float M[3][3], const float a[3]) ATTR_WARN_UNUSED_RESULT; MINLINE float dot_m3_v3_row_z(float M[3][3], const float a[3]) ATTR_WARN_UNUSED_RESULT; @@ -305,6 +305,7 @@ void ortho_basis_v3v3_v3(float r_n1[3], float r_n2[3], const float n[3]); void ortho_v3_v3(float out[3], const float v[3]); void ortho_v2_v2(float out[2], const float v[2]); void bisect_v3_v3v3v3(float r[3], const float a[3], const float b[3], const float c[3]); +void rotate_v2_v2fl(float r[2], const float p[2], const float angle); void rotate_v3_v3v3fl(float v[3], const float p[3], const float axis[3], const float angle); void rotate_normalized_v3_v3v3fl(float out[3], const float p[3], const float axis[3], const float angle); diff --git a/source/blender/blenlib/CMakeLists.txt b/source/blender/blenlib/CMakeLists.txt index 3277519c66e..97225170f67 100644 --- a/source/blender/blenlib/CMakeLists.txt +++ b/source/blender/blenlib/CMakeLists.txt @@ -155,6 +155,7 @@ set(SRC BLI_hash_md5.h BLI_hash_mm2a.h BLI_heap.h + BLI_iterator.h BLI_jitter.h BLI_kdopbvh.h BLI_kdtree.h diff --git a/source/blender/blenlib/intern/math_color_inline.c b/source/blender/blenlib/intern/math_color_inline.c index 01a805a09b6..bc3a1ee3e90 100644 --- a/source/blender/blenlib/intern/math_color_inline.c +++ b/source/blender/blenlib/intern/math_color_inline.c @@ -239,6 +239,14 @@ MINLINE void rgba_char_args_set(char col[4], const char r, const char g, const c col[3] = a; } +MINLINE void rgba_float_args_set(float col[4], const float r, const float g, const float b, const float a) +{ + col[0] = r; + col[1] = g; + col[2] = b; + col[3] = a; +} + MINLINE void rgba_char_args_test_set(char col[4], const char r, const char g, const char b, const char a) { if (col[3] == 0) { diff --git a/source/blender/blenlib/intern/math_matrix.c b/source/blender/blenlib/intern/math_matrix.c index 9a60c670ec7..50b92f5a383 100644 --- a/source/blender/blenlib/intern/math_matrix.c +++ b/source/blender/blenlib/intern/math_matrix.c @@ -74,23 +74,23 @@ void unit_m4(float m[4][4]) m[3][0] = m[3][1] = m[3][2] = 0.0f; } -void copy_m2_m2(float m1[2][2], float m2[2][2]) +void copy_m2_m2(float m1[2][2], const float m2[2][2]) { memcpy(m1, m2, sizeof(float[2][2])); } -void copy_m3_m3(float m1[3][3], float m2[3][3]) +void copy_m3_m3(float m1[3][3], const float m2[3][3]) { /* destination comes first: */ memcpy(m1, m2, sizeof(float[3][3])); } -void copy_m4_m4(float m1[4][4], float m2[4][4]) +void copy_m4_m4(float m1[4][4], const float m2[4][4]) { memcpy(m1, m2, sizeof(float[4][4])); } -void copy_m3_m4(float m1[3][3], float m2[4][4]) +void copy_m3_m4(float m1[3][3], const float m2[4][4]) { m1[0][0] = m2[0][0]; m1[0][1] = m2[0][1]; @@ -105,7 +105,7 @@ void copy_m3_m4(float m1[3][3], float m2[4][4]) m1[2][2] = m2[2][2]; } -void copy_m4_m3(float m1[4][4], float m2[3][3]) /* no clear */ +void copy_m4_m3(float m1[4][4], const float m2[3][3]) /* no clear */ { m1[0][0] = m2[0][0]; m1[0][1] = m2[0][1]; @@ -131,7 +131,7 @@ void copy_m4_m3(float m1[4][4], float m2[3][3]) /* no clear */ } -void copy_m3_m3d(float R[3][3], double A[3][3]) +void copy_m3_m3d(float R[3][3], const double A[3][3]) { /* Keep it stupid simple for better data flow in CPU. */ R[0][0] = (float)A[0][0]; @@ -177,64 +177,107 @@ void swap_m4m4(float m1[4][4], float m2[4][4]) /******************************** Arithmetic *********************************/ -void mul_m4_m4m4(float m1[4][4], float m3_[4][4], float m2_[4][4]) +void mul_m4_m4m4(float R[4][4], const float A[4][4], const float B[4][4]) { - float m2[4][4], m3[4][4]; + if (A == R) + mul_m4_m4_post(R, B); + else if (B == R) + mul_m4_m4_pre(R, A); + else + mul_m4_m4m4_uniq(R, A, B); +} - /* copy so it works when m1 is the same pointer as m2 or m3 */ - copy_m4_m4(m2, m2_); - copy_m4_m4(m3, m3_); +void mul_m4_m4m4_uniq(float R[4][4], const float A[4][4], const float B[4][4]) +{ + BLI_assert(R != A && R != B); - /* matrix product: m1[j][k] = m2[j][i].m3[i][k] */ - m1[0][0] = m2[0][0] * m3[0][0] + m2[0][1] * m3[1][0] + m2[0][2] * m3[2][0] + m2[0][3] * m3[3][0]; - m1[0][1] = m2[0][0] * m3[0][1] + m2[0][1] * m3[1][1] + m2[0][2] * m3[2][1] + m2[0][3] * m3[3][1]; - m1[0][2] = m2[0][0] * m3[0][2] + m2[0][1] * m3[1][2] + m2[0][2] * m3[2][2] + m2[0][3] * m3[3][2]; - m1[0][3] = m2[0][0] * m3[0][3] + m2[0][1] * m3[1][3] + m2[0][2] * m3[2][3] + m2[0][3] * m3[3][3]; + /* matrix product: R[j][k] = A[j][i] . B[i][k] */ + R[0][0] = B[0][0] * A[0][0] + B[0][1] * A[1][0] + B[0][2] * A[2][0] + B[0][3] * A[3][0]; + R[0][1] = B[0][0] * A[0][1] + B[0][1] * A[1][1] + B[0][2] * A[2][1] + B[0][3] * A[3][1]; + R[0][2] = B[0][0] * A[0][2] + B[0][1] * A[1][2] + B[0][2] * A[2][2] + B[0][3] * A[3][2]; + R[0][3] = B[0][0] * A[0][3] + B[0][1] * A[1][3] + B[0][2] * A[2][3] + B[0][3] * A[3][3]; - m1[1][0] = m2[1][0] * m3[0][0] + m2[1][1] * m3[1][0] + m2[1][2] * m3[2][0] + m2[1][3] * m3[3][0]; - m1[1][1] = m2[1][0] * m3[0][1] + m2[1][1] * m3[1][1] + m2[1][2] * m3[2][1] + m2[1][3] * m3[3][1]; - m1[1][2] = m2[1][0] * m3[0][2] + m2[1][1] * m3[1][2] + m2[1][2] * m3[2][2] + m2[1][3] * m3[3][2]; - m1[1][3] = m2[1][0] * m3[0][3] + m2[1][1] * m3[1][3] + m2[1][2] * m3[2][3] + m2[1][3] * m3[3][3]; + R[1][0] = B[1][0] * A[0][0] + B[1][1] * A[1][0] + B[1][2] * A[2][0] + B[1][3] * A[3][0]; + R[1][1] = B[1][0] * A[0][1] + B[1][1] * A[1][1] + B[1][2] * A[2][1] + B[1][3] * A[3][1]; + R[1][2] = B[1][0] * A[0][2] + B[1][1] * A[1][2] + B[1][2] * A[2][2] + B[1][3] * A[3][2]; + R[1][3] = B[1][0] * A[0][3] + B[1][1] * A[1][3] + B[1][2] * A[2][3] + B[1][3] * A[3][3]; - m1[2][0] = m2[2][0] * m3[0][0] + m2[2][1] * m3[1][0] + m2[2][2] * m3[2][0] + m2[2][3] * m3[3][0]; - m1[2][1] = m2[2][0] * m3[0][1] + m2[2][1] * m3[1][1] + m2[2][2] * m3[2][1] + m2[2][3] * m3[3][1]; - m1[2][2] = m2[2][0] * m3[0][2] + m2[2][1] * m3[1][2] + m2[2][2] * m3[2][2] + m2[2][3] * m3[3][2]; - m1[2][3] = m2[2][0] * m3[0][3] + m2[2][1] * m3[1][3] + m2[2][2] * m3[2][3] + m2[2][3] * m3[3][3]; + R[2][0] = B[2][0] * A[0][0] + B[2][1] * A[1][0] + B[2][2] * A[2][0] + B[2][3] * A[3][0]; + R[2][1] = B[2][0] * A[0][1] + B[2][1] * A[1][1] + B[2][2] * A[2][1] + B[2][3] * A[3][1]; + R[2][2] = B[2][0] * A[0][2] + B[2][1] * A[1][2] + B[2][2] * A[2][2] + B[2][3] * A[3][2]; + R[2][3] = B[2][0] * A[0][3] + B[2][1] * A[1][3] + B[2][2] * A[2][3] + B[2][3] * A[3][3]; - m1[3][0] = m2[3][0] * m3[0][0] + m2[3][1] * m3[1][0] + m2[3][2] * m3[2][0] + m2[3][3] * m3[3][0]; - m1[3][1] = m2[3][0] * m3[0][1] + m2[3][1] * m3[1][1] + m2[3][2] * m3[2][1] + m2[3][3] * m3[3][1]; - m1[3][2] = m2[3][0] * m3[0][2] + m2[3][1] * m3[1][2] + m2[3][2] * m3[2][2] + m2[3][3] * m3[3][2]; - m1[3][3] = m2[3][0] * m3[0][3] + m2[3][1] * m3[1][3] + m2[3][2] * m3[2][3] + m2[3][3] * m3[3][3]; + R[3][0] = B[3][0] * A[0][0] + B[3][1] * A[1][0] + B[3][2] * A[2][0] + B[3][3] * A[3][0]; + R[3][1] = B[3][0] * A[0][1] + B[3][1] * A[1][1] + B[3][2] * A[2][1] + B[3][3] * A[3][1]; + R[3][2] = B[3][0] * A[0][2] + B[3][1] * A[1][2] + B[3][2] * A[2][2] + B[3][3] * A[3][2]; + R[3][3] = B[3][0] * A[0][3] + B[3][1] * A[1][3] + B[3][2] * A[2][3] + B[3][3] * A[3][3]; +} +void mul_m4_m4_pre(float R[4][4], const float A[4][4]) +{ + BLI_assert(A != R); + float B[4][4]; + copy_m4_m4(B, R); + mul_m4_m4m4_uniq(R, A, B); } -void mul_m3_m3m3(float m1[3][3], float m3_[3][3], float m2_[3][3]) +void mul_m4_m4_post(float R[4][4], const float B[4][4]) { - float m2[3][3], m3[3][3]; + BLI_assert(B != R); + float A[4][4]; + copy_m4_m4(A, R); + mul_m4_m4m4_uniq(R, A, B); +} - /* copy so it works when m1 is the same pointer as m2 or m3 */ - copy_m3_m3(m2, m2_); - copy_m3_m3(m3, m3_); +void mul_m3_m3m3(float R[3][3], const float A[3][3], const float B[3][3]) +{ + if (A == R) + mul_m3_m3_post(R, B); + else if (B == R) + mul_m3_m3_pre(R, A); + else + mul_m3_m3m3_uniq(R, A, B); +} - /* m1[i][j] = m2[i][k] * m3[k][j], args are flipped! */ - m1[0][0] = m2[0][0] * m3[0][0] + m2[0][1] * m3[1][0] + m2[0][2] * m3[2][0]; - m1[0][1] = m2[0][0] * m3[0][1] + m2[0][1] * m3[1][1] + m2[0][2] * m3[2][1]; - m1[0][2] = m2[0][0] * m3[0][2] + m2[0][1] * m3[1][2] + m2[0][2] * m3[2][2]; +void mul_m3_m3_pre(float R[3][3], const float A[3][3]) +{ + BLI_assert(A != R); + float B[3][3]; + copy_m3_m3(B, R); + mul_m3_m3m3_uniq(R, A, B); +} - m1[1][0] = m2[1][0] * m3[0][0] + m2[1][1] * m3[1][0] + m2[1][2] * m3[2][0]; - m1[1][1] = m2[1][0] * m3[0][1] + m2[1][1] * m3[1][1] + m2[1][2] * m3[2][1]; - m1[1][2] = m2[1][0] * m3[0][2] + m2[1][1] * m3[1][2] + m2[1][2] * m3[2][2]; +void mul_m3_m3_post(float R[3][3], const float B[3][3]) +{ + BLI_assert(B != R); + float A[3][3]; + copy_m3_m3(A, R); + mul_m3_m3m3_uniq(R, A, B); +} - m1[2][0] = m2[2][0] * m3[0][0] + m2[2][1] * m3[1][0] + m2[2][2] * m3[2][0]; - m1[2][1] = m2[2][0] * m3[0][1] + m2[2][1] * m3[1][1] + m2[2][2] * m3[2][1]; - m1[2][2] = m2[2][0] * m3[0][2] + m2[2][1] * m3[1][2] + m2[2][2] * m3[2][2]; +void mul_m3_m3m3_uniq(float R[3][3], const float A[3][3], const float B[3][3]) +{ + BLI_assert(R != A && R != B); + + R[0][0] = B[0][0] * A[0][0] + B[0][1] * A[1][0] + B[0][2] * A[2][0]; + R[0][1] = B[0][0] * A[0][1] + B[0][1] * A[1][1] + B[0][2] * A[2][1]; + R[0][2] = B[0][0] * A[0][2] + B[0][1] * A[1][2] + B[0][2] * A[2][2]; + + R[1][0] = B[1][0] * A[0][0] + B[1][1] * A[1][0] + B[1][2] * A[2][0]; + R[1][1] = B[1][0] * A[0][1] + B[1][1] * A[1][1] + B[1][2] * A[2][1]; + R[1][2] = B[1][0] * A[0][2] + B[1][1] * A[1][2] + B[1][2] * A[2][2]; + + R[2][0] = B[2][0] * A[0][0] + B[2][1] * A[1][0] + B[2][2] * A[2][0]; + R[2][1] = B[2][0] * A[0][1] + B[2][1] * A[1][1] + B[2][2] * A[2][1]; + R[2][2] = B[2][0] * A[0][2] + B[2][1] * A[1][2] + B[2][2] * A[2][2]; } -void mul_m4_m4m3(float m1[4][4], float m3_[4][4], float m2_[3][3]) +void mul_m4_m4m3(float m1[4][4], const float m3_[4][4], const float m2_[3][3]) { float m2[3][3], m3[4][4]; /* copy so it works when m1 is the same pointer as m2 or m3 */ + /* TODO: avoid copying when matrices are different */ copy_m3_m3(m2, m2_); copy_m4_m4(m3, m3_); @@ -250,11 +293,12 @@ void mul_m4_m4m3(float m1[4][4], float m3_[4][4], float m2_[3][3]) } /* m1 = m2 * m3, ignore the elements on the 4th row/column of m3 */ -void mul_m3_m3m4(float m1[3][3], float m3_[4][4], float m2_[3][3]) +void mul_m3_m3m4(float m1[3][3], const float m3_[4][4], const float m2_[3][3]) { float m2[3][3], m3[4][4]; /* copy so it works when m1 is the same pointer as m2 or m3 */ + /* TODO: avoid copying when matrices are different */ copy_m3_m3(m2, m2_); copy_m4_m4(m3, m3_); @@ -272,11 +316,12 @@ void mul_m3_m3m4(float m1[3][3], float m3_[4][4], float m2_[3][3]) m1[2][2] = m2[2][0] * m3[0][2] + m2[2][1] * m3[1][2] + m2[2][2] * m3[2][2]; } -void mul_m4_m3m4(float m1[4][4], float m3_[3][3], float m2_[4][4]) +void mul_m4_m3m4(float m1[4][4], const float m3_[3][3], const float m2_[4][4]) { float m2[4][4], m3[3][3]; /* copy so it works when m1 is the same pointer as m2 or m3 */ + /* TODO: avoid copying when matrices are different */ copy_m4_m4(m2, m2_); copy_m3_m3(m3, m3_); @@ -434,7 +479,7 @@ void _va_mul_m4_series_9( } /** \} */ -void mul_v2_m3v2(float r[2], float m[3][3], float v[2]) +void mul_v2_m3v2(float r[2], const float m[3][3], const float v[2]) { float temp[3], warped[3]; @@ -447,12 +492,12 @@ void mul_v2_m3v2(float r[2], float m[3][3], float v[2]) r[1] = warped[1] / warped[2]; } -void mul_m3_v2(float m[3][3], float r[2]) +void mul_m3_v2(const float m[3][3], float r[2]) { mul_v2_m3v2(r, m, r); } -void mul_m4_v3(float mat[4][4], float vec[3]) +void mul_m4_v3(const float mat[4][4], float vec[3]) { const float x = vec[0]; const float y = vec[1]; @@ -462,7 +507,7 @@ void mul_m4_v3(float mat[4][4], float vec[3]) vec[2] = x * mat[0][2] + y * mat[1][2] + mat[2][2] * vec[2] + mat[3][2]; } -void mul_v3_m4v3(float r[3], float mat[4][4], const float vec[3]) +void mul_v3_m4v3(float r[3], const float mat[4][4], const float vec[3]) { const float x = vec[0]; const float y = vec[1]; @@ -472,7 +517,7 @@ void mul_v3_m4v3(float r[3], float mat[4][4], const float vec[3]) r[2] = x * mat[0][2] + y * mat[1][2] + mat[2][2] * vec[2] + mat[3][2]; } -void mul_v2_m4v3(float r[2], float mat[4][4], const float vec[3]) +void mul_v2_m4v3(float r[2], const float mat[4][4], const float vec[3]) { const float x = vec[0]; @@ -480,7 +525,7 @@ void mul_v2_m4v3(float r[2], float mat[4][4], const float vec[3]) r[1] = x * mat[0][1] + vec[1] * mat[1][1] + mat[2][1] * vec[2] + mat[3][1]; } -void mul_v2_m2v2(float r[2], float mat[2][2], const float vec[2]) +void mul_v2_m2v2(float r[2], const float mat[2][2], const float vec[2]) { const float x = vec[0]; @@ -488,13 +533,13 @@ void mul_v2_m2v2(float r[2], float mat[2][2], const float vec[2]) r[1] = mat[0][1] * x + mat[1][1] * vec[1]; } -void mul_m2v2(float mat[2][2], float vec[2]) +void mul_m2v2(const float mat[2][2], float vec[2]) { mul_v2_m2v2(vec, mat, vec); } /* same as mul_m4_v3() but doesnt apply translation component */ -void mul_mat3_m4_v3(float mat[4][4], float vec[3]) +void mul_mat3_m4_v3(const float mat[4][4], float vec[3]) { const float x = vec[0]; const float y = vec[1]; @@ -504,7 +549,7 @@ void mul_mat3_m4_v3(float mat[4][4], float vec[3]) vec[2] = x * mat[0][2] + y * mat[1][2] + mat[2][2] * vec[2]; } -void mul_v3_mat3_m4v3(float r[3], float mat[4][4], const float vec[3]) +void mul_v3_mat3_m4v3(float r[3], const float mat[4][4], const float vec[3]) { const float x = vec[0]; const float y = vec[1]; @@ -514,7 +559,7 @@ void mul_v3_mat3_m4v3(float r[3], float mat[4][4], const float vec[3]) r[2] = x * mat[0][2] + y * mat[1][2] + mat[2][2] * vec[2]; } -void mul_project_m4_v3(float mat[4][4], float vec[3]) +void mul_project_m4_v3(const float mat[4][4], float vec[3]) { /* absolute value to not flip the frustum upside down behind the camera */ const float w = fabsf(mul_project_m4_v3_zfac(mat, vec)); @@ -525,7 +570,7 @@ void mul_project_m4_v3(float mat[4][4], float vec[3]) vec[2] /= w; } -void mul_v3_project_m4_v3(float r[3], float mat[4][4], const float vec[3]) +void mul_v3_project_m4_v3(float r[3], const float mat[4][4], const float vec[3]) { const float w = fabsf(mul_project_m4_v3_zfac(mat, vec)); mul_v3_m4v3(r, mat, vec); @@ -535,7 +580,7 @@ void mul_v3_project_m4_v3(float r[3], float mat[4][4], const float vec[3]) r[2] /= w; } -void mul_v2_project_m4_v3(float r[2], float mat[4][4], const float vec[3]) +void mul_v2_project_m4_v3(float r[2], const float mat[4][4], const float vec[3]) { const float w = fabsf(mul_project_m4_v3_zfac(mat, vec)); mul_v2_m4v3(r, mat, vec); @@ -544,7 +589,7 @@ void mul_v2_project_m4_v3(float r[2], float mat[4][4], const float vec[3]) r[1] /= w; } -void mul_v4_m4v4(float r[4], float mat[4][4], const float v[4]) +void mul_v4_m4v4(float r[4], const float mat[4][4], const float v[4]) { const float x = v[0]; const float y = v[1]; @@ -556,12 +601,12 @@ void mul_v4_m4v4(float r[4], float mat[4][4], const float v[4]) r[3] = x * mat[0][3] + y * mat[1][3] + z * mat[2][3] + mat[3][3] * v[3]; } -void mul_m4_v4(float mat[4][4], float r[4]) +void mul_m4_v4(const float mat[4][4], float r[4]) { mul_v4_m4v4(r, mat, r); } -void mul_v4d_m4v4d(double r[4], float mat[4][4], double v[4]) +void mul_v4d_m4v4d(double r[4], const float mat[4][4], const double v[4]) { const double x = v[0]; const double y = v[1]; @@ -573,12 +618,21 @@ void mul_v4d_m4v4d(double r[4], float mat[4][4], double v[4]) r[3] = x * (double)mat[0][3] + y * (double)mat[1][3] + z * (double)mat[2][3] + (double)mat[3][3] * v[3]; } -void mul_m4_v4d(float mat[4][4], double r[4]) +void mul_m4_v4d(const float mat[4][4], double r[4]) { mul_v4d_m4v4d(r, mat, r); } -void mul_v3_m3v3(float r[3], float M[3][3], const float a[3]) +void mul_v4_m4v3(float r[4], const float M[4][4], const float v[3]) +{ + /* v has implicit w = 1.0f */ + r[0] = v[0] * M[0][0] + v[1] * M[1][0] + M[2][0] * v[2] + M[3][0]; + r[1] = v[0] * M[0][1] + v[1] * M[1][1] + M[2][1] * v[2] + M[3][1]; + r[2] = v[0] * M[0][2] + v[1] * M[1][2] + M[2][2] * v[2] + M[3][2]; + r[3] = v[0] * M[0][3] + v[1] * M[1][3] + M[2][3] * v[2] + M[3][3]; +} + +void mul_v3_m3v3(float r[3], const float M[3][3], const float a[3]) { BLI_assert(r != a); @@ -587,7 +641,7 @@ void mul_v3_m3v3(float r[3], float M[3][3], const float a[3]) r[2] = M[0][2] * a[0] + M[1][2] * a[1] + M[2][2] * a[2]; } -void mul_v3_m3v3_db(double r[3], double M[3][3], const double a[3]) +void mul_v3_m3v3_db(double r[3], const double M[3][3], const double a[3]) { BLI_assert(r != a); @@ -596,7 +650,7 @@ void mul_v3_m3v3_db(double r[3], double M[3][3], const double a[3]) r[2] = M[0][2] * a[0] + M[1][2] * a[1] + M[2][2] * a[2]; } -void mul_v2_m3v3(float r[2], float M[3][3], const float a[3]) +void mul_v2_m3v3(float r[2], const float M[3][3], const float a[3]) { BLI_assert(r != a); @@ -604,17 +658,17 @@ void mul_v2_m3v3(float r[2], float M[3][3], const float a[3]) r[1] = M[0][1] * a[0] + M[1][1] * a[1] + M[2][1] * a[2]; } -void mul_m3_v3(float M[3][3], float r[3]) +void mul_m3_v3(const float M[3][3], float r[3]) { mul_v3_m3v3(r, M, (const float[3]){UNPACK3(r)}); } -void mul_m3_v3_db(double M[3][3], double r[3]) +void mul_m3_v3_db(const double M[3][3], double r[3]) { mul_v3_m3v3_db(r, M, (const double[3]){UNPACK3(r)}); } -void mul_transposed_m3_v3(float mat[3][3], float vec[3]) +void mul_transposed_m3_v3(const float mat[3][3], float vec[3]) { const float x = vec[0]; const float y = vec[1]; @@ -624,7 +678,7 @@ void mul_transposed_m3_v3(float mat[3][3], float vec[3]) vec[2] = x * mat[2][0] + y * mat[2][1] + mat[2][2] * vec[2]; } -void mul_transposed_mat3_m4_v3(float mat[4][4], float vec[3]) +void mul_transposed_mat3_m4_v3(const float mat[4][4], float vec[3]) { const float x = vec[0]; const float y = vec[1]; @@ -688,7 +742,7 @@ void negate_m4(float m[4][4]) m[i][j] *= -1.0f; } -void mul_m3_v3_double(float mat[3][3], double vec[3]) +void mul_m3_v3_double(const float mat[3][3], double vec[3]) { const double x = vec[0]; const double y = vec[1]; @@ -698,7 +752,7 @@ void mul_m3_v3_double(float mat[3][3], double vec[3]) vec[2] = x * (double)mat[0][2] + y * (double)mat[1][2] + (double)mat[2][2] * vec[2]; } -void add_m3_m3m3(float m1[3][3], float m2[3][3], float m3[3][3]) +void add_m3_m3m3(float m1[3][3], const float m2[3][3], const float m3[3][3]) { int i, j; @@ -707,7 +761,7 @@ void add_m3_m3m3(float m1[3][3], float m2[3][3], float m3[3][3]) m1[i][j] = m2[i][j] + m3[i][j]; } -void add_m4_m4m4(float m1[4][4], float m2[4][4], float m3[4][4]) +void add_m4_m4m4(float m1[4][4], const float m2[4][4], const float m3[4][4]) { int i, j; @@ -716,7 +770,7 @@ void add_m4_m4m4(float m1[4][4], float m2[4][4], float m3[4][4]) m1[i][j] = m2[i][j] + m3[i][j]; } -void sub_m3_m3m3(float m1[3][3], float m2[3][3], float m3[3][3]) +void sub_m3_m3m3(float m1[3][3], const float m2[3][3], const float m3[3][3]) { int i, j; @@ -725,7 +779,7 @@ void sub_m3_m3m3(float m1[3][3], float m2[3][3], float m3[3][3]) m1[i][j] = m2[i][j] - m3[i][j]; } -void sub_m4_m4m4(float m1[4][4], float m2[4][4], float m3[4][4]) +void sub_m4_m4m4(float m1[4][4], const float m2[4][4], const float m3[4][4]) { int i, j; @@ -734,7 +788,7 @@ void sub_m4_m4m4(float m1[4][4], float m2[4][4], float m3[4][4]) m1[i][j] = m2[i][j] - m3[i][j]; } -float determinant_m3_array(float m[3][3]) +float determinant_m3_array(const float m[3][3]) { return (m[0][0] * (m[1][1] * m[2][2] - m[1][2] * m[2][1]) - m[1][0] * (m[0][1] * m[2][2] - m[0][2] * m[2][1]) + @@ -750,7 +804,7 @@ bool invert_m3_ex(float m[3][3], const float epsilon) return success; } -bool invert_m3_m3_ex(float m1[3][3], float m2[3][3], const float epsilon) +bool invert_m3_m3_ex(float m1[3][3], const float m2[3][3], const float epsilon) { float det; int a, b; @@ -786,7 +840,7 @@ bool invert_m3(float m[3][3]) return success; } -bool invert_m3_m3(float m1[3][3], float m2[3][3]) +bool invert_m3_m3(float m1[3][3], const float m2[3][3]) { float det; int a, b; @@ -830,7 +884,7 @@ bool invert_m4(float m[4][4]) * Mark Segal - 1992 */ -bool invert_m4_m4(float inverse[4][4], float mat[4][4]) +bool invert_m4_m4(float inverse[4][4], const float mat[4][4]) { int i, j, k; double temp; @@ -908,7 +962,7 @@ void transpose_m3(float mat[3][3]) mat[2][1] = t; } -void transpose_m3_m3(float rmat[3][3], float mat[3][3]) +void transpose_m3_m3(float rmat[3][3], const float mat[3][3]) { BLI_assert(rmat != mat); @@ -924,7 +978,7 @@ void transpose_m3_m3(float rmat[3][3], float mat[3][3]) } /* seems obscure but in-fact a common operation */ -void transpose_m3_m4(float rmat[3][3], float mat[4][4]) +void transpose_m3_m4(float rmat[3][3], const float mat[4][4]) { BLI_assert(&rmat[0][0] != &mat[0][0]); @@ -965,7 +1019,7 @@ void transpose_m4(float mat[4][4]) mat[3][2] = t; } -void transpose_m4_m4(float rmat[4][4], float mat[4][4]) +void transpose_m4_m4(float rmat[4][4], const float mat[4][4]) { BLI_assert(rmat != mat); @@ -987,7 +1041,8 @@ void transpose_m4_m4(float rmat[4][4], float mat[4][4]) rmat[3][3] = mat[3][3]; } -int compare_m4m4(float mat1[4][4], float mat2[4][4], float limit) +/* TODO: return bool */ +int compare_m4m4(const float mat1[4][4], const float mat2[4][4], float limit) { if (compare_v4v4(mat1[0], mat2[0], limit)) if (compare_v4v4(mat1[1], mat2[1], limit)) @@ -1165,7 +1220,7 @@ void orthogonalize_m4(float mat[4][4], int axis) mul_v3_fl(mat[2], size[2]); } -bool is_orthogonal_m3(float m[3][3]) +bool is_orthogonal_m3(const float m[3][3]) { int i, j; @@ -1179,7 +1234,7 @@ bool is_orthogonal_m3(float m[3][3]) return true; } -bool is_orthogonal_m4(float m[4][4]) +bool is_orthogonal_m4(const float m[4][4]) { int i, j; @@ -1194,7 +1249,7 @@ bool is_orthogonal_m4(float m[4][4]) return true; } -bool is_orthonormal_m3(float m[3][3]) +bool is_orthonormal_m3(const float m[3][3]) { if (is_orthogonal_m3(m)) { int i; @@ -1209,7 +1264,7 @@ bool is_orthonormal_m3(float m[3][3]) return false; } -bool is_orthonormal_m4(float m[4][4]) +bool is_orthonormal_m4(const float m[4][4]) { if (is_orthogonal_m4(m)) { int i; @@ -1224,7 +1279,7 @@ bool is_orthonormal_m4(float m[4][4]) return false; } -bool is_uniform_scaled_m3(float m[3][3]) +bool is_uniform_scaled_m3(const float m[3][3]) { const float eps = 1e-7f; float t[3][3]; @@ -1252,7 +1307,7 @@ bool is_uniform_scaled_m3(float m[3][3]) return false; } -bool is_uniform_scaled_m4(float m[4][4]) +bool is_uniform_scaled_m4(const float m[4][4]) { float t[3][3]; copy_m3_m4(t, m); @@ -1274,14 +1329,14 @@ void normalize_m3(float mat[3][3]) } } -void normalize_m3_m3_ex(float rmat[3][3], float mat[3][3], float r_scale[3]) +void normalize_m3_m3_ex(float rmat[3][3], const float mat[3][3], float r_scale[3]) { int i; for (i = 0; i < 3; i++) { r_scale[i] = normalize_v3_v3(rmat[i], mat[i]); } } -void normalize_m3_m3(float rmat[3][3], float mat[3][3]) +void normalize_m3_m3(float rmat[3][3], const float mat[3][3]) { int i; for (i = 0; i < 3; i++) { @@ -1310,7 +1365,7 @@ void normalize_m4(float mat[4][4]) } } -void normalize_m4_m4_ex(float rmat[4][4], float mat[4][4], float r_scale[3]) +void normalize_m4_m4_ex(float rmat[4][4], const float mat[4][4], float r_scale[3]) { int i; for (i = 0; i < 3; i++) { @@ -1319,7 +1374,7 @@ void normalize_m4_m4_ex(float rmat[4][4], float mat[4][4], float r_scale[3]) } copy_v4_v4(rmat[3], mat[3]); } -void normalize_m4_m4(float rmat[4][4], float mat[4][4]) +void normalize_m4_m4(float rmat[4][4], const float mat[4][4]) { int i; for (i = 0; i < 3; i++) { @@ -1329,7 +1384,7 @@ void normalize_m4_m4(float rmat[4][4], float mat[4][4]) copy_v4_v4(rmat[3], mat[3]); } -void adjoint_m2_m2(float m1[2][2], float m[2][2]) +void adjoint_m2_m2(float m1[2][2], const float m[2][2]) { BLI_assert(m1 != m); m1[0][0] = m[1][1]; @@ -1338,7 +1393,7 @@ void adjoint_m2_m2(float m1[2][2], float m[2][2]) m1[1][1] = m[0][0]; } -void adjoint_m3_m3(float m1[3][3], float m[3][3]) +void adjoint_m3_m3(float m1[3][3], const float m[3][3]) { BLI_assert(m1 != m); m1[0][0] = m[1][1] * m[2][2] - m[1][2] * m[2][1]; @@ -1354,7 +1409,7 @@ void adjoint_m3_m3(float m1[3][3], float m[3][3]) m1[2][2] = m[0][0] * m[1][1] - m[0][1] * m[1][0]; } -void adjoint_m4_m4(float out[4][4], float in[4][4]) /* out = ADJ(in) */ +void adjoint_m4_m4(float out[4][4], const float in[4][4]) /* out = ADJ(in) */ { float a1, a2, a3, a4, b1, b2, b3, b4; float c1, c2, c3, c4, d1, d2, d3, d4; @@ -1420,7 +1475,7 @@ float determinant_m3(float a1, float a2, float a3, return ans; } -float determinant_m4(float m[4][4]) +float determinant_m4(const float m[4][4]) { float ans; float a1, a2, a3, a4, b1, b2, b3, b4, c1, c2, c3, c4, d1, d2, d3, d4; @@ -1488,14 +1543,14 @@ void size_to_mat4(float mat[4][4], const float size[3]) mat[3][3] = 1.0f; } -void mat3_to_size(float size[3], float mat[3][3]) +void mat3_to_size(float size[3], const float mat[3][3]) { size[0] = len_v3(mat[0]); size[1] = len_v3(mat[1]); size[2] = len_v3(mat[2]); } -void mat4_to_size(float size[3], float mat[4][4]) +void mat4_to_size(float size[3], const float mat[4][4]) { size[0] = len_v3(mat[0]); size[1] = len_v3(mat[1]); @@ -1505,7 +1560,7 @@ void mat4_to_size(float size[3], float mat[4][4]) /* this gets the average scale of a matrix, only use when your scaling * data that has no idea of scale axis, examples are bone-envelope-radius * and curve radius */ -float mat3_to_scale(float mat[3][3]) +float mat3_to_scale(const float mat[3][3]) { /* unit length vector */ float unit_vec[3]; @@ -1514,7 +1569,7 @@ float mat3_to_scale(float mat[3][3]) return len_v3(unit_vec); } -float mat4_to_scale(float mat[4][4]) +float mat4_to_scale(const float mat[4][4]) { /* unit length vector */ float unit_vec[3]; @@ -1523,7 +1578,7 @@ float mat4_to_scale(float mat[4][4]) return len_v3(unit_vec); } -void mat3_to_rot_size(float rot[3][3], float size[3], float mat3[3][3]) +void mat3_to_rot_size(float rot[3][3], float size[3], const float mat3[3][3]) { /* keep rot as a 3x3 matrix, the caller can convert into a quat or euler */ size[0] = normalize_v3_v3(rot[0], mat3[0]); @@ -1535,7 +1590,7 @@ void mat3_to_rot_size(float rot[3][3], float size[3], float mat3[3][3]) } } -void mat4_to_loc_rot_size(float loc[3], float rot[3][3], float size[3], float wmat[4][4]) +void mat4_to_loc_rot_size(float loc[3], float rot[3][3], float size[3], const float wmat[4][4]) { float mat3[3][3]; /* wmat -> 3x3 */ @@ -1546,7 +1601,7 @@ void mat4_to_loc_rot_size(float loc[3], float rot[3][3], float size[3], float wm copy_v3_v3(loc, wmat[3]); } -void mat4_to_loc_quat(float loc[3], float quat[4], float wmat[4][4]) +void mat4_to_loc_quat(float loc[3], float quat[4], const float wmat[4][4]) { float mat3[3][3]; float mat3_n[3][3]; /* normalized mat3 */ @@ -1564,7 +1619,7 @@ void mat4_to_loc_quat(float loc[3], float quat[4], float wmat[4][4]) copy_v3_v3(loc, wmat[3]); } -void mat4_decompose(float loc[3], float quat[4], float size[3], float wmat[4][4]) +void mat4_decompose(float loc[3], float quat[4], float size[3], const float wmat[4][4]) { float rot[3][3]; mat4_to_loc_rot_size(loc, rot, size, wmat); @@ -1581,7 +1636,7 @@ void mat4_decompose(float loc[3], float quat[4], float size[3], float wmat[4][4] * See https://en.wikipedia.org/wiki/Polar_decomposition for more. */ #ifndef MATH_STANDALONE -void mat3_polar_decompose(float mat3[3][3], float r_U[3][3], float r_P[3][3]) +void mat3_polar_decompose(const float mat3[3][3], float r_U[3][3], float r_P[3][3]) { /* From svd decomposition (M = WSV*), we have: * U = WV* @@ -1625,6 +1680,7 @@ void translate_m4(float mat[4][4], float Tx, float Ty, float Tz) mat[3][2] += (Tx * mat[0][2] + Ty * mat[1][2] + Tz * mat[2][2]); } +/* TODO: enum for axis? */ /** * Rotate a matrix in-place. * @@ -1688,7 +1744,7 @@ void transform_pivot_set_m4(float mat[4][4], const float pivot[3]) mul_m4_m4m4(mat, mat, tmat); } -void blend_m3_m3m3(float out[3][3], float dst[3][3], float src[3][3], const float srcweight) +void blend_m3_m3m3(float out[3][3], const float dst[3][3], const float src[3][3], const float srcweight) { float srot[3][3], drot[3][3]; float squat[4], dquat[4], fquat[4]; @@ -1711,7 +1767,7 @@ void blend_m3_m3m3(float out[3][3], float dst[3][3], float src[3][3], const floa mul_m3_m3m3(out, rmat, smat); } -void blend_m4_m4m4(float out[4][4], float dst[4][4], float src[4][4], const float srcweight) +void blend_m4_m4m4(float out[4][4], const float dst[4][4], const float src[4][4], const float srcweight) { float sloc[3], dloc[3], floc[3]; float srot[3][3], drot[3][3]; @@ -1749,7 +1805,7 @@ void blend_m4_m4m4(float out[4][4], float dst[4][4], float src[4][4], const floa * @param B the intput matrix which is totally effective with \a t = 1.0. * @param t the interpolation factor. */ -void interp_m3_m3m3(float R[3][3], float A[3][3], float B[3][3], const float t) +void interp_m3_m3m3(float R[3][3], const float A[3][3], const float B[3][3], const float t) { /* 'Rotation' component ('U' part of polar decomposition, the closest orthogonal matrix to M3 rot/scale * transformation matrix), spherically interpolated. */ @@ -1784,7 +1840,7 @@ void interp_m3_m3m3(float R[3][3], float A[3][3], float B[3][3], const float t) * @param B the intput matrix which is totally effective with \a t = 1.0. * @param t the interpolation factor. */ -void interp_m4_m4m4(float R[4][4], float A[4][4], float B[4][4], const float t) +void interp_m4_m4m4(float R[4][4], const float A[4][4], const float B[4][4], const float t) { float A3[3][3], B3[3][3], R3[3][3]; @@ -1805,27 +1861,27 @@ void interp_m4_m4m4(float R[4][4], float A[4][4], float B[4][4], const float t) } #endif /* MATH_STANDALONE */ -bool is_negative_m3(float mat[3][3]) +bool is_negative_m3(const float mat[3][3]) { float vec[3]; cross_v3_v3v3(vec, mat[0], mat[1]); return (dot_v3v3(vec, mat[2]) < 0.0f); } -bool is_negative_m4(float mat[4][4]) +bool is_negative_m4(const float mat[4][4]) { float vec[3]; cross_v3_v3v3(vec, mat[0], mat[1]); return (dot_v3v3(vec, mat[2]) < 0.0f); } -bool is_zero_m3(float mat[3][3]) +bool is_zero_m3(const float mat[3][3]) { return (is_zero_v3(mat[0]) && is_zero_v3(mat[1]) && is_zero_v3(mat[2])); } -bool is_zero_m4(float mat[4][4]) +bool is_zero_m4(const float mat[4][4]) { return (is_zero_v4(mat[0]) && is_zero_v4(mat[1]) && @@ -1833,14 +1889,14 @@ bool is_zero_m4(float mat[4][4]) is_zero_v4(mat[3])); } -bool equals_m3m3(float mat1[3][3], float mat2[3][3]) +bool equals_m3m3(const float mat1[3][3], const float mat2[3][3]) { return (equals_v3v3(mat1[0], mat2[0]) && equals_v3v3(mat1[1], mat2[1]) && equals_v3v3(mat1[2], mat2[2])); } -bool equals_m4m4(float mat1[4][4], float mat2[4][4]) +bool equals_m4m4(const float mat1[4][4], const float mat2[4][4]) { return (equals_v4v4(mat1[0], mat2[0]) && equals_v4v4(mat1[1], mat2[1]) && @@ -1931,7 +1987,7 @@ void loc_axisangle_size_to_mat4(float mat[4][4], const float loc[3], const float /*********************************** Other ***********************************/ -void print_m3(const char *str, float m[3][3]) +void print_m3(const char *str, const float m[3][3]) { printf("%s\n", str); printf("%f %f %f\n", m[0][0], m[1][0], m[2][0]); @@ -1940,7 +1996,7 @@ void print_m3(const char *str, float m[3][3]) printf("\n"); } -void print_m4(const char *str, float m[4][4]) +void print_m4(const char *str, const float m[4][4]) { printf("%s\n", str); printf("%f %f %f %f\n", m[0][0], m[1][0], m[2][0], m[3][0]); @@ -2394,7 +2450,7 @@ void svd_m4(float U[4][4], float s[4], float V[4][4], float A_[4][4]) } } -void pseudoinverse_m4_m4(float Ainv[4][4], float A_[4][4], float epsilon) +void pseudoinverse_m4_m4(float Ainv[4][4], const float A_[4][4], float epsilon) { /* compute Moore-Penrose pseudo inverse of matrix, singular values * below epsilon are ignored for stability (truncated SVD) */ @@ -2415,7 +2471,7 @@ void pseudoinverse_m4_m4(float Ainv[4][4], float A_[4][4], float epsilon) mul_m4_series(Ainv, U, Wm, V); } -void pseudoinverse_m3_m3(float Ainv[3][3], float A[3][3], float epsilon) +void pseudoinverse_m3_m3(float Ainv[3][3], const float A[3][3], float epsilon) { /* try regular inverse when possible, otherwise fall back to slow svd */ if (!invert_m3_m3(Ainv, A)) { @@ -2427,14 +2483,14 @@ void pseudoinverse_m3_m3(float Ainv[3][3], float A[3][3], float epsilon) } } -bool has_zero_axis_m4(float matrix[4][4]) +bool has_zero_axis_m4(const float matrix[4][4]) { return len_squared_v3(matrix[0]) < FLT_EPSILON || len_squared_v3(matrix[1]) < FLT_EPSILON || len_squared_v3(matrix[2]) < FLT_EPSILON; } -void invert_m4_m4_safe(float Ainv[4][4], float A[4][4]) +void invert_m4_m4_safe(float Ainv[4][4], const float A[4][4]) { if (!invert_m4_m4(Ainv, A)) { float Atemp[4][4]; @@ -2482,7 +2538,7 @@ void invert_m4_m4_safe(float Ainv[4][4], float A[4][4]) * this defines a transform matrix TM such that (x', y', z') = TM * (x, y, z) * where (x', y', z') are the coordinates of P' in target space such that it keeps (X, Y, Z) coordinates in global space. */ -void BLI_space_transform_from_matrices(SpaceTransform *data, float local[4][4], float target[4][4]) +void BLI_space_transform_from_matrices(SpaceTransform *data, const float local[4][4], const float target[4][4]) { float itarget[4][4]; invert_m4_m4(itarget, target); @@ -2500,7 +2556,7 @@ void BLI_space_transform_from_matrices(SpaceTransform *data, float local[4][4], * this defines a transform matrix TM such that (X', Y', Z') = TM * (X, Y, Z) * where (X', Y', Z') are the coordinates of p' in global space such that it keeps (x, y, z) coordinates in target space. */ -void BLI_space_transform_global_from_matrices(SpaceTransform *data, float local[4][4], float target[4][4]) +void BLI_space_transform_global_from_matrices(SpaceTransform *data, const float local[4][4], const float target[4][4]) { float ilocal[4][4]; invert_m4_m4(ilocal, local); diff --git a/source/blender/blenlib/intern/math_vector.c b/source/blender/blenlib/intern/math_vector.c index dfecc3b556a..500c6e57923 100644 --- a/source/blender/blenlib/intern/math_vector.c +++ b/source/blender/blenlib/intern/math_vector.c @@ -782,6 +782,20 @@ void ortho_v2_v2(float out[2], const float v[2]) } /** + * Rotate a point \a p by \a angle around origin (0, 0) + */ +void rotate_v2_v2fl(float r[2], const float p[2], const float angle) +{ + const float co = cosf(angle); + const float si = sinf(angle); + + BLI_assert(r != p); + + r[0] = co * p[0] - si * p[1]; + r[1] = si * p[0] + co * p[1]; +} + +/** * Rotate a point \a p by \a angle around an arbitrary unit length \a axis. * http://local.wasp.uwa.edu.au/~pbourke/geometry/ */ diff --git a/source/blender/blenlib/intern/math_vector_inline.c b/source/blender/blenlib/intern/math_vector_inline.c index ee5e8651bd3..4389cd29034 100644 --- a/source/blender/blenlib/intern/math_vector_inline.c +++ b/source/blender/blenlib/intern/math_vector_inline.c @@ -491,7 +491,7 @@ MINLINE void mul_v2_v2_ccw(float r[2], const float mat[2], const float vec[2]) * return co_4d[3]; * \endcode */ -MINLINE float mul_project_m4_v3_zfac(float mat[4][4], const float co[3]) +MINLINE float mul_project_m4_v3_zfac(const float mat[4][4], const float co[3]) { return (mat[0][3] * co[0]) + (mat[1][3] * co[1]) + diff --git a/source/blender/blenlib/intern/scanfill_utils.c b/source/blender/blenlib/intern/scanfill_utils.c index 3b6ab99ae86..ef1df479f13 100644 --- a/source/blender/blenlib/intern/scanfill_utils.c +++ b/source/blender/blenlib/intern/scanfill_utils.c @@ -95,20 +95,6 @@ void BLI_scanfill_obj_dump(ScanFillContext *sf_ctx) } #endif -#if 0 -void BLI_scanfill_view3d_dump(ScanFillContext *sf_ctx) -{ - ScanFillEdge *eed; - - bl_debug_draw_quad_clear(); - bl_debug_color_set(0x0000ff); - - for (eed = sf_ctx->filledgebase.first; eed; eed = eed->next) { - bl_debug_draw_edge_add(eed->v1->co, eed->v2->co); - } -} -#endif - static ListBase *edge_isect_ls_ensure(GHash *isect_hash, ScanFillEdge *eed) { ListBase *e_ls; diff --git a/source/blender/blenloader/CMakeLists.txt b/source/blender/blenloader/CMakeLists.txt index 8cb9ef837b2..e40692f4a88 100644 --- a/source/blender/blenloader/CMakeLists.txt +++ b/source/blender/blenloader/CMakeLists.txt @@ -53,6 +53,7 @@ set(SRC intern/versioning_250.c intern/versioning_260.c intern/versioning_270.c + intern/versioning_280.c intern/versioning_defaults.c intern/versioning_legacy.c intern/writefile.c diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c index 7ea79fc5557..8a18533f730 100644 --- a/source/blender/blenloader/intern/readfile.c +++ b/source/blender/blenloader/intern/readfile.c @@ -72,6 +72,7 @@ #include "DNA_ipo_types.h" #include "DNA_key_types.h" #include "DNA_lattice_types.h" +#include "DNA_layer_types.h" #include "DNA_lamp_types.h" #include "DNA_linestyle_types.h" #include "DNA_meta_types.h" @@ -125,6 +126,7 @@ #include "BKE_fcurve.h" #include "BKE_global.h" // for G #include "BKE_group.h" +#include "BKE_layer.h" #include "BKE_library.h" // for which_libbase #include "BKE_library_idmap.h" #include "BKE_library_query.h" @@ -3967,6 +3969,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); @@ -3987,6 +3990,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 ***************** */ @@ -4607,6 +4615,7 @@ static void direct_link_mesh(FileData *fd, Mesh *mesh) mesh->bb = NULL; mesh->edit_btmesh = NULL; + mesh->batch_cache = NULL; /* happens with old files */ if (mesh->mselect == NULL) { @@ -5548,6 +5557,7 @@ static void direct_link_object(FileData *fd, Object *ob) ob->bb = NULL; ob->derivedDeform = NULL; ob->derivedFinal = NULL; + BLI_listbase_clear(&ob->collection_settings); BLI_listbase_clear(&ob->gpulamp); link_list(fd, &ob->pc_ids); @@ -5629,11 +5639,29 @@ static bool scene_validate_setscene__liblink(Scene *sce, const int totscene) } #endif +static void lib_link_scene_collection(FileData *fd, Library *lib, SceneCollection *sc) +{ + for (LinkData *link = sc->objects.first; link; link = link->next) { + link->data = newlibadr_us(fd, lib, link->data); + BLI_assert(link->data); + } + + for (LinkData *link = sc->filter_objects.first; link; link = link->next) { + link->data = newlibadr_us(fd, lib, link->data); + BLI_assert(link->data); + } + + for (SceneCollection *nsc = sc->scene_collections.first; nsc; nsc = nsc->next) { + lib_link_scene_collection(fd, lib, nsc); + } +} + static void lib_link_scene(FileData *fd, Main *main) { Scene *sce; - Base *base, *next; + BaseLegacy *base_legacy, *base_legacy_next; Sequence *seq; + SceneLayer *sl; SceneRenderLayer *srl; FreestyleModuleConfig *fmc; FreestyleLineSet *fls; @@ -5683,17 +5711,17 @@ static void lib_link_scene(FileData *fd, Main *main) sce->toolsettings->particle.shape_object = newlibadr(fd, sce->id.lib, sce->toolsettings->particle.shape_object); - for (base = sce->base.first; base; base = next) { - next = base->next; + for (base_legacy = sce->base.first; base_legacy; base_legacy = base_legacy_next) { + base_legacy_next = base_legacy->next; - base->object = newlibadr_us(fd, sce->id.lib, base->object); + base_legacy->object = newlibadr_us(fd, sce->id.lib, base_legacy->object); - if (base->object == NULL) { + if (base_legacy->object == NULL) { blo_reportf_wrap(fd->reports, RPT_WARNING, TIP_("LIB: object lost from scene: '%s'"), sce->id.name + 2); - BLI_remlink(&sce->base, base); - if (base == sce->basact) sce->basact = NULL; - MEM_freeN(base); + BLI_remlink(&sce->base, base_legacy); + if (base_legacy == sce->basact) sce->basact = NULL; + MEM_freeN(base_legacy); } } @@ -5779,6 +5807,18 @@ static void lib_link_scene(FileData *fd, Main *main) /* Motion Tracking */ sce->clip = newlibadr_us(fd, sce->id.lib, sce->clip); + lib_link_scene_collection(fd, sce->id.lib, sce->collection); + + for (sl = sce->render_layers.first; sl; sl = sl->next) { + /* tag scene layer to update for collection tree evaluation */ + sl->flag |= SCENE_LAYER_ENGINE_DIRTY; + for (Base *base = sl->object_bases.first; base; base = base->next) { + /* we only bump the use count for the collection objects */ + base->object = newlibadr(fd, sce->id.lib, base->object); + base->flag |= BASE_DIRTY_ENGINE_SETTINGS; + } + } + #ifdef USE_SETSCENE_CHECK if (sce->set != NULL) { /* link flag for scenes with set would be reset later, @@ -5882,13 +5922,56 @@ static void direct_link_view_settings(FileData *fd, ColorManagedViewSettings *vi direct_link_curvemapping(fd, view_settings->curve_mapping); } +static void direct_link_scene_collection(FileData *fd, SceneCollection *sc) +{ + link_list(fd, &sc->objects); + link_list(fd, &sc->filter_objects); + link_list(fd, &sc->scene_collections); + + for (SceneCollection *nsc = sc->scene_collections.first; nsc; nsc = nsc->next) { + direct_link_scene_collection(fd, nsc); + } +} + +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); + for (LayerCollection *lc = lb->first; lc; lc = lc->next) { + lc->scene_collection = newdataadr(fd, lc->scene_collection); + + link_list(fd, &lc->object_bases); + + for (LinkData *link = lc->object_bases.first; link; link = link->next) { + link->data = newdataadr(fd, link->data); + } + + link_list(fd, &lc->overrides); + + direct_link_engine_settings(fd, &lc->engine_settings); + + direct_link_engine_settings(fd, &lc->mode_settings); + + direct_link_layer_collections(fd, &lc->layer_collections); + } +} + static void direct_link_scene(FileData *fd, Scene *sce) { Editing *ed; Sequence *seq; MetaStack *ms; RigidBodyWorld *rbw; + SceneLayer *sl; SceneRenderLayer *srl; + RenderEngineSettings *res; sce->theDag = NULL; sce->depsgraph = NULL; @@ -6138,6 +6221,26 @@ static void direct_link_scene(FileData *fd, Scene *sce) sce->preview = direct_link_preview_image(fd, sce->preview); direct_link_curvemapping(fd, &sce->r.mblur_shutter_curve); + + /* this runs before the very first doversion */ + if (sce->collection) { + sce->collection = newdataadr(fd, sce->collection); + direct_link_scene_collection(fd, sce->collection); + } + + link_list(fd, &sce->render_layers); + for (sl = sce->render_layers.first; sl; sl = sl->next) { + link_list(fd, &sl->object_bases); + sl->basact = newdataadr(fd, sl->basact); + direct_link_layer_collections(fd, &sl->layer_collections); + /* tag scene layer to update for collection tree evaluation */ + BKE_scene_layer_base_flag_recalculate(sl); + } + + link_list(fd, &sce->engines_settings); + for (res = sce->engines_settings.first; res; res = res->next) { + res->data = newdataadr(fd, res->data); + } } /* ************ READ WM ***************** */ @@ -6922,6 +7025,7 @@ static void direct_link_region(FileData *fd, ARegion *ar, int spacetype) rv3d->sms = NULL; rv3d->smooth_timer = NULL; rv3d->compositor = NULL; + rv3d->viewport = NULL; } } } @@ -6938,6 +7042,7 @@ static void direct_link_region(FileData *fd, ARegion *ar, int spacetype) ar->type = NULL; ar->swap = 0; ar->do_draw = 0; + ar->manipulator_map = NULL; ar->regiontimer = NULL; memset(&ar->drawrct, 0, sizeof(ar->drawrct)); } @@ -6984,6 +7089,8 @@ static bool direct_link_screen(FileData *fd, bScreen *sc) sc->mainwin = sc->subwinactive= 0; /* indices */ sc->swap = 0; + sc->preview = direct_link_preview_image(fd, sc->preview); + /* edges */ for (se = sc->edgebase.first; se; se = se->next) { se->v1 = newdataadr(fd, se->v1); @@ -7452,7 +7559,7 @@ static void lib_link_group(FileData *fd, Main *main) if (add_us) { id_us_ensure_real(&group->id); } - BKE_group_object_unlink(group, NULL, NULL, NULL); /* removes NULL entries */ + BKE_group_object_unlink(group, NULL); /* removes NULL entries */ } } } @@ -8384,6 +8491,7 @@ static void do_versions(FileData *fd, Library *lib, Main *main) blo_do_versions_250(fd, lib, main); blo_do_versions_260(fd, lib, main); blo_do_versions_270(fd, lib, main); + blo_do_versions_280(fd, lib, main); /* WATCH IT!!!: pointers from libdata have not been converted yet here! */ /* WATCH IT 2!: Userdef struct init see do_versions_userdef() above! */ @@ -8395,8 +8503,8 @@ static void do_versions_after_linking(Main *main) { // printf("%s for %s (%s), %d.%d\n", __func__, main->curlib ? main->curlib->name : main->name, // main->curlib ? "LIB" : "MAIN", main->versionfile, main->subversionfile); - do_versions_after_linking_270(main); + do_versions_after_linking_280(main); } static void lib_link_all(FileData *fd, Main *main) @@ -9371,7 +9479,7 @@ static void expand_object(FileData *fd, Main *mainvar, Object *ob) expand_doit(fd, mainvar, ob->proxy); if (ob->proxy_group) expand_doit(fd, mainvar, ob->proxy_group); - + for (psys = ob->particlesystem.first; psys; psys = psys->next) expand_doit(fd, mainvar, psys->part); @@ -9479,9 +9587,24 @@ static void expand_object(FileData *fd, Main *mainvar, Object *ob) } } +static void expand_scene_collection(FileData *fd, Main *mainvar, SceneCollection *sc) +{ + for (LinkData *link = sc->objects.first; link; link = link->next) { + expand_doit(fd, mainvar, link->data); + } + + for (LinkData *link = sc->filter_objects.first; link; link = link->next) { + expand_doit(fd, mainvar, link->data); + } + + for (SceneCollection *nsc= sc->scene_collections.first; nsc; nsc = nsc->next) { + expand_scene_collection(fd, mainvar, nsc); + } +} + static void expand_scene(FileData *fd, Main *mainvar, Scene *sce) { - Base *base; + BaseLegacy *base; SceneRenderLayer *srl; FreestyleModuleConfig *module; FreestyleLineSet *lineset; @@ -9548,6 +9671,8 @@ static void expand_scene(FileData *fd, Main *mainvar, Scene *sce) } expand_doit(fd, mainvar, sce->clip); + + expand_scene_collection(fd, mainvar, sce->collection); } static void expand_camera(FileData *fd, Main *mainvar, Camera *ca) @@ -9794,7 +9919,7 @@ static bool object_in_any_scene(Main *mainvar, Object *ob) static void give_base_to_objects(Main *mainvar, Scene *scene, View3D *v3d, Library *lib, const short flag) { Object *ob; - Base *base; + BaseLegacy *base; const unsigned int active_lay = (flag & FILE_ACTIVELAY) ? BKE_screen_view3d_layer_active(v3d, scene) : 0; const bool is_link = (flag & FILE_LINK) != 0; @@ -9815,7 +9940,7 @@ static void give_base_to_objects(Main *mainvar, Scene *scene, View3D *v3d, Libra } if (do_it) { - base = MEM_callocN(sizeof(Base), __func__); + base = MEM_callocN(sizeof(BaseLegacy), __func__); BLI_addtail(&scene->base, base); if (active_lay) { @@ -9830,7 +9955,7 @@ static void give_base_to_objects(Main *mainvar, Scene *scene, View3D *v3d, Libra base->object = ob; base->lay = ob->lay; - base->flag = ob->flag; + BKE_scene_base_flag_sync_from_object(base); CLAMP_MIN(ob->id.us, 0); id_us_plus_no_lib((ID *)ob); @@ -9846,7 +9971,7 @@ static void give_base_to_groups( Main *mainvar, Scene *scene, View3D *v3d, Library *UNUSED(lib), const short UNUSED(flag)) { Group *group; - Base *base; + BaseLegacy *base; Object *ob; const unsigned int active_lay = BKE_screen_view3d_layer_active(v3d, scene); @@ -9863,8 +9988,8 @@ static void give_base_to_groups( /* assign the base */ base = BKE_scene_base_add(scene, ob); - base->flag |= SELECT; - base->object->flag = base->flag; + base->flag_legacy |= SELECT; + BKE_scene_base_flag_sync_from_base(base); DAG_id_tag_update(&ob->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME); scene->basact = base; @@ -9946,10 +10071,10 @@ static ID *link_named_part( static void link_object_postprocess(ID *id, Scene *scene, View3D *v3d, const short flag) { if (scene) { - Base *base; + BaseLegacy *base; Object *ob; - base = MEM_callocN(sizeof(Base), "app_nam_part"); + base = MEM_callocN(sizeof(BaseLegacy), "app_nam_part"); BLI_addtail(&scene->base, base); ob = (Object *)id; @@ -9962,12 +10087,12 @@ static void link_object_postprocess(ID *id, Scene *scene, View3D *v3d, const sho ob->mode = OB_MODE_OBJECT; base->lay = ob->lay; base->object = ob; - base->flag = ob->flag; + base->flag_legacy = ob->flag; id_us_plus_no_lib((ID *)ob); if (flag & FILE_AUTOSELECT) { - base->flag |= SELECT; - base->object->flag = base->flag; + base->flag_legacy |= SELECT; + BKE_scene_base_flag_sync_from_base(base); /* do NOT make base active here! screws up GUI stuff, if you want it do it on src/ level */ } } diff --git a/source/blender/blenloader/intern/readfile.h b/source/blender/blenloader/intern/readfile.h index d97bef13a78..50cdeca16b5 100644 --- a/source/blender/blenloader/intern/readfile.h +++ b/source/blender/blenloader/intern/readfile.h @@ -34,6 +34,8 @@ #define __READFILE_H__ #include "zlib.h" +#include "DNA_sdna_types.h" +#include "DNA_space_types.h" #include "DNA_windowmanager_types.h" /* for ReportType */ struct OldNewMap; @@ -169,8 +171,10 @@ void blo_do_versions_pre250(struct FileData *fd, struct Library *lib, struct Mai void blo_do_versions_250(struct FileData *fd, struct Library *lib, struct Main *main); void blo_do_versions_260(struct FileData *fd, struct Library *lib, struct Main *main); void blo_do_versions_270(struct FileData *fd, struct Library *lib, struct Main *main); +void blo_do_versions_280(struct FileData *fd, struct Library *lib, struct Main *main); void do_versions_after_linking_270(struct Main *main); +void do_versions_after_linking_280(struct Main *main); #endif diff --git a/source/blender/blenloader/intern/versioning_250.c b/source/blender/blenloader/intern/versioning_250.c index 1956a17d57b..943e5479d9a 100644 --- a/source/blender/blenloader/intern/versioning_250.c +++ b/source/blender/blenloader/intern/versioning_250.c @@ -736,7 +736,7 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *main) if (main->versionfile < 250) { bScreen *screen; Scene *scene; - Base *base; + BaseLegacy *base; Material *ma; Camera *cam; Mesh *me; diff --git a/source/blender/blenloader/intern/versioning_270.c b/source/blender/blenloader/intern/versioning_270.c index 7106cf60721..12045dfdb83 100644 --- a/source/blender/blenloader/intern/versioning_270.c +++ b/source/blender/blenloader/intern/versioning_270.c @@ -1599,6 +1599,29 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main) } FOREACH_NODETREE_END } } + + { + if (!DNA_struct_elem_find(fd->filesdna, "View3DDebug", "char", "background")) { + bScreen *screen; + + for (screen = main->screen.first; screen; screen = screen->id.next) { + ScrArea *sa; + for (sa = screen->areabase.first; sa; sa = sa->next) { + SpaceLink *sl; + + for (sl = sa->spacedata.first; sl; sl = sl->next) { + switch (sl->spacetype) { + case SPACE_VIEW3D: + { + View3D *v3d = (View3D *)sl; + v3d->debug.background = V3D_DEBUG_BACKGROUND_NONE; + } + } + } + } + } + } + } } void do_versions_after_linking_270(Main *main) diff --git a/source/blender/blenloader/intern/versioning_280.c b/source/blender/blenloader/intern/versioning_280.c new file mode 100644 index 00000000000..9d575c8f6d2 --- /dev/null +++ b/source/blender/blenloader/intern/versioning_280.c @@ -0,0 +1,196 @@ +/* + * ***** 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. + * + * Contributor(s): Dalai Felinto + * + * ***** END GPL LICENSE BLOCK ***** + * + */ + +/** \file blender/blenloader/intern/versioning_280.c + * \ingroup blenloader + */ + +/* allow readfile to use deprecated functionality */ +#define DNA_DEPRECATED_ALLOW + +#include "DNA_object_types.h" +#include "DNA_layer_types.h" +#include "DNA_material_types.h" +#include "DNA_scene_types.h" +#include "DNA_genfile.h" + +#include "BKE_collection.h" +#include "BKE_layer.h" +#include "BKE_main.h" +#include "BKE_scene.h" + +#include "BLI_listbase.h" +#include "BLI_string.h" + +#include "BLO_readfile.h" +#include "readfile.h" + +#include "MEM_guardedalloc.h" + +void do_versions_after_linking_280(Main *main) +{ + if (!MAIN_VERSION_ATLEAST(main, 280, 0)) { + for (Scene *scene = main->scene.first; scene; scene = scene->id.next) { + /* since we don't have access to FileData we check the (always valid) first render layer instead */ + if (scene->render_layers.first == NULL) { + SceneCollection *sc_master = BKE_collection_master(scene); + BLI_strncpy(sc_master->name, "Master Collection", sizeof(sc_master->name)); + + SceneCollection *collections[20] = {NULL}; + bool is_visible[20]; + + int lay_used = 0; + for (int i = 0; i < 20; i++) { + char name[MAX_NAME]; + + BLI_snprintf(name, sizeof(collections[i]->name), "%d", i + 1); + collections[i] = BKE_collection_add(scene, sc_master, name); + + is_visible[i] = (scene->lay & (1 << i)); + } + + for (Base *base = scene->base.first; base; base = base->next) { + lay_used |= base->lay & ((1 << 20) - 1); /* ignore localview */ + + for (int i = 0; i < 20; i++) { + if ((base->lay & (1 << i)) != 0) { + BKE_collection_object_add(scene, collections[i], base->object); + } + } + } + + scene->active_layer = 0; + + if (!BKE_scene_uses_blender_game(scene)) { + for (SceneRenderLayer *srl = scene->r.layers.first; srl; srl = srl->next) { + + SceneLayer *sl = BKE_scene_layer_add(scene, srl->name); + BKE_scene_layer_engine_set(sl, scene->r.engine); + + if (srl->mat_override) { + BKE_collection_override_datablock_add((LayerCollection *)sl->layer_collections.first, "material", (ID *)srl->mat_override); + } + + if (srl->light_override && BKE_scene_uses_blender_internal(scene)) { + /* not sure how we handle this, pending until we design the override system */ + TODO_LAYER_OVERRIDE; + } + + if (srl->lay != scene->lay) { + /* unlink master collection */ + BKE_collection_unlink(sl, sl->layer_collections.first); + + /* add new collection bases */ + for (int i = 0; i < 20; i++) { + if ((srl->lay & (1 << i)) != 0) { + BKE_collection_link(sl, collections[i]); + } + } + } + + /* for convenience set the same active object in all the layers */ + if (scene->basact) { + sl->basact = BKE_scene_layer_base_find(sl, scene->basact->object); + } + + /* TODO: passes, samples, mask_layesr, exclude, ... */ + } + + if (BLI_findlink(&scene->render_layers, scene->r.actlay)) { + scene->active_layer = scene->r.actlay; + } + } + + SceneLayer *sl = BKE_scene_layer_add(scene, "Viewport"); + + /* In this particular case we can safely assume the data struct */ + LayerCollection *lc = ((LayerCollection *)sl->layer_collections.first)->layer_collections.first; + for (int i = 0; i < 20; i++) { + if (!is_visible[i]) { + lc->flag &= ~COLLECTION_VISIBLE; + } + lc = lc->next; + } + + /* but we still need to make the flags synced */ + BKE_scene_layer_base_flag_recalculate(sl); + + /* convert active base */ + if (scene->basact) { + sl->basact = BKE_scene_layer_base_find(sl, scene->basact->object); + } + + /* convert selected bases */ + for (Base *base = scene->base.first; base; base = base->next) { + Base *ob_base = BKE_scene_layer_base_find(sl, base->object); + if ((base->flag & SELECT) != 0) { + if ((ob_base->flag & BASE_SELECTABLED) != 0) { + ob_base->flag |= BASE_SELECTED; + } + } + else { + ob_base->flag &= ~BASE_SELECTED; + } + } + + /* TODO: copy scene render data to layer */ + + /* Cleanup */ + for (int i = 0; i < 20; i++) { + if ((lay_used & (1 << i)) == 0) { + BKE_collection_remove(scene, collections[i]); + } + } + + /* remove bases once and for all */ + for (Base *base = scene->base.first; base; base = base->next) { + id_us_min(&base->object->id); + } + BLI_freelistN(&scene->base); + scene->basact = NULL; + } + } + } +} + +static void blo_do_version_temporary(Main *main) +{ + BKE_scene_layer_doversion_update(main); +} + +void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *main) +{ + if (!MAIN_VERSION_ATLEAST(main, 280, 0)) { + if (!DNA_struct_elem_find(fd->filesdna, "Scene", "ListBase", "render_layers")) { + for (Scene *scene = main->scene.first; scene; scene = scene->id.next) { + /* Master Collection */ + scene->collection = MEM_callocN(sizeof(SceneCollection), "Master Collection"); + BLI_strncpy(scene->collection->name, "Master Collection", sizeof(scene->collection->name)); + } + } + + /* temporary validation of 280 files for layers */ + blo_do_version_temporary(main); + } + +} diff --git a/source/blender/blenloader/intern/writefile.c b/source/blender/blenloader/intern/writefile.c index 38a032f4907..f97e4d6c48f 100644 --- a/source/blender/blenloader/intern/writefile.c +++ b/source/blender/blenloader/intern/writefile.c @@ -120,6 +120,7 @@ #include "DNA_key_types.h" #include "DNA_lattice_types.h" #include "DNA_lamp_types.h" +#include "DNA_layer_types.h" #include "DNA_linestyle_types.h" #include "DNA_meta_types.h" #include "DNA_mesh_types.h" @@ -1728,6 +1729,8 @@ static void write_modifiers(WriteData *wd, ListBase *modbase) SmokeModifierData *smd = (SmokeModifierData *)md; if (smd->type & MOD_SMOKE_TYPE_DOMAIN) { + writestruct(wd, DATA, SmokeDomainSettings, 1, smd->domain); + if (smd->domain) { write_pointcaches(wd, &(smd->domain->ptcaches[0])); @@ -1741,11 +1744,8 @@ static void write_modifiers(WriteData *wd, ListBase *modbase) if (smd->domain->coba) { writestruct(wd, DATA, ColorBand, 1, smd->domain->coba); } - } - writestruct(wd, DATA, SmokeDomainSettings, 1, smd->domain); - if (smd->domain) { /* cleanup the fake pointcache */ BKE_ptcache_free_list(&smd->domain->ptcaches[1]); smd->domain->point_cache[1] = NULL; @@ -2235,6 +2235,7 @@ static void write_meshes(WriteData *wd, ListBase *idbase) CustomData_reset(&mesh->pdata); CustomData_reset(&mesh->ldata); mesh->edit_btmesh = NULL; + mesh->batch_cache = NULL; /* now fill in polys to mfaces */ /* XXX This breaks writing design, by using temp allocated memory, which will likely generate @@ -2416,6 +2417,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) { for (Material *ma = idbase->first; ma; ma = ma->id.next) { @@ -2448,6 +2464,8 @@ static void write_materials(WriteData *wd, ListBase *idbase) } write_previews(wd, ma->preview); + + write_material_engines_settings(wd, &ma->engines_settings); } } } @@ -2558,6 +2576,72 @@ static void write_paint(WriteData *wd, Paint *p) } } +static void write_scene_collection(WriteData *wd, SceneCollection *sc) +{ + writestruct(wd, DATA, SceneCollection, 1, sc); + + writelist(wd, DATA, LinkData, &sc->objects); + writelist(wd, DATA, LinkData, &sc->filter_objects); + + for (SceneCollection *nsc = sc->scene_collections.first; nsc; nsc = nsc->next) { + write_scene_collection(wd, nsc); + } +} + +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; + case COLLECTION_PROP_TYPE_BOOL: + writestruct(wd, DATA, CollectionEnginePropertyBool, 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) { + writestruct(wd, DATA, LayerCollection, 1, lc); + + writelist(wd, DATA, LinkData, &lc->object_bases); + writelist(wd, DATA, CollectionOverride, &lc->overrides); + + write_collection_engine_settings(wd, &lc->engine_settings); + + write_collection_engine_settings(wd, &lc->mode_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) { for (Scene *sce = scebase->first; sce; sce = sce->id.next) { @@ -2571,8 +2655,8 @@ static void write_scenes(WriteData *wd, ListBase *scebase) write_keyingsets(wd, &sce->keyingsets); /* direct data */ - for (Base *base = sce->base.first; base; base = base->next) { - writestruct(wd, DATA, Base, 1, base); + for (BaseLegacy *base = sce->base.first; base; base = base->next) { + writestruct(wd, DATA, BaseLegacy, 1, base); } ToolSettings *tos = sce->toolsettings; @@ -2762,6 +2846,16 @@ static void write_scenes(WriteData *wd, ListBase *scebase) write_previews(wd, sce->preview); write_curvemapping_curves(wd, &sce->r.mblur_shutter_curve); + write_scene_collection(wd, sce->collection); + + for (SceneLayer *sl = sce->render_layers.first; sl; sl = sl->next) { + writestruct(wd, DATA, SceneLayer, 1, sl); + writelist(wd, DATA, Base, &sl->object_bases); + write_layer_collections(wd, &sl->layer_collections); + } + + write_render_engines_settings(wd, &sce->engines_settings); + } mywrite_flush(wd); @@ -2909,6 +3003,8 @@ static void write_screens(WriteData *wd, ListBase *scrbase) writestruct(wd, ID_SCRN, bScreen, 1, sc); write_iddata(wd, &sc->id); + write_previews(wd, sc->preview); + /* direct data */ for (ScrVert *sv = sc->vertbase.first; sv; sv = sv->next) { writestruct(wd, DATA, ScrVert, 1, sv); diff --git a/source/blender/bmesh/tools/bmesh_intersect.c b/source/blender/bmesh/tools/bmesh_intersect.c index 58234ddf3bd..2b38af80fc9 100644 --- a/source/blender/bmesh/tools/bmesh_intersect.c +++ b/source/blender/bmesh/tools/bmesh_intersect.c @@ -81,12 +81,6 @@ /* use accelerated overlap check */ #define USE_BVH -// #define USE_BOOLEAN_RAYCAST_DRAW - -#ifdef USE_BOOLEAN_RAYCAST_DRAW -/* insert bl_debug_draw_quad_clear... here */ -#endif - // #define USE_DUMP static void tri_v3_scale( @@ -1006,10 +1000,6 @@ bool BM_mesh_intersect( int i_a, i_b; #endif -#ifdef USE_BOOLEAN_RAYCAST_DRAW - bl_debug_draw_quad_clear(); -#endif - s.bm = bm; s.edgetri_cache = BLI_ghash_new(BLI_ghashutil_inthash_v4_p, BLI_ghashutil_inthash_v4_cmp, __func__); @@ -1607,17 +1597,6 @@ bool BM_mesh_intersect( do_flip = (side == 0); break; } - -#ifdef USE_BOOLEAN_RAYCAST_DRAW - { - unsigned int colors[4] = {0x00000000, 0xffffffff, 0xff000000, 0x0000ff}; - float co_other[3] = {UNPACK3(co)}; - co_other[0] += 1000.0f; - bl_debug_color_set(colors[(hits & 1) == 1]); - bl_debug_draw_edge_add(co, co_other); - } -#endif - } if (do_remove) { diff --git a/source/blender/collada/DocumentImporter.cpp b/source/blender/collada/DocumentImporter.cpp index 226f319cefd..5118234a587 100644 --- a/source/blender/collada/DocumentImporter.cpp +++ b/source/blender/collada/DocumentImporter.cpp @@ -57,6 +57,7 @@ extern "C" { #include "BLI_fileops.h" #include "BKE_camera.h" +#include "BKE_collection.h" #include "BKE_main.h" #include "BKE_lamp.h" #include "BKE_library.h" @@ -264,7 +265,7 @@ void DocumentImporter::finish() for (it = libnode_ob.begin(); it != libnode_ob.end(); it++) { Object *ob = *it; - Base *base = BKE_scene_base_find(sce, ob); + BaseLegacy *base = (BaseLegacy *)BKE_scene_base_find(sce, ob); if (base) { BLI_remlink(&sce->base, base); BKE_libblock_free_us(G.main, base->object); @@ -418,7 +419,7 @@ Object *DocumentImporter::create_instance_node(Object *source_ob, COLLADAFW::Nod Object *obn = BKE_object_copy(G.main, source_ob); DAG_id_tag_update(&obn->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME); - BKE_scene_base_add(sce, obn); + BKE_collection_object_add_from(sce, source_ob, obn); if (instance_node) { anim_importer.read_node_transform(instance_node, obn); diff --git a/source/blender/collada/EffectExporter.cpp b/source/blender/collada/EffectExporter.cpp index 76b51148509..7d9599c8554 100644 --- a/source/blender/collada/EffectExporter.cpp +++ b/source/blender/collada/EffectExporter.cpp @@ -66,7 +66,7 @@ EffectsExporter::EffectsExporter(COLLADASW::StreamWriter *sw, const ExportSettin bool EffectsExporter::hasEffects(Scene *sce) { - Base *base = (Base *)sce->base.first; + BaseLegacy *base = (BaseLegacy *)sce->base.first; while (base) { Object *ob = base->object; diff --git a/source/blender/depsgraph/CMakeLists.txt b/source/blender/depsgraph/CMakeLists.txt index e635256cda6..2d32e85bf64 100644 --- a/source/blender/depsgraph/CMakeLists.txt +++ b/source/blender/depsgraph/CMakeLists.txt @@ -113,10 +113,6 @@ else() endif() endif() -if(WITH_LEGACY_DEPSGRAPH) - add_definitions(-DWITH_LEGACY_DEPSGRAPH) -endif() - if(WITH_BOOST) list(APPEND INC_SYS ${BOOST_INCLUDE_DIR} diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc index 6b7fb5246ca..0f0d16907f4 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc @@ -125,7 +125,7 @@ static void modifier_walk(void *user_data, { BuilderWalkUserData *data = (BuilderWalkUserData *)user_data; if (*obpoin) { - data->builder->build_object(data->scene, NULL, *obpoin); + data->builder->build_object(data->scene, *obpoin); } } @@ -138,7 +138,7 @@ void constraint_walk(bConstraint * /*con*/, if (*idpoin) { ID *id = *idpoin; if (GS(id->name) == ID_OB) { - data->builder->build_object(data->scene, NULL, (Object *)id); + data->builder->build_object(data->scene, (Object *)id); } } } @@ -337,9 +337,7 @@ void DepsgraphNodeBuilder::begin_build(Main *bmain) { } FOREACH_NODETREE_END } -void DepsgraphNodeBuilder::build_group(Scene *scene, - Base *base, - Group *group) +void DepsgraphNodeBuilder::build_group(Scene *scene, Group *group) { ID *group_id = &group->id; if (group_id->tag & LIB_TAG_DOIT) { @@ -348,7 +346,7 @@ void DepsgraphNodeBuilder::build_group(Scene *scene, group_id->tag |= LIB_TAG_DOIT; LINKLIST_FOREACH (GroupObject *, go, &group->gobject) { - build_object(scene, base, go->ob); + build_object(scene, go->ob); } } @@ -387,7 +385,7 @@ SubgraphDepsNode *DepsgraphNodeBuilder::build_subgraph(Group *group) return subgraph_node; } -void DepsgraphNodeBuilder::build_object(Scene *scene, Base *base, Object *ob) +void DepsgraphNodeBuilder::build_object(Scene *scene, Object *ob) { const bool has_object = (ob->id.tag & LIB_TAG_DOIT); IDDepsNode *id_node = (has_object) @@ -397,9 +395,12 @@ void DepsgraphNodeBuilder::build_object(Scene *scene, Base *base, Object *ob) * Do it for both new and existing ID nodes. This is so because several * bases might be sharing same object. */ - if (base != NULL) { - id_node->layers |= base->lay; - } + + /* Blender 2.8 transition: we don't have bases and do not have + * layer masks, but still want objects to be updated + */ + id_node->layers |= ((1 << 20) - 1); + if (ob == scene->camera) { /* Camera should always be updated, it used directly by viewport. */ id_node->layers |= (unsigned int)(-1); @@ -415,7 +416,7 @@ void DepsgraphNodeBuilder::build_object(Scene *scene, Base *base, Object *ob) build_object_transform(scene, ob); if (ob->parent != NULL) { - build_object(scene, NULL, ob->parent); + build_object(scene, ob->parent); } if (ob->modifiers.first != NULL) { BuilderWalkUserData data; @@ -834,8 +835,8 @@ void DepsgraphNodeBuilder::build_obdata_geom(Scene *scene, Object *ob) add_operation_node(&ob->id, DEPSNODE_TYPE_SHADING, DEPSOP_TYPE_EXEC, - NULL, - DEG_OPCODE_PLACEHOLDER, "Material Update"); + function_bind(BKE_object_eval_shading, _1, ob), + DEG_OPCODE_OPERATION, "Material Update"); } /* geometry collision */ @@ -927,13 +928,13 @@ void DepsgraphNodeBuilder::build_obdata_geom(Scene *scene, Object *ob) */ Curve *cu = (Curve *)obdata; if (cu->bevobj != NULL) { - build_object(scene, NULL, cu->bevobj); + build_object(scene, cu->bevobj); } if (cu->taperobj != NULL) { - build_object(scene, NULL, cu->taperobj); + build_object(scene, cu->taperobj); } if (ob->type == OB_FONT && cu->textoncurve != NULL) { - build_object(scene, NULL, cu->textoncurve); + build_object(scene, cu->textoncurve); } break; } diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes.h b/source/blender/depsgraph/intern/builder/deg_builder_nodes.h index c5035f35f6e..2f3f733b8db 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_nodes.h +++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes.h @@ -32,7 +32,6 @@ #include "intern/depsgraph_types.h" -struct Base; struct CacheFile; struct bGPdata; struct ListBase; @@ -126,8 +125,8 @@ struct DepsgraphNodeBuilder { void build_scene(Main *bmain, Scene *scene); SubgraphDepsNode *build_subgraph(Group *group); - void build_group(Scene *scene, Base *base, Group *group); - void build_object(Scene *scene, Base *base, Object *ob); + void build_group(Scene *scene, Group *group); + void build_object(Scene *scene, Object *ob); void build_object_transform(Scene *scene, Object *ob); void build_object_constraints(Scene *scene, Object *ob); void build_pose_constraints(Object *ob, bPoseChannel *pchan); diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes_rig.cc b/source/blender/depsgraph/intern/builder/deg_builder_nodes_rig.cc index f2437ce1fac..b1896fdc22a 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_nodes_rig.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes_rig.cc @@ -133,7 +133,7 @@ void DepsgraphNodeBuilder::build_rig(Scene *scene, Object *ob) /* Rebuild pose if not up to date. */ if (ob->pose == NULL || (ob->pose->flag & POSE_RECALC)) { - BKE_pose_rebuild_ex(ob, arm, false); + BKE_pose_rebuild(ob, arm); /* XXX: Without this animation gets lost in certain circumstances * after loading file. Need to investigate further since it does * not happen with simple scenes.. diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes_scene.cc b/source/blender/depsgraph/intern/builder/deg_builder_nodes_scene.cc index 99e61692231..f4a191067ca 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_nodes_scene.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes_scene.cc @@ -46,6 +46,7 @@ extern "C" { #include "DNA_object_types.h" #include "DNA_scene_types.h" +#include "BKE_layer.h" #include "BKE_main.h" #include "BKE_node.h" @@ -79,24 +80,24 @@ void DepsgraphNodeBuilder::build_scene(Main *bmain, Scene *scene) } /* scene objects */ - LINKLIST_FOREACH (Base *, base, &scene->base) { - Object *ob = base->object; - + FOREACH_SCENE_OBJECT(scene, ob) + { /* object itself */ - build_object(scene, base, ob); + build_object(scene, ob); /* object that this is a proxy for */ // XXX: the way that proxies work needs to be completely reviewed! if (ob->proxy) { ob->proxy->proxy_from = ob; - build_object(scene, base, ob->proxy); + build_object(scene, ob->proxy); } /* Object dupligroup. */ if (ob->dup_group) { - build_group(scene, base, ob->dup_group); + build_group(scene, ob->dup_group); } } + FOREACH_SCENE_OBJECT_END /* rigidbody */ if (scene->rigidbody_world) { diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc index 94cff521edc..6d4597fed9d 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc @@ -1432,6 +1432,14 @@ void DepsgraphRelationBuilder::build_obdata_geom(Main *bmain, Scene *scene, Obje "Object Shading"); } } + OperationKey obdata_geom_done_key(obdata, + DEPSNODE_TYPE_GEOMETRY, + DEG_OPCODE_PLACEHOLDER, + "Eval Done"); + add_relation(geom_key, + object_shading_key, + DEPSREL_TYPE_UPDATE, + "Object Shading"); } /* geometry collision */ diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations.h b/source/blender/depsgraph/intern/builder/deg_builder_relations.h index 054e4103290..2e6fa7b5801 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_relations.h +++ b/source/blender/depsgraph/intern/builder/deg_builder_relations.h @@ -45,7 +45,7 @@ #include "intern/nodes/deg_node.h" #include "intern/nodes/deg_node_operation.h" -struct Base; +struct BaseLegacy; struct bGPdata; struct CacheFile; struct ListBase; diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations_scene.cc b/source/blender/depsgraph/intern/builder/deg_builder_relations_scene.cc index 8a3476cff45..f0d70e3871b 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_relations_scene.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_relations_scene.cc @@ -46,6 +46,7 @@ extern "C" { #include "DNA_object_types.h" #include "DNA_scene_types.h" +#include "BKE_layer.h" #include "BKE_main.h" #include "BKE_node.h" @@ -74,9 +75,8 @@ void DepsgraphRelationBuilder::build_scene(Main *bmain, Scene *scene) } /* scene objects */ - LINKLIST_FOREACH (Base *, base, &scene->base) { - Object *ob = base->object; - + FOREACH_SCENE_OBJECT(scene, ob) + { /* object itself */ build_object(bmain, scene, ob); @@ -97,6 +97,7 @@ void DepsgraphRelationBuilder::build_scene(Main *bmain, Scene *scene) build_group(bmain, scene, ob, ob->dup_group); } } + FOREACH_SCENE_OBJECT_END /* rigidbody */ if (scene->rigidbody_world) { diff --git a/source/blender/depsgraph/intern/depsgraph_eval.cc b/source/blender/depsgraph/intern/depsgraph_eval.cc index c41f28b07e8..ebaf0089835 100644 --- a/source/blender/depsgraph/intern/depsgraph_eval.cc +++ b/source/blender/depsgraph/intern/depsgraph_eval.cc @@ -52,43 +52,9 @@ extern "C" { #include "intern/depsgraph.h" -#ifdef WITH_LEGACY_DEPSGRAPH -static bool use_legacy_depsgraph = true; -#endif - /* Unfinished and unused, and takes quite some pre-processing time. */ #undef USE_EVAL_PRIORITY -bool DEG_depsgraph_use_legacy(void) -{ -#ifdef DISABLE_NEW_DEPSGRAPH - return true; -#elif defined(WITH_LEGACY_DEPSGRAPH) - return use_legacy_depsgraph; -#else - BLI_assert(!"Should not be used with new depsgraph"); - return false; -#endif -} - -void DEG_depsgraph_switch_to_legacy(void) -{ -#ifdef WITH_LEGACY_DEPSGRAPH - use_legacy_depsgraph = true; -#else - BLI_assert(!"Should not be used with new depsgraph"); -#endif -} - -void DEG_depsgraph_switch_to_new(void) -{ -#ifdef WITH_LEGACY_DEPSGRAPH - use_legacy_depsgraph = false; -#else - BLI_assert(!"Should not be used with new depsgraph"); -#endif -} - /* ****************** */ /* Evaluation Context */ diff --git a/source/blender/depsgraph/intern/depsgraph_tag.cc b/source/blender/depsgraph/intern/depsgraph_tag.cc index e8ed03666a6..a9df68beb36 100644 --- a/source/blender/depsgraph/intern/depsgraph_tag.cc +++ b/source/blender/depsgraph/intern/depsgraph_tag.cc @@ -74,7 +74,9 @@ extern "C" { * design of those areas is more clear we'll do the same legacy code here. * - sergey - */ +#if 0 #define DEPSGRAPH_USE_LEGACY_TAGGING +#endif namespace { diff --git a/source/blender/depsgraph/util/deg_util_foreach.h b/source/blender/depsgraph/util/deg_util_foreach.h index 87d37168d51..8c234eae7de 100644 --- a/source/blender/depsgraph/util/deg_util_foreach.h +++ b/source/blender/depsgraph/util/deg_util_foreach.h @@ -36,15 +36,7 @@ # include <boost/foreach.hpp> # define foreach BOOST_FOREACH #else -#pragma message("No available foreach() implementation. Using stub instead, disabling new depsgraph") - -#ifndef WITH_LEGACY_DEPSGRAPH -# error "Unable to build new depsgraph and legacy one is disabled." -#endif - -#define DISABLE_NEW_DEPSGRAPH - -# define foreach(x, y) for (x; false; (void)y) +# error "Depsgraph requires either Boost or C++11 for range-based loops." #endif #define GHASH_FOREACH_BEGIN(type, var, what) \ diff --git a/source/blender/depsgraph/util/deg_util_function.h b/source/blender/depsgraph/util/deg_util_function.h index 1e34ae04d9a..da31bb037f9 100644 --- a/source/blender/depsgraph/util/deg_util_function.h +++ b/source/blender/depsgraph/util/deg_util_function.h @@ -47,64 +47,5 @@ using boost::function; #define function_bind boost::bind #else - -#pragma message("No available function binding implementation. Using stub instead, disabling new depsgraph") - -#ifndef WITH_LEGACY_DEPSGRAPH -# error "Unable to build new depsgraph and legacy one is disabled." -#endif - -#define DISABLE_NEW_DEPSGRAPH - -#include "BLI_utildefines.h" -#include <cstdlib> - -template<typename T> -class function { -public: - function() {}; - function(void *) {} - operator bool() const { return false; } - bool operator== (void *) { return false; } - - template<typename T1> - void operator() (T1) { - BLI_assert(!"Should not be used"); - } -}; - -class Wrap { -public: - Wrap() {} - template <typename T> - Wrap(T /*arg*/) {} -}; - -template <typename T> -void *function_bind(T func, - Wrap arg1 = Wrap(), - Wrap arg2 = Wrap(), - Wrap arg3 = Wrap(), - Wrap arg4 = Wrap(), - Wrap arg5 = Wrap(), - Wrap arg6 = Wrap(), - Wrap arg7 = Wrap()) -{ - BLI_assert(!"Should not be used"); - (void)func; - (void)arg1; - (void)arg2; - (void)arg3; - (void)arg4; - (void)arg5; - (void)arg6; - (void)arg7; - return NULL; -} - -#define _1 Wrap() -#define _2 Wrap() -#define _3 Wrap() -#define _4 Wrap() - +# error "Depsgraph requires either Boost or C++11 for function bindings." #endif diff --git a/source/blender/draw/CMakeLists.txt b/source/blender/draw/CMakeLists.txt new file mode 100644 index 00000000000..12722ff23ef --- /dev/null +++ b/source/blender/draw/CMakeLists.txt @@ -0,0 +1,88 @@ +# ***** 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) 2016, Blender Foundation +# All rights reserved. +# +# The Original Code is: all of this file. +# +# Contributor(s): Blender Institute +# +# ***** END GPL LICENSE BLOCK ***** + +set(INC + . + intern + engines/clay + modes/ + + ../blenkernel + ../blenlib + ../blentranslation + ../imbuf + ../depsgraph + ../makesdna + ../makesrna + ../gpu + ../editors/include + ../editors/space_view3d + ../render/extern/include + ../render/intern/include + + ../../../intern/glew-mx + ../../../intern/guardedalloc +) + +set(INC_SYS + ${GLEW_INCLUDE_PATH} +) + +set(SRC + intern/draw_manager.c + intern/draw_mode_pass.c + intern/draw_cache.c + intern/draw_view.c + intern/draw_armature.c + engines/clay/clay.c + modes/edit_armature_mode.c + modes/edit_mesh_mode.c + modes/object_mode.c + + intern/DRW_render.h + intern/draw_mode_pass.h + intern/draw_cache.h + intern/draw_view.h + engines/clay/clay.h + modes/edit_armature_mode.h + modes/edit_mesh_mode.h + modes/object_mode.h + + ./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..05ecc7390d1 --- /dev/null +++ b/source/blender/draw/DRW_engine.h @@ -0,0 +1,49 @@ +/* + * 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__ + +struct CollectionEngineSettings; +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); + +/* Mode engines initialization */ +void OBJECT_collection_settings_create(struct CollectionEngineSettings *ces); +void EDIT_MESH_collection_settings_create(struct CollectionEngineSettings *ces); +void EDIT_ARMATURE_collection_settings_create(struct CollectionEngineSettings *ces); + +#endif /* __DRW_ENGINE_H__ */ diff --git a/source/blender/draw/engines/clay/clay.c b/source/blender/draw/engines/clay/clay.c new file mode 100644 index 00000000000..54bae5de85c --- /dev/null +++ b/source/blender/draw/engines/clay/clay.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 + * + */ + +#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 */ + +#define CLAY_ENGINE "BLENDER_CLAY" + +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 */ + +#define MAX_CLAY_MAT 512 /* 512 = 9 bit material id */ + +typedef struct CLAY_UBO_Storage { + CLAY_UBO_Material materials[MAX_CLAY_MAT]; +} CLAY_UBO_Storage; + +static struct CLAY_data { + /* Depth Pre Pass */ + struct GPUShader *depth_sh; + /* Shading Pass */ + struct GPUShader *clay_sh; + + /* 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}; + +/* GPUViewport.storage + * Is freed everytime the viewport engine changes */ +typedef struct CLAY_Storage { + /* Materials Parameter UBO */ + CLAY_UBO_Storage mat_storage; + int ubo_current_id; + DRWShadingGroup *shgrps[MAX_CLAY_MAT]; +} CLAY_Storage; + +/* Just a serie of int from 0 to MAX_CLAY_MAT-1 */ +static int ubo_mat_idxs[MAX_CLAY_MAT] = {0}; + +/* keep it under MAX_STORAGE */ +typedef struct CLAY_StorageList { + struct CLAY_Storage *storage; + struct GPUUniformBuffer *mat_ubo; +} CLAY_StorageList; + +/* keep it under MAX_BUFFERS */ +typedef struct CLAY_FramebufferList { + /* default */ + struct GPUFrameBuffer *default_fb; + /* engine specific */ + struct GPUFrameBuffer *dupli_depth; +} CLAY_FramebufferList; + +/* keep it under MAX_TEXTURES */ +typedef struct CLAY_TextureList { + /* default */ + struct GPUTexture *color; + struct GPUTexture *depth; + /* engine specific */ + struct GPUTexture *depth_dup; +} CLAY_TextureList; + +/* for clarity follow the same layout as CLAY_TextureList */ +enum { + SCENE_COLOR, + SCENE_DEPTH, + SCENE_DEPTH_DUP, +}; + +/* keep it under MAX_PASSES */ +typedef struct CLAY_PassList { + struct DRWPass *depth_pass; + struct DRWPass *depth_pass_cull; + struct DRWPass *clay_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(void) +{ + CLAY_StorageList *stl = DRW_engine_storage_list_get(); + CLAY_TextureList *txl = DRW_engine_texture_list_get(); + CLAY_FramebufferList *fbl = DRW_engine_framebuffer_list_get(); + + /* 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(); + } + + /* 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); + } + + if (!stl->storage) { + stl->storage = MEM_callocN(sizeof(CLAY_Storage), "CLAY_Storage"); + } + + if (!stl->mat_ubo) { + stl->mat_ubo = DRW_uniformbuffer_create(sizeof(CLAY_UBO_Storage), NULL); + } + + if (ubo_mat_idxs[1] == 0) { + /* Just int to have pointers to them */ + for (int i = 0; i < MAX_CLAY_MAT; ++i) { + ubo_mat_idxs[i] = i; + } + } + + { + float *viewport_size = DRW_viewport_size_get(); + DRWFboTexture tex = {&txl->depth_dup, DRW_BUF_DEPTH_24}; + DRW_framebuffer_init(&fbl->dupli_depth, + (int)viewport_size[0], (int)viewport_size[1], + &tex, 1); + } + + /* SSAO setup */ + { + 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 *material_id) +{ + const int depthloc = 0, matcaploc = 1, jitterloc = 2, sampleloc = 3; + + 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_DUP, 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, "mat_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 int search_mat_to_ubo(CLAY_Storage *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) +{ + /* For now just use a linear search and test all parameters */ + /* TODO make a hash table */ + for (int i = 0; i < storage->ubo_current_id; ++i) { + CLAY_UBO_Material *ubo = &storage->mat_storage.materials[i]; + + if ((ubo->matcap_rot[0] == cosf(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))) + { + return i; + } + } + + return -1; +} + +static int push_mat_to_ubo(CLAY_Storage *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) +{ + int id = storage->ubo_current_id; + CLAY_UBO_Material *ubo = &storage->mat_storage.materials[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); + + storage->ubo_current_id++; + + return id; +} + +static int mat_in_ubo(CLAY_Storage *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) +{ + /* Search material in UBO */ + int id = search_mat_to_ubo(storage, matcap_rot, matcap_hue, matcap_sat, matcap_val, + ssao_distance, ssao_factor_cavity, ssao_factor_edge, + ssao_attenuation, matcap_icon); + + /* if not found create it */ + if (id == -1) { + id = push_mat_to_ubo(storage, matcap_rot, matcap_hue, matcap_sat, matcap_val, + ssao_distance, ssao_factor_cavity, ssao_factor_edge, + ssao_attenuation, matcap_icon); + } + + return id; +} + +/* Safe way to get override values */ +static void override_setting(CollectionEngineSettings *ces, const char *name, void *ret) +{ + CollectionEngineProperty *cep = BKE_collection_engine_property_get(ces, name); + + if (cep == NULL) { + return; + } + + if ((cep->flag & COLLECTION_PROP_USE) == 0) { + return; + } + + if (cep->type == COLLECTION_PROP_TYPE_INT) { + CollectionEnginePropertyInt *prop = (CollectionEnginePropertyInt *)cep; + *((int *)ret) = prop->value; + } + else if (cep->type == COLLECTION_PROP_TYPE_FLOAT) { + CollectionEnginePropertyFloat *prop = (CollectionEnginePropertyFloat *)cep; + *((float *)ret) = prop->value; + } + else if (cep->type == COLLECTION_PROP_TYPE_BOOL) { + CollectionEnginePropertyBool *prop = (CollectionEnginePropertyBool *)cep; + *((bool *)ret) = prop->value; + } +} + +static DRWShadingGroup *CLAY_object_shgrp_get(Object *ob, CLAY_StorageList *stl, CLAY_PassList *psl) +{ + DRWShadingGroup **shgrps = stl->storage->shgrps; + MaterialEngineSettingsClay *settings = DRW_render_settings_get(NULL, RE_engine_id_BLENDER_CLAY); + CollectionEngineSettings *ces = BKE_object_collection_engine_get(ob, COLLECTION_MODE_NONE, RE_engine_id_BLENDER_CLAY); + + /* Default Settings */ + float matcap_rot = settings->matcap_rot; + float matcap_hue = settings->matcap_hue; + float matcap_sat = settings->matcap_sat; + float matcap_val = settings->matcap_val; + float ssao_distance = settings->ssao_distance; + float ssao_factor_cavity = settings->ssao_factor_cavity; + float ssao_factor_edge = settings->ssao_factor_edge; + float ssao_attenuation = settings->ssao_attenuation; + int matcap_icon = settings->matcap_icon; + + /* Override settings */ + if (ces) { + override_setting(ces, "matcap_rotation", &matcap_rot); + override_setting(ces, "matcap_hue", &matcap_hue); + override_setting(ces, "matcap_saturation", &matcap_sat); + override_setting(ces, "matcap_value", &matcap_val); + override_setting(ces, "ssao_distance", &ssao_distance); + override_setting(ces, "ssao_factor_cavity", &ssao_factor_cavity); + override_setting(ces, "ssao_factor_edge", &ssao_factor_edge); + override_setting(ces, "ssao_attenuation", &ssao_attenuation); + override_setting(ces, "matcap_icon", &matcap_icon); + } + + int id = mat_in_ubo(stl->storage, matcap_rot, matcap_hue, matcap_sat, matcap_val, + ssao_distance, ssao_factor_cavity, ssao_factor_edge, + ssao_attenuation, matcap_icon); + + if (shgrps[id] == NULL) { + shgrps[id] = CLAY_shgroup_create(psl->clay_pass, &ubo_mat_idxs[id]); + /* if it's the first shgrp, pass bind the material UBO */ + if (stl->storage->ubo_current_id == 1) { + DRW_shgroup_uniform_block(shgrps[0], "material_block", stl->mat_ubo, 0); + } + } + + return shgrps[id]; +} + +static DRWShadingGroup *depth_shgrp; +static DRWShadingGroup *depth_shgrp_cull; + +static void CLAY_cache_init(void) +{ + CLAY_PassList *psl = DRW_engine_pass_list_get(); + CLAY_StorageList *stl = DRW_engine_storage_list_get(); + + + /* Depth Pass */ + { + psl->depth_pass_cull = DRW_pass_create("Depth Pass Cull", DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS | DRW_STATE_CULL_BACK); + psl->depth_pass = DRW_pass_create("Depth Pass", DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS); + + depth_shgrp_cull = DRW_shgroup_create(data.depth_sh, psl->depth_pass_cull); + depth_shgrp = DRW_shgroup_create(data.depth_sh, psl->depth_pass); + } + + /* Clay Pass */ + { + psl->clay_pass = DRW_pass_create("Clay Pass", DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_EQUAL); + stl->storage->ubo_current_id = 0; + memset(stl->storage->shgrps, 0, sizeof(DRWShadingGroup *) * MAX_CLAY_MAT); + } +} + +static void CLAY_cache_populate(Object *ob) +{ + const bContext *C = DRW_get_context(); + int mode = CTX_data_mode_enum(C); + CLAY_StorageList *stl = DRW_engine_storage_list_get(); + CLAY_PassList *psl = DRW_engine_pass_list_get(); + struct Batch *geom; + DRWShadingGroup *clay_shgrp; + bool do_occlude_wire = false; + bool do_cull = false; + CollectionEngineSettings *ces_mode_ed, *ces_mode_ob; + + switch (mode) { + case CTX_MODE_EDIT_MESH: + case CTX_MODE_EDIT_CURVE: + case CTX_MODE_EDIT_SURFACE: + case CTX_MODE_EDIT_TEXT: + case CTX_MODE_EDIT_ARMATURE: + case CTX_MODE_EDIT_METABALL: + case CTX_MODE_EDIT_LATTICE: + case CTX_MODE_POSE: + case CTX_MODE_SCULPT: + case CTX_MODE_PAINT_WEIGHT: + case CTX_MODE_PAINT_VERTEX: + case CTX_MODE_PAINT_TEXTURE: + case CTX_MODE_PARTICLE: + ces_mode_ed = BKE_object_collection_engine_get(ob, COLLECTION_MODE_EDIT, ""); + do_occlude_wire = BKE_collection_engine_property_value_get_bool(ces_mode_ed, "show_occlude_wire"); + break; + case CTX_MODE_OBJECT: + ces_mode_ob = BKE_object_collection_engine_get(ob, COLLECTION_MODE_OBJECT, ""); + do_cull = BKE_collection_engine_property_value_get_bool(ces_mode_ob, "show_backface_culling"); + break; + } + + if (do_occlude_wire) + return; + + switch (ob->type) { + case OB_MESH: + geom = DRW_cache_surface_get(ob); + + /* Depth Prepass */ + DRW_shgroup_call_add((do_cull) ? depth_shgrp_cull : depth_shgrp, geom, ob->obmat); + + /* Shading */ + clay_shgrp = CLAY_object_shgrp_get(ob, stl, psl); + DRW_shgroup_call_add(clay_shgrp, geom, ob->obmat); + break; + } +} + +static void CLAY_cache_finish(void) +{ + CLAY_StorageList *stl = DRW_engine_storage_list_get(); + + DRW_uniformbuffer_update(stl->mat_ubo, &stl->storage->mat_storage); +} + +static void CLAY_view_draw(RenderEngine *UNUSED(engine), const bContext *context) +{ + DRW_viewport_init(context); + + /* This function may run for multiple viewports + * so get the current viewport buffers */ + CLAY_PassList *psl = DRW_engine_pass_list_get(); + CLAY_FramebufferList *fbl = DRW_engine_framebuffer_list_get(); + + CLAY_engine_init(); + + /* TODO : tag to refresh by the deps graph */ + /* ideally only refresh when objects are added/removed */ + /* or render properties / materials change */ + if (DRW_viewport_cache_is_dirty()) { + + SceneLayer *sl = CTX_data_scene_layer(context); + + CLAY_cache_init(); + DRW_mode_cache_init(); + + DEG_OBJECT_ITER(sl, ob); + { + CLAY_cache_populate(ob); + DRW_mode_cache_populate(ob); + } + DEG_OBJECT_ITER_END + + CLAY_cache_finish(); + DRW_mode_cache_finish(); + } + + /* Start Drawing */ + DRW_draw_background(); + + /* Pass 1 : Depth pre-pass */ + DRW_draw_pass(psl->depth_pass); + DRW_draw_pass(psl->depth_pass_cull); + + /* Pass 2 : Duplicate depth */ + /* Unless we go for deferred shading we need this to avoid manual depth test and artifacts */ + DRW_framebuffer_blit(fbl->default_fb, fbl->dupli_depth, true); + + /* Pass 3 : Shading */ + DRW_draw_pass(psl->clay_pass); + + /* Pass 4 : Overlays */ + /* At this point all shaded geometry should have been rendered and their depth written */ + DRW_draw_mode_overlays(); + + /* 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); +} + +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); + } +} + +RenderEngineType viewport_clay_type = { + NULL, NULL, + CLAY_ENGINE, N_("Clay"), RE_INTERNAL | RE_USE_OGL_PIPELINE, + NULL, NULL, NULL, NULL, &CLAY_view_draw, NULL, &CLAY_collection_settings_create, + {NULL, NULL, NULL} +}; + + +#undef CLAY_ENGINE + +#endif diff --git a/source/blender/draw/engines/clay/clay.h b/source/blender/draw/engines/clay/clay.h new file mode 100644 index 00000000000..add2a45fbd7 --- /dev/null +++ b/source/blender/draw/engines/clay/clay.h @@ -0,0 +1,36 @@ +/* + * Copyright 2016, Blender Foundation. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Contributor(s): Blender Institute + * + */ + +/** \file clay.h + * \ingroup DNA + */ + +#ifndef __CLAY_H__ +#define __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 /* __CLAY_H__ */ 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..35d803dc9ef --- /dev/null +++ b/source/blender/draw/engines/clay/shaders/clay_frag.glsl @@ -0,0 +1,191 @@ +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]; +}; + +uniform 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; + } +} + +#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); + +#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..7ad1c309581 --- /dev/null +++ b/source/blender/draw/intern/DRW_render.h @@ -0,0 +1,234 @@ +/* + * 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 "draw_view.h" + +#include "MEM_guardedalloc.h" + +#include "RE_engine.h" + +struct bContext; +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); +void DRW_framebuffer_blit(struct GPUFrameBuffer *fb_read, struct GPUFrameBuffer *fb_write, bool depth); +/* 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; + +DRWShadingGroup *DRW_shgroup_create(struct GPUShader *shader, DRWPass *pass); +DRWShadingGroup *DRW_shgroup_instance_create(struct GPUShader *shader, DRWPass *pass, struct Batch *geom); +DRWShadingGroup *DRW_shgroup_point_batch_create(struct GPUShader *shader, DRWPass *pass); +DRWShadingGroup *DRW_shgroup_line_batch_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_dynamic_call_add(DRWShadingGroup *shgroup, ...); +void DRW_shgroup_state_set(DRWShadingGroup *shgroup, DRWState state); +void DRW_shgroup_attrib_int(DRWShadingGroup *shgroup, const char *name, int size); +void DRW_shgroup_attrib_float(DRWShadingGroup *shgroup, const char *name, int size); + +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); + +/* Viewport */ +typedef enum { + DRW_MAT_PERS, + DRW_MAT_WIEW, + DRW_MAT_WIN, +} DRWViewportMatrixType; + +void DRW_viewport_init(const bContext *C); +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__ */ + +/* Cache */ +void DRW_mode_cache_init(void); +void DRW_mode_cache_populate(struct Object *ob); +void DRW_mode_cache_finish(void); + +/* Draw commands */ +void DRW_draw_pass(DRWPass *pass); +void DRW_draw_mode_overlays(void); + +void DRW_state_reset(void); + +/* Other */ +void DRW_get_dfdy_factors(float dfdyfac[2]); +const struct bContext *DRW_get_context(void); +void *DRW_engine_pass_list_get(void); +void *DRW_engine_storage_list_get(void); +void *DRW_engine_texture_list_get(void); +void *DRW_engine_framebuffer_list_get(void); +void *DRW_mode_pass_list_get(void); +void *DRW_mode_storage_list_get(void); +void *DRW_mode_texture_list_get(void); +void *DRW_mode_framebuffer_list_get(void); +#endif /* __DRW_RENDER_H__ */ diff --git a/source/blender/draw/intern/draw_armature.c b/source/blender/draw/intern/draw_armature.c new file mode 100644 index 00000000000..68d1b3d7ea4 --- /dev/null +++ b/source/blender/draw/intern/draw_armature.c @@ -0,0 +1,323 @@ +/* + * 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_armature.c + * \ingroup draw + */ + +#include <stdlib.h> +#include <string.h> +#include <math.h> + +#include "DNA_anim_types.h" +#include "DNA_armature_types.h" +#include "DNA_constraint_types.h" +#include "DNA_scene_types.h" +#include "DNA_screen_types.h" +#include "DNA_view3d_types.h" +#include "DNA_object_types.h" + +#include "BLI_blenlib.h" +#include "BLI_math.h" +#include "BLI_dlrbTree.h" +#include "BLI_utildefines.h" + +#include "BKE_animsys.h" +#include "BKE_action.h" +#include "BKE_armature.h" +#include "BKE_global.h" +#include "BKE_modifier.h" +#include "BKE_nla.h" +#include "BKE_curve.h" + +#include "BIF_gl.h" +#include "BIF_glutil.h" + +#include "ED_armature.h" +#include "ED_keyframes_draw.h" + +#include "UI_resources.h" + +#include "draw_mode_pass.h" + +#define BONE_VAR(eBone, pchan, var) ((eBone) ? (eBone->var) : (pchan->var)) +#define BONE_FLAG(eBone, pchan) ((eBone) ? (eBone->flag) : (pchan->bone->flag)) + +/* *************** Armature Drawing - Coloring API ***************************** */ + +static float colorBoneSolid[4]; +static float colorTextHi[4]; +static float colorText[4]; +static float colorVertexSelect[4]; +static float colorVertex[4]; + +static const float *constColor; + +static void update_color(const float const_color[4]) +{ + constColor = const_color; + + UI_GetThemeColor4fv(TH_BONE_SOLID, colorBoneSolid); + UI_GetThemeColor4fv(TH_TEXT_HI, colorTextHi); + UI_GetThemeColor4fv(TH_TEXT, colorText); + UI_GetThemeColor4fv(TH_VERTEX_SELECT, colorVertexSelect); + UI_GetThemeColor4fv(TH_VERTEX, colorVertex); +} + +static const float *get_bone_solid_color(EditBone *eBone, bPoseChannel *pchan, bArmature *arm) +{ + if (constColor) + return colorBoneSolid; + + /* Edit Mode */ + if (eBone) { + if (eBone->flag & BONE_SELECTED) + return colorVertexSelect; + } + + return colorBoneSolid; +} + +static const float *get_bone_wire_color(EditBone *eBone, bPoseChannel *pchan, bArmature *arm) +{ + if (constColor) + return constColor; + + if (eBone) { + if (eBone->flag & BONE_SELECTED) + return colorVertexSelect; + } + + return colorVertex; +} + +/* *************** Armature drawing, helper calls for parts ******************* */ + +static void draw_bone_update_disp_matrix(EditBone *eBone, bPoseChannel *pchan, int drawtype) +{ + float s[4][4], ebmat[4][4]; + float length; + float (*bone_mat)[4]; + float (*disp_mat)[4]; + float (*disp_tail_mat)[4]; + + /* TODO : This should be moved to depsgraph or armature refresh + * and not be tight to the draw pass creation. + * This would refresh armature without invalidating the draw cache */ + if (pchan) { + length = pchan->bone->length; + bone_mat = pchan->pose_mat; + disp_mat = pchan->disp_mat; + disp_tail_mat = pchan->disp_tail_mat; + } + else { + eBone->length = len_v3v3(eBone->tail, eBone->head); + ED_armature_ebone_to_mat4(eBone, ebmat); + + length = eBone->length; + bone_mat = ebmat; + disp_mat = eBone->disp_mat; + disp_tail_mat = eBone->disp_tail_mat; + } + + if (pchan && pchan->custom) { + /* TODO */ + } + else if (drawtype == ARM_ENVELOPE) { + /* TODO */ + } + else if (drawtype == ARM_LINE) { + /* TODO */ + } + else if (drawtype == ARM_WIRE) { + /* TODO */ + } + else if (drawtype == ARM_B_BONE) { + /* TODO */ + } + else { + scale_m4_fl(s, length); + mul_m4_m4m4(disp_mat, bone_mat, s); + copy_m4_m4(disp_tail_mat, disp_mat); + translate_m4(disp_tail_mat, 0.0f, 1.0f, 0.0f); + } +} + +static void draw_axes(EditBone *eBone, bPoseChannel *pchan) +{ + const float *col = (constColor) ? constColor : + (BONE_FLAG(eBone, pchan) & BONE_SELECTED) ? colorTextHi : colorText; + + DRW_shgroup_bone_axes(BONE_VAR(eBone, pchan, disp_tail_mat), col); +} + +static void draw_points(EditBone *eBone, bPoseChannel *pchan, bArmature *arm) +{ + const float *col_solid_root = colorBoneSolid; + const float *col_solid_tail = colorBoneSolid; + const float *col_wire_root = (constColor) ? constColor : colorVertex; + const float *col_wire_tail = (constColor) ? constColor : colorVertex; + + /* Edit bone points can be selected */ + if (eBone) { + if (eBone->flag & BONE_ROOTSEL) { + col_solid_root = colorVertexSelect; + col_wire_root = colorVertexSelect; + } + if (eBone->flag & BONE_TIPSEL) { + col_solid_tail = colorVertexSelect; + col_wire_tail = colorVertexSelect; + } + } + + /* Draw root point if we are not connected and parent are not hidden */ + if ((BONE_FLAG(eBone, pchan) & BONE_CONNECTED) == 0) { + if (eBone) { + if (!((eBone->parent) && !EBONE_VISIBLE(arm, eBone->parent))) { + DRW_shgroup_bone_point_solid(eBone->disp_mat, col_solid_root); + DRW_shgroup_bone_point_wire(eBone->disp_mat, col_wire_root); + } + } + else { + Bone *bone = pchan->bone; + if (!((bone->parent) && (bone->parent->flag & (BONE_HIDDEN_P | BONE_HIDDEN_PG)))) { + DRW_shgroup_bone_point_solid(pchan->disp_mat, col_solid_root); + DRW_shgroup_bone_point_wire(pchan->disp_mat, col_wire_root); + } + } + } + + /* Draw tip point */ + DRW_shgroup_bone_point_solid(BONE_VAR(eBone, pchan, disp_tail_mat), col_solid_tail); + DRW_shgroup_bone_point_wire(BONE_VAR(eBone, pchan, disp_tail_mat), col_wire_tail); +} + +static void draw_bone_custom_shape(EditBone *eBone, bPoseChannel *pchan, bArmature *arm) +{ +} + +static void draw_bone_envelope(EditBone *eBone, bPoseChannel *pchan, bArmature *arm) +{ +} + +static void draw_bone_line(EditBone *eBone, bPoseChannel *pchan, bArmature *arm) +{ +} + +static void draw_bone_wire(EditBone *eBone, bPoseChannel *pchan, bArmature *arm) +{ +} + +static void draw_bone_box(EditBone *eBone, bPoseChannel *pchan, bArmature *arm) +{ +} + +static void draw_bone_octahedral(EditBone *eBone, bPoseChannel *pchan, bArmature *arm) +{ + const float *col_solid = get_bone_solid_color(eBone, pchan, arm); + const float *col_wire = get_bone_wire_color(eBone, pchan, arm); + + DRW_shgroup_bone_octahedral_solid(BONE_VAR(eBone, pchan, disp_mat), col_solid); + DRW_shgroup_bone_octahedral_wire(BONE_VAR(eBone, pchan, disp_mat), col_wire); + + draw_points(eBone, pchan, arm); +} + +void draw_armature_edit(Object *ob) +{ + EditBone *eBone; + bArmature *arm = ob->data; + unsigned int index; + + update_color(NULL); + + for (eBone = arm->edbo->first, index = 0; eBone; eBone = eBone->next, index++) { + if (eBone->layer & arm->layer) { + if ((eBone->flag & BONE_HIDDEN_A) == 0) { + + draw_bone_update_disp_matrix(eBone, NULL, arm->drawtype); + + if (arm->drawtype == ARM_ENVELOPE) + draw_bone_envelope(eBone, NULL, arm); + else if (arm->drawtype == ARM_LINE) + draw_bone_line(eBone, NULL, arm); + else if (arm->drawtype == ARM_WIRE) + draw_bone_wire(eBone, NULL, arm); + else if (arm->drawtype == ARM_B_BONE) + draw_bone_box(eBone, NULL, arm); + else + draw_bone_octahedral(eBone, NULL, arm); + + /* Draw additional axes */ + if (arm->flag & ARM_DRAWAXES) + draw_axes(eBone, NULL); + } + } + } +} + +/* if const_color is NULL do pose mode coloring */ +void draw_armature_pose(Object *ob, const float const_color[4]) +{ + bArmature *arm = ob->data; + bPoseChannel *pchan; + Bone *bone; + + update_color(const_color); + + /* We can't safely draw non-updated pose, might contain NULL bone pointers... */ + if (ob->pose->flag & POSE_RECALC) { + BKE_pose_rebuild(ob, arm); + } + + /* being set below */ + arm->layer_used = 0; + + for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) { + bone = pchan->bone; + arm->layer_used |= bone->layer; + + /* bone must be visible */ + if ((bone->flag & (BONE_HIDDEN_P | BONE_HIDDEN_PG)) == 0) { + if (bone->layer & arm->layer) { + + draw_bone_update_disp_matrix(NULL, pchan, arm->drawtype); + + if ((pchan->custom) && !(arm->flag & ARM_NO_CUSTOM)) + draw_bone_custom_shape(NULL, pchan, arm); + else if (arm->drawtype == ARM_ENVELOPE) + draw_bone_envelope(NULL, pchan, arm); + else if (arm->drawtype == ARM_LINE) + draw_bone_line(NULL, pchan, arm); + else if (arm->drawtype == ARM_WIRE) + draw_bone_wire(NULL, pchan, arm); + else if (arm->drawtype == ARM_B_BONE) + draw_bone_box(NULL, pchan, arm); + else + draw_bone_octahedral(NULL, pchan, arm); + + /* Draw additional axes */ + if (arm->flag & ARM_DRAWAXES) + draw_axes(NULL, pchan); + } + } + } +}
\ 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..4f9b4926fb6 --- /dev/null +++ b/source/blender/draw/intern/draw_cache.c @@ -0,0 +1,913 @@ +/* + * 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_cube; + Batch *drw_circle; + Batch *drw_line; + Batch *drw_empty_sphere; + Batch *drw_empty_cone; + Batch *drw_arrows; + Batch *drw_axis_names; + Batch *drw_lamp; + Batch *drw_lamp_sunrays; + Batch *drw_speaker; + Batch *drw_bone_octahedral; + Batch *drw_bone_octahedral_wire; + Batch *drw_bone_point; + Batch *drw_bone_point_wire; + Batch *drw_bone_arrows; +} 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_cube) + Batch_discard_all(SHC.drw_cube); + if (SHC.drw_circle) + Batch_discard_all(SHC.drw_circle); + if (SHC.drw_line) + Batch_discard_all(SHC.drw_line); + 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_axis_names) + Batch_discard_all(SHC.drw_axis_names); + if (SHC.drw_lamp) + Batch_discard_all(SHC.drw_lamp); + if (SHC.drw_lamp_sunrays) + Batch_discard_all(SHC.drw_lamp_sunrays); + if (SHC.drw_speaker) + Batch_discard_all(SHC.drw_speaker); + if (SHC.drw_bone_octahedral) + Batch_discard_all(SHC.drw_bone_octahedral); + if (SHC.drw_bone_octahedral_wire) + Batch_discard_all(SHC.drw_bone_octahedral_wire); + if (SHC.drw_bone_point) + Batch_discard_all(SHC.drw_bone_point); + if (SHC.drw_bone_point_wire) + Batch_discard_all(SHC.drw_bone_point_wire); + if (SHC.drw_bone_arrows) + Batch_discard_all(SHC.drw_bone_arrows); +} + +/* Helper functions */ + +static void add_fancy_edge(VertexBuffer *vbo, unsigned int pos_id, unsigned int n1_id, unsigned int n2_id, + unsigned int *v_idx, const float co1[3], const float co2[3], + const float n1[3], const float n2[3]) +{ + setAttrib(vbo, n1_id, *v_idx, n1); + setAttrib(vbo, n2_id, *v_idx, n2); + setAttrib(vbo, pos_id, (*v_idx)++, co1); + + setAttrib(vbo, n1_id, *v_idx, n1); + setAttrib(vbo, n2_id, *v_idx, n2); + setAttrib(vbo, pos_id, (*v_idx)++, co2); +} + +static void add_lat_lon_vert(VertexBuffer *vbo, unsigned int pos_id, unsigned int nor_id, + unsigned int *v_idx, const float rad, const float lat, const float lon) +{ + float pos[3], nor[3]; + nor[0] = sinf(lat) * cosf(lon); + nor[1] = cosf(lat); + nor[2] = sinf(lat) * sinf(lon); + mul_v3_v3fl(pos, nor, rad); + + setAttrib(vbo, nor_id, *v_idx, nor); + setAttrib(vbo, pos_id, (*v_idx)++, pos); +} + +static VertexBuffer *fill_arrows_vbo(const float scale) +{ + /* 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); + + float v1[3] = {0.0, 0.0, 0.0}; + float v2[3] = {0.0, 0.0, 0.0}; + float vtmp1[3], vtmp2[3]; + + for (int axis = 0; axis < 3; axis++) { + const int arrow_axis = (axis == 0) ? 1 : 0; + + v2[axis] = 1.0f; + mul_v3_v3fl(vtmp1, v1, scale); + mul_v3_v3fl(vtmp2, v2, scale); + setAttrib(vbo, pos_id, axis * 6 + 0, vtmp1); + setAttrib(vbo, pos_id, axis * 6 + 1, vtmp2); + + v1[axis] = 0.85f; + v1[arrow_axis] = -0.08f; + mul_v3_v3fl(vtmp1, v1, scale); + mul_v3_v3fl(vtmp2, v2, scale); + setAttrib(vbo, pos_id, axis * 6 + 2, vtmp1); + setAttrib(vbo, pos_id, axis * 6 + 3, vtmp2); + + v1[arrow_axis] = 0.08f; + mul_v3_v3fl(vtmp1, v1, scale); + mul_v3_v3fl(vtmp2, v2, scale); + setAttrib(vbo, pos_id, axis * 6 + 4, vtmp1); + setAttrib(vbo, pos_id, axis * 6 + 5, vtmp2); + + /* reset v1 & v2 to zero */ + v1[arrow_axis] = v1[axis] = v2[axis] = 0.0f; + } + + return vbo; +} + +static VertexBuffer *sphere_wire_vbo(const float rad) +{ +#define NSEGMENTS 16 + /* 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); + + /* 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] = rad * cosf(angle); + p[i][1] = rad * sinf(angle); + } + + 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); + } + } + } + + return vbo; +#undef NSEGMENTS +} + +/* 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[2] = cosf((2.0f * M_PI * a) / ((float)CIRCLE_RESOL)); + v[1] = 0.0f; + setAttrib(vbo, pos_id, a * 2, v); + + v[0] = sinf((2.0f * M_PI * (a + 1)) / ((float)CIRCLE_RESOL)); + v[2] = cosf((2.0f * M_PI * (a + 1)) / ((float)CIRCLE_RESOL)); + v[1] = 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 +} + +Batch *DRW_cache_single_line_get(void) +{ + /* Z axis line */ + if (!SHC.drw_line) { + float v1[3] = {0.0f, 0.0f, 0.0f}; + float v2[3] = {0.0f, 0.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, 2); + + setAttrib(vbo, pos_id, 0, v1); + setAttrib(vbo, pos_id, 1, v2); + + SHC.drw_line = Batch_create(GL_LINES, vbo, NULL); + } + return SHC.drw_line; +} + +/* 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(void) +{ + if (!SHC.drw_single_arrow) { + float v1[3] = {0.0f, 0.0f, 1.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); + } + + /* Square Pyramid */ + VertexBuffer *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); + } + return SHC.drw_single_arrow; +} + +Batch *DRW_cache_empty_sphere_get(void) +{ + if (!SHC.drw_empty_sphere) { + VertexBuffer *vbo = sphere_wire_vbo(1.0f); + SHC.drw_empty_sphere = Batch_create(GL_LINES, vbo, NULL); + } + return SHC.drw_empty_sphere; +} + +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) { + VertexBuffer *vbo = fill_arrows_vbo(1.0f); + + SHC.drw_arrows = Batch_create(GL_LINES, vbo, NULL); + } + return SHC.drw_arrows; +} + +Batch *DRW_cache_axis_names_get(void) +{ + if (!SHC.drw_axis_names) { + const float size = 0.1f; + float v1[3], v2[3]; + + /* Position Only 3D format */ + static VertexFormat format = { 0 }; + static unsigned pos_id; + if (format.attrib_ct == 0) { + /* Using 3rd component as axis indicator */ + pos_id = add_attrib(&format, "pos", GL_FLOAT, 3, KEEP_FLOAT); + } + + /* Line */ + VertexBuffer *vbo = VertexBuffer_create_with_format(&format); + VertexBuffer_allocate_data(vbo, 14); + + /* X */ + copy_v3_fl3(v1, -size, size, 0.0f); + copy_v3_fl3(v2, size, -size, 0.0f); + setAttrib(vbo, pos_id, 0, v1); + setAttrib(vbo, pos_id, 1, v2); + + copy_v3_fl3(v1, size, size, 0.0f); + copy_v3_fl3(v2, -size, -size, 0.0f); + setAttrib(vbo, pos_id, 2, v1); + setAttrib(vbo, pos_id, 3, v2); + + /* Y */ + copy_v3_fl3(v1, -size + 0.25f * size, size, 1.0f); + copy_v3_fl3(v2, 0.0f, 0.0f, 1.0f); + setAttrib(vbo, pos_id, 4, v1); + setAttrib(vbo, pos_id, 5, v2); + + copy_v3_fl3(v1, size - 0.25f * size, size, 1.0f); + copy_v3_fl3(v2, -size + 0.25f * size, -size, 1.0f); + setAttrib(vbo, pos_id, 6, v1); + setAttrib(vbo, pos_id, 7, v2); + + /* Z */ + copy_v3_fl3(v1, -size, size, 2.0f); + copy_v3_fl3(v2, size, size, 2.0f); + setAttrib(vbo, pos_id, 8, v1); + setAttrib(vbo, pos_id, 9, v2); + + copy_v3_fl3(v1, size, size, 2.0f); + copy_v3_fl3(v2, -size, -size, 2.0f); + setAttrib(vbo, pos_id, 10, v1); + setAttrib(vbo, pos_id, 11, v2); + + copy_v3_fl3(v1, -size, -size, 2.0f); + copy_v3_fl3(v2, size, -size, 2.0f); + setAttrib(vbo, pos_id, 12, v1); + setAttrib(vbo, pos_id, 13, v2); + + SHC.drw_axis_names = Batch_create(GL_LINES, vbo, NULL); + } + return SHC.drw_axis_names; +} + +/* 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; +} + +/* Speaker */ +Batch *DRW_cache_speaker_get(void) +{ + if (!SHC.drw_speaker) { + float v[3]; + const int segments = 16; + int vidx = 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); + } + + VertexBuffer *vbo = VertexBuffer_create_with_format(&format); + VertexBuffer_allocate_data(vbo, 3 * segments * 2 + 4 * 4); + + for (int j = 0; j < 3; j++) { + float z = 0.25f * j - 0.125f; + float r = (j == 0 ? 0.5f : 0.25f); + + copy_v3_fl3(v, r, 0.0f, z); + setAttrib(vbo, pos_id, vidx++, v); + for (int i = 1; i < segments; i++) { + float x = cosf(2.f * (float)M_PI * i / segments) * r; + float y = sinf(2.f * (float)M_PI * i / segments) * r; + copy_v3_fl3(v, x, y, z); + setAttrib(vbo, pos_id, vidx++, v); + setAttrib(vbo, pos_id, vidx++, v); + } + copy_v3_fl3(v, r, 0.0f, z); + setAttrib(vbo, pos_id, vidx++, v); + } + + for (int j = 0; j < 4; j++) { + float x = (((j + 1) % 2) * (j - 1)) * 0.5f; + float y = ((j % 2) * (j - 2)) * 0.5f; + for (int i = 0; i < 3; i++) { + if (i == 1) { + x *= 0.5f; + y *= 0.5f; + } + + float z = 0.25f * i - 0.125f; + copy_v3_fl3(v, x, y, z); + setAttrib(vbo, pos_id, vidx++, v); + if (i == 1) { + setAttrib(vbo, pos_id, vidx++, v); + } + } + } + + SHC.drw_speaker = Batch_create(GL_LINES, vbo, NULL); + } + return SHC.drw_speaker; +} + +/* Armature bones */ +static const float bone_octahedral_verts[6][3] = { + { 0.0f, 0.0f, 0.0f}, + { 0.1f, 0.1f, 0.1f}, + { 0.1f, 0.1f, -0.1f}, + {-0.1f, 0.1f, -0.1f}, + {-0.1f, 0.1f, 0.1f}, + { 0.0f, 1.0f, 0.0f} +}; + +static const unsigned int bone_octahedral_wire[24] = { + 0, 1, 1, 5, 5, 3, 3, 0, + 0, 4, 4, 5, 5, 2, 2, 0, + 1, 2, 2, 3, 3, 4, 4, 1, +}; + +/* aligned with bone_octahedral_wire + * Contains adjacent normal index */ +static const unsigned int bone_octahedral_wire_adjacent_face[24] = { + 0, 3, 4, 7, 5, 6, 1, 2, + 2, 3, 6, 7, 4, 5, 0, 1, + 0, 4, 1, 5, 2, 6, 3, 7, +}; + +static const unsigned int bone_octahedral_solid_tris[8][3] = { + {2, 1, 0}, /* bottom */ + {3, 2, 0}, + {4, 3, 0}, + {1, 4, 0}, + + {5, 1, 2}, /* top */ + {5, 2, 3}, + {5, 3, 4}, + {5, 4, 1} +}; + +/* aligned with bone_octahedral_solid_tris */ +static const float bone_octahedral_solid_normals[8][3] = { + { M_SQRT1_2, -M_SQRT1_2, 0.00000000f}, + {-0.00000000f, -M_SQRT1_2, -M_SQRT1_2}, + {-M_SQRT1_2, -M_SQRT1_2, 0.00000000f}, + { 0.00000000f, -M_SQRT1_2, M_SQRT1_2}, + { 0.99388373f, 0.11043154f, -0.00000000f}, + { 0.00000000f, 0.11043154f, -0.99388373f}, + {-0.99388373f, 0.11043154f, 0.00000000f}, + { 0.00000000f, 0.11043154f, 0.99388373f} +}; + +Batch *DRW_cache_bone_octahedral_get(void) +{ + if (!SHC.drw_bone_octahedral) { + unsigned int v_idx = 0; + + static VertexFormat format = { 0 }; + static unsigned pos_id, nor_id; + if (format.attrib_ct == 0) { + pos_id = add_attrib(&format, "pos", GL_FLOAT, 3, KEEP_FLOAT); + nor_id = add_attrib(&format, "nor", GL_FLOAT, 3, KEEP_FLOAT); + } + + /* Vertices */ + VertexBuffer *vbo = VertexBuffer_create_with_format(&format); + VertexBuffer_allocate_data(vbo, 24); + + for (int i = 0; i < 8; i++) { + setAttrib(vbo, nor_id, v_idx, bone_octahedral_solid_normals[i]); + setAttrib(vbo, pos_id, v_idx++, bone_octahedral_verts[bone_octahedral_solid_tris[i][0]]); + setAttrib(vbo, nor_id, v_idx, bone_octahedral_solid_normals[i]); + setAttrib(vbo, pos_id, v_idx++, bone_octahedral_verts[bone_octahedral_solid_tris[i][1]]); + setAttrib(vbo, nor_id, v_idx, bone_octahedral_solid_normals[i]); + setAttrib(vbo, pos_id, v_idx++, bone_octahedral_verts[bone_octahedral_solid_tris[i][2]]); + } + + SHC.drw_bone_octahedral = Batch_create(GL_TRIANGLES, vbo, NULL); + } + return SHC.drw_bone_octahedral; +} + +Batch *DRW_cache_bone_octahedral_wire_outline_get(void) +{ + if (!SHC.drw_bone_octahedral_wire) { + unsigned int v_idx = 0; + + static VertexFormat format = { 0 }; + static unsigned pos_id, n1_id, n2_id; + if (format.attrib_ct == 0) { + pos_id = add_attrib(&format, "pos", GL_FLOAT, 3, KEEP_FLOAT); + n1_id = add_attrib(&format, "N1", COMP_F32, 3, KEEP_FLOAT); + n2_id = add_attrib(&format, "N2", COMP_F32, 3, KEEP_FLOAT); + } + + /* Vertices */ + VertexBuffer *vbo = VertexBuffer_create_with_format(&format); + VertexBuffer_allocate_data(vbo, 12 * 2); + + for (int i = 0; i < 12; i++) { + const float *co1 = bone_octahedral_verts[bone_octahedral_wire[i * 2]]; + const float *co2 = bone_octahedral_verts[bone_octahedral_wire[i * 2 + 1]]; + const float *n1 = bone_octahedral_solid_normals[bone_octahedral_wire_adjacent_face[i * 2]]; + const float *n2 = bone_octahedral_solid_normals[bone_octahedral_wire_adjacent_face[i * 2 + 1]]; + add_fancy_edge(vbo, pos_id, n1_id, n2_id, &v_idx, co1, co2, n1, n2); + } + + SHC.drw_bone_octahedral_wire = Batch_create(GL_LINES, vbo, NULL); + } + return SHC.drw_bone_octahedral_wire; +} + +Batch *DRW_cache_bone_point_get(void) +{ + if (!SHC.drw_bone_point) { + const int lon_res = 16; + const int lat_res = 8; + const float rad = 0.05f; + const float lon_inc = 2 * M_PI / lon_res; + const float lat_inc = M_PI / lat_res; + unsigned int v_idx = 0; + + static VertexFormat format = { 0 }; + static unsigned pos_id, nor_id; + if (format.attrib_ct == 0) { + pos_id = add_attrib(&format, "pos", GL_FLOAT, 3, KEEP_FLOAT); + nor_id = add_attrib(&format, "nor", GL_FLOAT, 3, KEEP_FLOAT); + } + + /* Vertices */ + VertexBuffer *vbo = VertexBuffer_create_with_format(&format); + VertexBuffer_allocate_data(vbo, (lat_res - 1) * lon_res * 6); + + float lon = 0.0f; + for (int i = 0; i < lon_res; i++, lon += lon_inc) { + float lat = 0.0f; + for (int j = 0; j < lat_res; j++, lat += lat_inc) { + if (j != lat_res - 1) { /* Pole */ + add_lat_lon_vert(vbo, pos_id, nor_id, &v_idx, rad, lat + lat_inc, lon + lon_inc); + add_lat_lon_vert(vbo, pos_id, nor_id, &v_idx, rad, lat + lat_inc, lon); + add_lat_lon_vert(vbo, pos_id, nor_id, &v_idx, rad, lat, lon); + } + + if (j != 0) { /* Pole */ + add_lat_lon_vert(vbo, pos_id, nor_id, &v_idx, rad, lat, lon + lon_inc); + add_lat_lon_vert(vbo, pos_id, nor_id, &v_idx, rad, lat + lat_inc, lon + lon_inc); + add_lat_lon_vert(vbo, pos_id, nor_id, &v_idx, rad, lat, lon); + } + } + } + + SHC.drw_bone_point = Batch_create(GL_TRIANGLES, vbo, NULL); + } + return SHC.drw_bone_point; +} + +Batch *DRW_cache_bone_point_wire_outline_get(void) +{ + if (!SHC.drw_bone_point_wire) { + VertexBuffer *vbo = sphere_wire_vbo(0.05f); + SHC.drw_bone_point_wire = Batch_create(GL_LINES, vbo, NULL); + } + return SHC.drw_bone_point_wire; +} + +Batch *DRW_cache_bone_arrows_get(void) +{ + if (!SHC.drw_bone_arrows) { + VertexBuffer *vbo = fill_arrows_vbo(0.25f); + SHC.drw_bone_arrows = Batch_create(GL_LINES, vbo, NULL); + } + return SHC.drw_bone_arrows; +} + +/* 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_triangles_with_normals(me); + + return surface; +} + +#if 0 /* TODO */ +struct Batch *DRW_cache_surface_material_get(Object *ob, int nr) { + /* TODO */ + return NULL; +} +#endif diff --git a/source/blender/draw/intern/draw_cache.h b/source/blender/draw/intern/draw_cache.h new file mode 100644 index 00000000000..809d8be8422 --- /dev/null +++ b/source/blender/draw/intern/draw_cache.h @@ -0,0 +1,68 @@ +/* + * 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); +struct Batch *DRW_cache_single_line_get(void); + +/* Empties */ +struct Batch *DRW_cache_plain_axes_get(void); +struct Batch *DRW_cache_single_arrow_get(void); +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); +struct Batch *DRW_cache_axis_names_get(void); + +/* Lamps */ +struct Batch *DRW_cache_lamp_get(void); +struct Batch *DRW_cache_lamp_sunrays_get(void); + +/* Speaker */ +struct Batch *DRW_cache_speaker_get(void); + +/* Bones */ +struct Batch *DRW_cache_bone_octahedral_get(void); +struct Batch *DRW_cache_bone_octahedral_wire_outline_get(void); +struct Batch *DRW_cache_bone_point_get(void); +struct Batch *DRW_cache_bone_point_wire_outline_get(void); +struct Batch *DRW_cache_bone_arrows_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..f481965678c --- /dev/null +++ b/source/blender/draw/intern/draw_manager.c @@ -0,0 +1,1378 @@ +/* + * 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/intern/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_batch.h" +#include "GPU_draw.h" +#include "GPU_extensions.h" +#include "GPU_framebuffer.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 "object_mode.h" +#include "edit_armature_mode.h" +#include "edit_mesh_mode.h" +#include "clay.h" + +#define MAX_ATTRIB_NAME 32 + +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; + +typedef enum { + DRW_ATTRIB_INT, + DRW_ATTRIB_FLOAT, +} DRWAttribType; + +typedef struct DRWUniform { + struct DRWUniform *next, *prev; + DRWUniformType type; + int location; + int length; + int arraysize; + int bindloc; + const void *value; +} DRWUniform; + +typedef struct DRWAttrib { + struct DRWAttrib *next, *prev; + char name[MAX_ATTRIB_NAME]; + int location; + int format_id; + int size; /* number of component */ + int type; +} DRWAttrib; + +struct DRWInterface { + ListBase uniforms; /* DRWUniform */ + ListBase attribs; /* DRWAttrib */ + int attribs_count; + int attribs_stride; + int attribs_size[16]; + int attribs_loc[16]; + /* matrices locations */ + int modelview; + int projection; + int view; + int modelviewprojection; + int viewprojection; + int normal; + int eye; + /* Dynamic batch */ + GLuint instance_vbo; + int instance_count; + VertexFormat vbo_format; +}; + +struct DRWPass { + ListBase shgroups; /* DRWShadingGroup */ + DRWState state; + float state_param; /* Line / Point width */ +}; + +typedef struct DRWCall { + struct DRWCall *next, *prev; + Batch *geometry; + float (*obmat)[4]; +} DRWCall; + +typedef struct DRWDynamicCall { + struct DRWDynamicCall *next, *prev; + const void *data[]; +} DRWDynamicCall; + +struct DRWShadingGroup { + struct DRWShadingGroup *next, *prev; + + struct GPUShader *shader; /* Shader to bind */ + struct DRWInterface *interface; /* Uniforms pointers */ + ListBase calls; /* DRWCall or DRWDynamicCall depending of type*/ + int state; /* State changes for this batch only */ + int type; + + Batch *instance_geom; /* Geometry to instance */ + Batch *batch_geom; /* Result of call batching */ +}; + +/* Used by DRWShadingGroup.type */ +enum { + DRW_SHG_NORMAL, + DRW_SHG_POINT_BATCH, + DRW_SHG_LINE_BATCH, + DRW_SHG_INSTANCE, +}; + +/* Render State */ +static struct DRWGlobalState { + GPUShader *shader; + struct GPUFrameBuffer *default_framebuffer; + FramebufferList *fbl, *fbl_mode; + TextureList *txl, *txl_mode; + PassList *psl, *psl_mode; + StorageList *stl, *stl_mode; + 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->view = GPU_shader_get_uniform(shader, "ViewMatrix"); + 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"); + interface->instance_count = 0; + interface->attribs_count = 0; + interface->attribs_stride = 0; + interface->instance_vbo = 0; + + memset(&interface->vbo_format, 0, sizeof(VertexFormat)); + + BLI_listbase_clear(&interface->uniforms); + BLI_listbase_clear(&interface->attribs); + + 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); +} + +static void DRW_interface_attrib(DRWShadingGroup *shgroup, const char *name, DRWAttribType type, int size) +{ + DRWAttrib *attrib = MEM_mallocN(sizeof(DRWAttrib), "DRWAttrib"); + GLuint program = GPU_shader_get_program(shgroup->shader); + + attrib->location = glGetAttribLocation(program, name); + attrib->type = type; + attrib->size = size; + + if (attrib->location == -1) { + if (G.debug & G_DEBUG) + fprintf(stderr, "Attribute '%s' not found!\n", name); + + MEM_freeN(attrib); + return; + } + + BLI_assert(BLI_strnlen(name, 32) < 32); + BLI_strncpy(attrib->name, name, 32); + + shgroup->interface->attribs_count += 1; + + BLI_addtail(&shgroup->interface->attribs, attrib); +} + +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_mallocN(sizeof(DRWShadingGroup), "DRWShadingGroup"); + + shgroup->type = DRW_SHG_NORMAL; + shgroup->shader = shader; + shgroup->interface = DRW_interface_create(shader); + shgroup->state = 0; + shgroup->batch_geom = NULL; + shgroup->instance_geom = NULL; + + BLI_addtail(&pass->shgroups, shgroup); + BLI_listbase_clear(&shgroup->calls); + + return shgroup; +} + +DRWShadingGroup *DRW_shgroup_instance_create(struct GPUShader *shader, DRWPass *pass, Batch *geom) +{ + DRWShadingGroup *shgroup = DRW_shgroup_create(shader, pass); + + shgroup->type = DRW_SHG_INSTANCE; + shgroup->instance_geom = geom; + + return shgroup; +} + +DRWShadingGroup *DRW_shgroup_point_batch_create(struct GPUShader *shader, DRWPass *pass) +{ + DRWShadingGroup *shgroup = DRW_shgroup_create(shader, pass); + + shgroup->type = DRW_SHG_POINT_BATCH; + DRW_shgroup_attrib_float(shgroup, "pos", 3); + + return shgroup; +} + +DRWShadingGroup *DRW_shgroup_line_batch_create(struct GPUShader *shader, DRWPass *pass) +{ + DRWShadingGroup *shgroup = DRW_shgroup_create(shader, pass); + + shgroup->type = DRW_SHG_LINE_BATCH; + DRW_shgroup_attrib_float(shgroup, "pos", 3); + + return shgroup; +} + +void DRW_shgroup_free(struct DRWShadingGroup *shgroup) +{ + BLI_freelistN(&shgroup->calls); + BLI_freelistN(&shgroup->interface->uniforms); + BLI_freelistN(&shgroup->interface->attribs); + + if (shgroup->interface->instance_vbo) { + glDeleteBuffers(1, &shgroup->interface->instance_vbo); + } + + MEM_freeN(shgroup->interface); + + if (shgroup->batch_geom) { + Batch_discard_all(shgroup->batch_geom); + } +} + +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); + } +} + +void DRW_shgroup_dynamic_call_add(DRWShadingGroup *shgroup, ...) +{ + va_list params; + int i; + DRWInterface *interface = shgroup->interface; + int size = sizeof(ListBase) + sizeof(void *) * interface->attribs_count; + + DRWDynamicCall *call = MEM_callocN(size, "DRWDynamicCall"); + + va_start(params, shgroup); + for (i = 0; i < interface->attribs_count; ++i) { + call->data[i] = va_arg(params, void *); + } + va_end(params); + + interface->instance_count += 1; + + 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_attrib_float(DRWShadingGroup *shgroup, const char *name, int size) +{ + DRW_interface_attrib(shgroup, name, DRW_ATTRIB_FLOAT, size); +} + +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 a VBO containing OGL primitives for all DRWDynamicCall */ +static void shgroup_dynamic_batch(DRWShadingGroup *shgroup) +{ + DRWInterface *interface = shgroup->interface; + int nbr = interface->instance_count; + + GLenum type = (shgroup->type == DRW_SHG_POINT_BATCH) ? GL_POINTS : GL_LINES; + + if (nbr == 0) + return; + + /* Upload Data */ + if (interface->vbo_format.attrib_ct == 0) { + for (DRWAttrib *attrib = interface->attribs.first; attrib; attrib = attrib->next) { + BLI_assert(attrib->size <= 4); /* matrices have no place here for now */ + if (attrib->type == DRW_ATTRIB_FLOAT) { + attrib->format_id = add_attrib(&interface->vbo_format, attrib->name, GL_FLOAT, attrib->size, KEEP_FLOAT); + } + else if (attrib->type == DRW_ATTRIB_INT) { + attrib->format_id = add_attrib(&interface->vbo_format, attrib->name, GL_BYTE, attrib->size, KEEP_INT); + } + else { + BLI_assert(false); + } + } + } + + VertexBuffer *vbo = VertexBuffer_create_with_format(&interface->vbo_format); + VertexBuffer_allocate_data(vbo, nbr); + + int j = 0; + for (DRWDynamicCall *call = shgroup->calls.first; call; call = call->next, j++) { + int i = 0; + for (DRWAttrib *attrib = interface->attribs.first; attrib; attrib = attrib->next, i++) { + setAttrib(vbo, attrib->format_id, j, call->data[i]); + } + } + + /* TODO make the batch dynamic instead of freeing it every times */ + if (shgroup->batch_geom) + Batch_discard_all(shgroup->batch_geom); + + shgroup->batch_geom = Batch_create(type, vbo, NULL); +} + +static void shgroup_dynamic_instance(DRWShadingGroup *shgroup) +{ + int i = 0; + int offset = 0; + DRWInterface *interface = shgroup->interface; + int vert_nbr = interface->instance_count; + int buffer_size = 0; + + if (vert_nbr == 0) { + if (interface->instance_vbo) { + glDeleteBuffers(1, &interface->instance_vbo); + interface->instance_vbo = 0; + } + return; + } + + /* only once */ + if (interface->attribs_stride == 0) { + for (DRWAttrib *attrib = interface->attribs.first; attrib; attrib = attrib->next, i++) { + BLI_assert(attrib->type == DRW_ATTRIB_FLOAT); /* Only float for now */ + interface->attribs_stride += attrib->size; + interface->attribs_size[i] = attrib->size; + interface->attribs_loc[i] = attrib->location; + } + } + + /* Gather Data */ + buffer_size = sizeof(float) * interface->attribs_stride * vert_nbr; + float *data = MEM_mallocN(buffer_size, "Instance VBO data"); + + for (DRWDynamicCall *call = shgroup->calls.first; call; call = call->next) { + for (int j = 0; j < interface->attribs_count; ++j) { + memcpy(data + offset, call->data[j], sizeof(float) * interface->attribs_size[j]); + offset += interface->attribs_size[j]; + } + } + + /* TODO poke mike to add this to gawain */ + if (interface->instance_vbo) { + glDeleteBuffers(1, &interface->instance_vbo); + interface->instance_vbo = 0; + } + + glGenBuffers(1, &interface->instance_vbo); + glBindBuffer(GL_ARRAY_BUFFER, interface->instance_vbo); + glBufferData(GL_ARRAY_BUFFER, buffer_size, data, GL_STATIC_DRAW); + + MEM_freeN(data); +} + +static void shgroup_dynamic_batch_from_calls(DRWShadingGroup *shgroup) +{ + if ((shgroup->interface->instance_vbo || shgroup->batch_geom) && + (G.debug_value == 667)) + { + return; + } + + if (shgroup->type == DRW_SHG_INSTANCE) { + shgroup_dynamic_instance(shgroup); + } + else { + shgroup_dynamic_batch(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); +} + +/* ****************************************** DRAW ******************************************/ + +#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, Batch *geom, const float (*obmat)[4]) +{ + RegionView3D *rv3d = CTX_wm_region_view3d(DST.context); + DRWInterface *interface = shgroup->interface; + + 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->view != -1) { + GPU_shader_uniform_vector(shgroup->shader, interface->view, 16, 1, (float *)rv3d->viewmat); + } + 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 (interface->instance_vbo) { + Batch_draw_stupid_instanced(geom, interface->instance_vbo, interface->instance_count, interface->attribs_count, + interface->attribs_stride, interface->attribs_size, interface->attribs_loc); + } + 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->type != DRW_SHG_NORMAL) { + 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.txl->textures[uni->length], uni->bindloc); + GPU_texture_compare_mode(DST.txl->textures[uni->length], false); + GPU_texture_filter_mode(DST.txl->textures[uni->length], false); + + bound_tex = MEM_callocN(sizeof(DRWBoundTexture), "DRWBoundTexture"); + bound_tex->tex = DST.txl->textures[uni->length]; + BLI_addtail(&DST.bound_texs, bound_tex); + + GPU_shader_uniform_texture(shgroup->shader, uni->location, DST.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->type != DRW_SHG_NORMAL) { + /* Replacing multiple calls with only one */ + float obmat[4][4]; + unit_m4(obmat); + + if (shgroup->type == DRW_SHG_INSTANCE && interface->instance_count > 0) { + draw_geometry(shgroup, shgroup->instance_geom, obmat); + } + else { + /* Some dynamic batch can have no geom (no call to aggregate) */ + if (shgroup->batch_geom) { + draw_geometry(shgroup, shgroup->batch_geom, obmat); + } + } + } + else { + for (DRWCall *call = shgroup->calls.first; call; call = call->next) { + draw_geometry(shgroup, call->geometry, 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); +} + +void DRW_draw_mode_overlays(void) +{ + const bContext *C = DRW_get_context(); + int mode = CTX_data_mode_enum(C); + + DRW_draw_grid(); + + switch (mode) { + case CTX_MODE_EDIT_MESH: + EDIT_MESH_draw(); + break; + case CTX_MODE_EDIT_ARMATURE: + EDIT_ARMATURE_draw(); + break; + case CTX_MODE_OBJECT: + OBJECT_draw(); + break; + } + + DRW_draw_manipulator(); + DRW_draw_region_info(); +} +#else +void DRW_draw_pass(DRWPass *UNUSED(pass)) +{ +} + +#endif + +/* ******************************************* Mode Engine Cache ****************************************** */ +void DRW_mode_cache_init(void) +{ + const bContext *C = DRW_get_context(); + int mode = CTX_data_mode_enum(C); + + switch (mode) { + case CTX_MODE_EDIT_MESH: + EDIT_MESH_cache_init(); + break; + case CTX_MODE_EDIT_ARMATURE: + EDIT_ARMATURE_cache_init(); + break; + case CTX_MODE_OBJECT: + OBJECT_cache_init(); + break; + } +} + +void DRW_mode_cache_populate(Object *ob) +{ + const bContext *C = DRW_get_context(); + int mode = CTX_data_mode_enum(C); + + switch (mode) { + case CTX_MODE_EDIT_MESH: + EDIT_MESH_cache_populate(ob); + break; + case CTX_MODE_EDIT_ARMATURE: + EDIT_ARMATURE_cache_populate(ob); + break; + case CTX_MODE_OBJECT: + OBJECT_cache_populate(ob); + break; + } +} + +void DRW_mode_cache_finish(void) +{ + const bContext *C = DRW_get_context(); + int mode = CTX_data_mode_enum(C); + + switch (mode) { + case CTX_MODE_EDIT_MESH: + EDIT_MESH_cache_finish(); + break; + case CTX_MODE_EDIT_ARMATURE: + EDIT_ARMATURE_cache_finish(); + break; + case CTX_MODE_OBJECT: + OBJECT_cache_finish(); + break; + } +} + +/* ****************************************** 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); +} + +void DRW_framebuffer_blit(struct GPUFrameBuffer *fb_read, struct GPUFrameBuffer *fb_write, bool depth) +{ + GPU_framebuffer_blit(fb_read, 0, fb_write, 0, depth); +} + +/* ****************************************** 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) +{ + RegionView3D *rv3d = CTX_wm_region_view3d(C); + GPUViewport *viewport = rv3d->viewport; + + GPU_viewport_get_engine_data(viewport, &DST.fbl, &DST.txl, &DST.psl, &DST.stl); + GPU_viewport_get_mode_data(viewport, &DST.fbl_mode, &DST.txl_mode, &DST.psl_mode, &DST.stl_mode); + + /* Refresh DST.size */ + DefaultTextureList *txl = (DefaultTextureList *)DST.txl; + DST.size[0] = (float)GPU_texture_width(txl->color); + DST.size[1] = (float)GPU_texture_height(txl->color); + + DefaultFramebufferList *fbl = (DefaultFramebufferList *)DST.fbl; + DST.default_framebuffer = fbl->default_fb; + + /* 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.psl->passes[0] == NULL); +} + +/* ****************************************** OTHER ***************************************** */ + +const bContext *DRW_get_context(void) +{ + return DST.context; +} + +void *DRW_engine_pass_list_get(void) +{ + return DST.psl; +} + +void *DRW_engine_storage_list_get(void) +{ + return DST.stl; +} + +void *DRW_engine_texture_list_get(void) +{ + return DST.txl; +} + +void *DRW_engine_framebuffer_list_get(void) +{ + return DST.fbl; +} + +void *DRW_mode_pass_list_get(void) +{ + return DST.psl_mode; +} + +void *DRW_mode_storage_list_get(void) +{ + return DST.stl_mode; +} + +void *DRW_mode_texture_list_get(void) +{ + return DST.txl_mode; +} + +void *DRW_mode_framebuffer_list_get(void) +{ + return DST.fbl_mode; +} + +/* ****************************************** 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 +} 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..043ac9573a3 --- /dev/null +++ b/source/blender/draw/intern/draw_mode_pass.c @@ -0,0 +1,713 @@ +/* + * 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/intern/draw_mode_pass.c + * \ingroup draw + */ + +#include "DNA_userdef_types.h" + +#include "GPU_shader.h" + +#include "UI_resources.h" + +#include "BKE_global.h" + +#include "DRW_render.h" + +#include "draw_mode_pass.h" + +/* ************************** OBJECT MODE ******************************* */ + +/* Store list of shading group for easy access*/ + +/* Empties */ +static DRWShadingGroup *plain_axes; +static DRWShadingGroup *cube; +static DRWShadingGroup *circle; +static DRWShadingGroup *sphere; +static DRWShadingGroup *cone; +static DRWShadingGroup *single_arrow; +static DRWShadingGroup *single_arrow_line; +static DRWShadingGroup *arrows; +static DRWShadingGroup *axis_names; + +/* Speaker */ +static DRWShadingGroup *speaker; + +/* 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_shadow; +static DRWShadingGroup *lamp_sunrays; + +/* Helpers */ +static DRWShadingGroup *relationship_lines; + +/* Objects Centers */ +static DRWShadingGroup *center_active; +static DRWShadingGroup *center_selected; +static DRWShadingGroup *center_deselected; + +/* Colors & Constant */ +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]; + +/* Store list of passes for easy access */ +static DRWPass *wire_overlay; +static DRWPass *wire_overlay_hidden_wire; +static DRWPass *wire_outline; +static DRWPass *non_meshes; +static DRWPass *ob_center; +static DRWPass *bone_solid; +static DRWPass *bone_wire; + +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_line_batch_create(sh, pass); + DRW_shgroup_uniform_vec4(grp, "color", color, 1); + + 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_point_batch_create(sh, pass); + DRW_shgroup_uniform_vec4(grp, "color", color, 1); + DRW_shgroup_uniform_float(grp, "size", size, 1); + 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_point_batch_create(sh, pass); + DRW_shgroup_uniform_vec4(grp, "color", color, 1); + + 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_point_batch_create(sh, pass); + DRW_shgroup_uniform_vec4(grp, "color", color, 1); + DRW_shgroup_state_set(grp, DRW_STATE_POINT); + + return grp; +} + +static DRWShadingGroup *shgroup_instance_screenspace(DRWPass *pass, struct Batch *geom, float *size) +{ + GPUShader *sh = GPU_shader_get_builtin_shader(GPU_SHADER_3D_SCREENSPACE_VARIYING_COLOR); + + DRWShadingGroup *grp = DRW_shgroup_instance_create(sh, pass, geom); + DRW_shgroup_attrib_float(grp, "world_pos", 3); + DRW_shgroup_attrib_float(grp, "color", 3); + 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_state_set(grp, DRW_STATE_STIPPLE_3); + + return grp; +} + +static DRWShadingGroup *shgroup_instance_objspace_solid(DRWPass *pass, struct Batch *geom, float (*obmat)[4]) +{ + static float light[3] = {0.0f, 0.0f, 1.0f}; + GPUShader *sh = GPU_shader_get_builtin_shader(GPU_SHADER_3D_OBJECTSPACE_SIMPLE_LIGHTING_VARIYING_COLOR); + + DRWShadingGroup *grp = DRW_shgroup_instance_create(sh, pass, geom); + DRW_shgroup_attrib_float(grp, "InstanceModelMatrix", 16); + DRW_shgroup_attrib_float(grp, "color", 4); + DRW_shgroup_uniform_mat4(grp, "ModelMatrix", (float *)obmat); + DRW_shgroup_uniform_vec3(grp, "light", light, 1); + + return grp; +} + +static DRWShadingGroup *shgroup_instance_objspace_wire(DRWPass *pass, struct Batch *geom, float (*obmat)[4]) +{ + GPUShader *sh = GPU_shader_get_builtin_shader(GPU_SHADER_3D_OBJECTSPACE_VARIYING_COLOR); + + DRWShadingGroup *grp = DRW_shgroup_instance_create(sh, pass, geom); + DRW_shgroup_attrib_float(grp, "InstanceModelMatrix", 16); + DRW_shgroup_attrib_float(grp, "color", 4); + DRW_shgroup_uniform_mat4(grp, "ModelMatrix", (float *)obmat); + + return grp; +} + +static DRWShadingGroup *shgroup_instance_axis_names(DRWPass *pass, struct Batch *geom) +{ + GPUShader *sh = GPU_shader_get_builtin_shader(GPU_SHADER_3D_INSTANCE_SCREEN_ALIGNED_AXIS); + + DRWShadingGroup *grp = DRW_shgroup_instance_create(sh, pass, geom); + DRW_shgroup_attrib_float(grp, "color", 3); + DRW_shgroup_attrib_float(grp, "size", 1); + DRW_shgroup_attrib_float(grp, "InstanceModelMatrix", 16); + DRW_shgroup_uniform_vec3(grp, "screen_vecs", DRW_viewport_screenvecs_get(), 2); + + return grp; +} + +static DRWShadingGroup *shgroup_instance(DRWPass *pass, struct Batch *geom) +{ + GPUShader *sh_inst = GPU_shader_get_builtin_shader(GPU_SHADER_INSTANCE_VARIYING_COLOR_VARIYING_SIZE); + + DRWShadingGroup *grp = DRW_shgroup_instance_create(sh_inst, pass, geom); + DRW_shgroup_attrib_float(grp, "color", 3); + DRW_shgroup_attrib_float(grp, "size", 1); + DRW_shgroup_attrib_float(grp, "InstanceModelMatrix", 16); + + return grp; +} + +/* This Function setup the passes needed for the mode rendering. + * The passes are populated by the rendering engines using the DRW_shgroup_* functions. + * If a pass is not needed use NULL instead of the pass pointer */ +void DRW_mode_passes_setup(DRWPass **psl_wire_overlay, + DRWPass **psl_wire_overlay_hidden_wire, + DRWPass **psl_wire_outline, + DRWPass **psl_non_meshes, + DRWPass **psl_ob_center, + DRWPass **psl_bone_solid, + DRWPass **psl_bone_wire) +{ + 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 (psl_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; + *psl_wire_overlay = DRW_pass_create("Wire Overlays Pass", state); + } + + if (psl_wire_overlay_hidden_wire) { + /* 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_DEPTH_EQUAL | DRW_STATE_BLEND; + *psl_wire_overlay_hidden_wire = DRW_pass_create("Wire Overlays Pass", state); + } + + if (psl_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; + *psl_wire_outline = DRW_pass_create("Wire + Outlines Pass", state); + } + + if (psl_bone_solid) { + /* Solid bones */ + DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS; + *psl_bone_solid = DRW_pass_create("Bone Solid Pass", state); + } + + if (psl_bone_wire) { + /* Wire bones */ + DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS | DRW_STATE_BLEND; + *psl_bone_wire = DRW_pass_create("Bone Wire Pass", state); + } + + if (psl_non_meshes) { + /* Non Meshes Pass (Camera, empties, lamps ...) */ + struct Batch *geom; + + DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS | DRW_STATE_BLEND; + state |= DRW_STATE_WIRE; + *psl_non_meshes = DRW_pass_create("Non Meshes Pass", state); + + /* Empties */ + geom = DRW_cache_plain_axes_get(); + plain_axes = shgroup_instance(*psl_non_meshes, geom); + + geom = DRW_cache_cube_get(); + cube = shgroup_instance(*psl_non_meshes, geom); + + geom = DRW_cache_circle_get(); + circle = shgroup_instance(*psl_non_meshes, geom); + + geom = DRW_cache_empty_sphere_get(); + sphere = shgroup_instance(*psl_non_meshes, geom); + + geom = DRW_cache_empty_cone_get(); + cone = shgroup_instance(*psl_non_meshes, geom); + + geom = DRW_cache_single_arrow_get(); + single_arrow = shgroup_instance(*psl_non_meshes, geom); + + geom = DRW_cache_single_line_get(); + single_arrow_line = shgroup_instance(*psl_non_meshes, geom); + + geom = DRW_cache_arrows_get(); + arrows = shgroup_instance(*psl_non_meshes, geom); + + geom = DRW_cache_axis_names_get(); + axis_names = shgroup_instance_axis_names(*psl_non_meshes, geom); + + /* Speaker */ + geom = DRW_cache_speaker_get(); + speaker = shgroup_instance(*psl_non_meshes, geom); + + /* 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(*psl_non_meshes, colorLampNoAlpha, &lampCenterSize); + lamp_center_group = shgroup_dynpoints_uniform_color(*psl_non_meshes, colorGroup, &lampCenterSize); + + geom = DRW_cache_lamp_get(); + lamp_circle = shgroup_instance_screenspace(*psl_non_meshes, geom, &lampCircleRad); + lamp_circle_shadow = shgroup_instance_screenspace(*psl_non_meshes, geom, &lampCircleShadowRad); + + geom = DRW_cache_lamp_sunrays_get(); + lamp_sunrays = shgroup_instance_screenspace(*psl_non_meshes, geom, &lampCircleRad); + + lamp_groundline = shgroup_groundlines_uniform_color(*psl_non_meshes, colorLamp); + lamp_groundpoint = shgroup_groundpoints_uniform_color(*psl_non_meshes, colorLamp); + + /* Relationship Lines */ + relationship_lines = shgroup_dynlines_uniform_color(*psl_non_meshes, colorWire); + DRW_shgroup_state_set(relationship_lines, DRW_STATE_STIPPLE_3); + } + + if (psl_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; + *psl_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_point_batch_create(sh, *psl_ob_center); + 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_point_batch_create(sh, *psl_ob_center); + DRW_shgroup_uniform_vec4(grp, "color", colorSelect, 1); + center_selected = grp; + + /* Deselect */ + grp = DRW_shgroup_point_batch_create(sh, *psl_ob_center); + DRW_shgroup_uniform_vec4(grp, "color", colorDeselect, 1); + center_deselected = grp; + } + + /* Save passes refs */ + wire_overlay = (psl_wire_overlay) ? *psl_wire_overlay : NULL; + wire_overlay_hidden_wire = (psl_wire_overlay_hidden_wire) ? *psl_wire_overlay_hidden_wire : NULL; + wire_outline = (psl_wire_outline) ? *psl_wire_outline : NULL; + non_meshes = (psl_non_meshes) ? *psl_non_meshes : NULL; + ob_center = (psl_ob_center) ? *psl_ob_center : NULL; + bone_solid = (psl_bone_solid) ? *psl_bone_solid : NULL; + bone_wire = (psl_bone_wire) ? *psl_bone_wire : NULL; +} + +/* ******************************************** WIRES *********************************************** */ + +/* TODO FINISH */ +/* Get the wire color theme_id of an object based on it's state + * **color is a way to get a pointer to the static color var associated */ +static int draw_object_wire_theme(Object *ob, float **color) +{ + 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 */ + } + } + } + + if (color != NULL) { + switch (theme_id) { + case TH_WIRE_EDIT: *color = colorTransform; break; + case TH_ACTIVE: *color = colorActive; break; + case TH_SELECT: *color = colorSelect; break; + case TH_GROUP: *color = colorGroup; break; + case TH_GROUP_ACTIVE: *color = colorGroupActive; break; + case TH_TRANSFORM: *color = colorTransform; break; + case OB_SPEAKER: *color = colorSpeaker; break; + case OB_CAMERA: *color = colorCamera; break; + case OB_EMPTY: *color = colorEmpty; break; + case OB_LAMP: *color = colorLamp; break; + default: *color = colorWire; break; + } + } + + return theme_id; +} + +void DRW_shgroup_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(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); + + float *color; + draw_object_wire_theme(ob, &color); + +#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", color, 1); + DRW_shgroup_uniform_vec4(grp, "backColor", color, 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 ********************** */ + +void DRW_shgroup_lamp(Object *ob) +{ + Lamp *la = ob->data; + float *color; + int theme_id = draw_object_wire_theme(ob, &color); + + /* Don't draw the center if it's selected or active */ + if (theme_id == TH_GROUP) + DRW_shgroup_dynamic_call_add(lamp_center_group, ob->obmat[3]); + else if (theme_id == TH_LAMP) + DRW_shgroup_dynamic_call_add(lamp_center, ob->obmat[3]); + + /* First circle */ + DRW_shgroup_dynamic_call_add(lamp_circle, ob->obmat[3], color); + + /* draw dashed outer circle if shadow is on. remember some lamps can't have certain shadows! */ + if (la->type != LA_HEMI) { + DRW_shgroup_dynamic_call_add(lamp_circle_shadow, ob->obmat[3], color); + } + + /* Sunrays */ + if (la->type == LA_SUN) { + DRW_shgroup_dynamic_call_add(lamp_sunrays, ob->obmat[3], color); + } + + /* Line and point going to the ground */ + DRW_shgroup_dynamic_call_add(lamp_groundline, ob->obmat[3]); + DRW_shgroup_dynamic_call_add(lamp_groundpoint, ob->obmat[3]); +} + +void DRW_shgroup_empty(Object *ob) +{ + float *color; + draw_object_wire_theme(ob, &color); + + switch (ob->empty_drawtype) { + case OB_PLAINAXES: + DRW_shgroup_dynamic_call_add(plain_axes, color, &ob->empty_drawsize, ob->obmat); + break; + case OB_SINGLE_ARROW: + DRW_shgroup_dynamic_call_add(single_arrow, color, &ob->empty_drawsize, ob->obmat); + DRW_shgroup_dynamic_call_add(single_arrow_line, color, &ob->empty_drawsize, ob->obmat); + break; + case OB_CUBE: + DRW_shgroup_dynamic_call_add(cube, color, &ob->empty_drawsize, ob->obmat); + break; + case OB_CIRCLE: + DRW_shgroup_dynamic_call_add(circle, color, &ob->empty_drawsize, ob->obmat); + break; + case OB_EMPTY_SPHERE: + DRW_shgroup_dynamic_call_add(sphere, color, &ob->empty_drawsize, ob->obmat); + break; + case OB_EMPTY_CONE: + DRW_shgroup_dynamic_call_add(cone, color, &ob->empty_drawsize, ob->obmat); + break; + case OB_ARROWS: + DRW_shgroup_dynamic_call_add(arrows, color, &ob->empty_drawsize, ob->obmat); + DRW_shgroup_dynamic_call_add(axis_names, color, &ob->empty_drawsize, ob->obmat); + break; + } +} + +void DRW_shgroup_speaker(Object *ob) +{ + float *color; + static float one = 1.0f; + draw_object_wire_theme(ob, &color); + + DRW_shgroup_dynamic_call_add(speaker, color, &one, ob->obmat); +} + +void DRW_shgroup_relationship_lines(Object *ob) +{ + if (ob->parent) { + DRW_shgroup_dynamic_call_add(relationship_lines, ob->obmat[3]); + DRW_shgroup_dynamic_call_add(relationship_lines, ob->parent->obmat[3]); + } +} + +/* ***************************** COMMON **************************** */ + +void DRW_shgroup_object_center(Object *ob) +{ + if ((ob->base_flag & BASE_SELECTED) != 0) { + DRW_shgroup_dynamic_call_add(center_selected, ob->obmat[3]); + } + else if (0) { + DRW_shgroup_dynamic_call_add(center_deselected, ob->obmat[3]); + } +} + +/* *************************** ARMATURES ***************************** */ + +static Object *current_armature; +/* Reset when changing current_armature */ +static DRWShadingGroup *bone_octahedral_solid; +static DRWShadingGroup *bone_octahedral_wire; +static DRWShadingGroup *bone_point_solid; +static DRWShadingGroup *bone_point_wire; +static DRWShadingGroup *bone_axes; + +/* this function set the object space to use + * for all subsequent DRW_shgroup_bone_*** calls */ +static void DRW_shgroup_armature(Object *ob) +{ + current_armature = ob; + bone_octahedral_solid = NULL; + bone_octahedral_wire = NULL; + bone_point_solid = NULL; + bone_point_wire = NULL; + bone_axes = NULL; +} + +void DRW_shgroup_armature_object(Object *ob) +{ + float *color; + draw_object_wire_theme(ob, &color); + + DRW_shgroup_armature(ob); + draw_armature_pose(ob, color); +} + +void DRW_shgroup_armature_pose(Object *ob) +{ + DRW_shgroup_armature(ob); + draw_armature_pose(ob, NULL); +} + +void DRW_shgroup_armature_edit(Object *ob) +{ + DRW_shgroup_armature(ob); + draw_armature_edit(ob); +} + +/* Octahedral */ +void DRW_shgroup_bone_octahedral_solid(const float (*bone_mat)[4], const float color[4]) +{ + if (bone_octahedral_solid == NULL) { + struct Batch *geom = DRW_cache_bone_octahedral_get(); + bone_octahedral_solid = shgroup_instance_objspace_solid(bone_solid, geom, current_armature->obmat); + } + + DRW_shgroup_dynamic_call_add(bone_octahedral_solid, bone_mat, color); +} + +void DRW_shgroup_bone_octahedral_wire(const float (*bone_mat)[4], const float color[4]) +{ + if (bone_octahedral_wire == NULL) { + struct Batch *geom = DRW_cache_bone_octahedral_wire_outline_get(); + bone_octahedral_wire = shgroup_instance_objspace_wire(bone_wire, geom, current_armature->obmat); + } + + DRW_shgroup_dynamic_call_add(bone_octahedral_wire, bone_mat, color); +} + +/* Head and tail sphere */ +void DRW_shgroup_bone_point_solid(const float (*bone_mat)[4], const float color[4]) +{ + if (bone_point_solid == NULL) { + struct Batch *geom = DRW_cache_bone_point_get(); + bone_point_solid = shgroup_instance_objspace_solid(bone_solid, geom, current_armature->obmat); + } + + DRW_shgroup_dynamic_call_add(bone_point_solid, bone_mat, color); +} + +void DRW_shgroup_bone_point_wire(const float (*bone_mat)[4], const float color[4]) +{ + if (bone_point_wire == NULL) { + struct Batch *geom = DRW_cache_bone_point_wire_outline_get(); + bone_point_wire = shgroup_instance_objspace_wire(bone_wire, geom, current_armature->obmat); + } + + DRW_shgroup_dynamic_call_add(bone_point_wire, bone_mat, color); +} + +/* Axes */ +void DRW_shgroup_bone_axes(const float (*bone_mat)[4], const float color[4]) +{ + if (bone_axes == NULL) { + struct Batch *geom = DRW_cache_bone_arrows_get(); + bone_axes = shgroup_instance_objspace_wire(bone_wire, geom, current_armature->obmat); + } + + DRW_shgroup_dynamic_call_add(bone_axes, bone_mat, color); +} + + +void DRW_shgroup_bone_relationship_lines(const float head[3], const float tail[3]) +{ + DRW_shgroup_dynamic_call_add(relationship_lines, head); + DRW_shgroup_dynamic_call_add(relationship_lines, tail); +} 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..53322729f0c --- /dev/null +++ b/source/blender/draw/intern/draw_mode_pass.h @@ -0,0 +1,64 @@ +/* + * 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__ + +struct DRWPass; +struct Batch; +struct Object; + +void DRW_mode_passes_setup(struct DRWPass **psl_wire_overlay, + struct DRWPass **psl_wire_overlay_hidden_wire, + struct DRWPass **psl_wire_outline, + struct DRWPass **psl_non_meshes, + struct DRWPass **psl_ob_center, + struct DRWPass **psl_bone_solid, + struct DRWPass **psl_bone_wire); + +void DRW_shgroup_wire_overlay(struct Object *ob); +void DRW_shgroup_wire_outline(struct Object *ob, const bool do_front, const bool do_back, const bool do_outline); +void DRW_shgroup_lamp(struct Object *ob); +void DRW_shgroup_empty(struct Object *ob); +void DRW_shgroup_speaker(struct Object *ob); +void DRW_shgroup_relationship_lines(struct Object *ob); +void DRW_shgroup_object_center(struct Object *ob); + +void DRW_shgroup_armature_object(struct Object *ob); +void DRW_shgroup_armature_edit(struct Object *ob); +void DRW_shgroup_armature_pose(struct Object *ob); + +void DRW_shgroup_bone_octahedral_solid(const float (*arm_mat)[4], const float color[4]); +void DRW_shgroup_bone_octahedral_wire(const float (*arm_mat)[4], const float color[4]); +void DRW_shgroup_bone_point_solid(const float (*arm_mat)[4], const float color[4]); +void DRW_shgroup_bone_point_wire(const float (*arm_mat)[4], const float color[4]); +void DRW_shgroup_bone_relationship_lines(const float head[3], const float tail[3]); +void DRW_shgroup_bone_axes(const float (*arm_mat)[4], const float color[4]); + +/* draw_armature.c */ +void draw_armature_edit(struct Object *ob); +void draw_armature_pose(struct Object *ob, const float const_color[4]); + +#endif /* __DRAW_MODE_PASS_H__ */
\ No newline at end of file diff --git a/source/blender/draw/intern/draw_view.c b/source/blender/draw/intern/draw_view.c new file mode 100644 index 00000000000..f3865a7a92f --- /dev/null +++ b/source/blender/draw/intern/draw_view.c @@ -0,0 +1,698 @@ +/* + * 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/intern/draw_view.c + * \ingroup draw + * + * Contains dynamic drawing using immediate mode + */ + +#include "DNA_brush_types.h" +#include "DNA_screen_types.h" +#include "DNA_userdef_types.h" +#include "DNA_view3d_types.h" + +#include "ED_screen.h" +#include "ED_transform.h" +#include "ED_view3d.h" + +#include "GPU_draw.h" +#include "GPU_shader.h" +#include "GPU_immediate.h" +#include "GPU_matrix.h" + +#include "UI_resources.h" + +#include "BKE_global.h" +#include "BKE_object.h" +#include "BKE_paint.h" +#include "BKE_unit.h" + +#include "DRW_render.h" + +#include "view3d_intern.h" + +#include "draw_view.h" + +/* ******************** region info ***************** */ + +void DRW_draw_region_info(void) +{ + const bContext *C = DRW_get_context(); + ARegion *ar = CTX_wm_region(C); + + DRW_draw_cursor(); + view3d_draw_region_info(C, ar); +} + +/* ************************* Grid ************************** */ + +static void gridline_range(double x0, double dx, double max, int *r_first, int *r_count) +{ + /* determine range of gridlines that appear in this Area -- similar calc but separate ranges for x & y + * x0 is gridline 0, the axis in screen space + * Area covers [0 .. max) pixels */ + + int first = (int)ceil(-x0 / dx); + int last = (int)floor((max - x0) / dx); + + if (first <= last) { + *r_first = first; + *r_count = last - first + 1; + } + else { + *r_first = 0; + *r_count = 0; + } +} + +static int gridline_count(ARegion *ar, double x0, double y0, double dx) +{ + /* x0 & y0 establish the "phase" of the grid within this 2D region + * dx is the frequency, shared by x & y directions + * pass in dx of smallest (highest precision) grid we want to draw */ + + int first, x_ct, y_ct; + + gridline_range(x0, dx, ar->winx, &first, &x_ct); + gridline_range(y0, dx, ar->winy, &first, &y_ct); + + int total_ct = x_ct + y_ct; + + return total_ct; +} + +static bool drawgrid_draw(ARegion *ar, double x0, double y0, double dx, int skip_mod, unsigned pos, unsigned col, GLubyte col_value[3]) +{ + /* skip every skip_mod lines relative to each axis; they will be overlaid by another drawgrid_draw + * always skip exact x0 & y0 axes; they will be drawn later in color + * + * set grid color once, just before the first line is drawn + * it's harmless to set same color for every line, or every vertex + * but if no lines are drawn, color must not be set! */ + + const float x_max = (float)ar->winx; + const float y_max = (float)ar->winy; + + int first, ct; + int x_ct = 0, y_ct = 0; /* count of lines actually drawn */ + int lines_skipped_for_next_unit = 0; + + /* draw vertical lines */ + gridline_range(x0, dx, x_max, &first, &ct); + + for (int i = first; i < first + ct; ++i) { + if (i == 0) + continue; + else if (skip_mod && (i % skip_mod) == 0) { + ++lines_skipped_for_next_unit; + continue; + } + + if (x_ct == 0) + immAttrib3ub(col, col_value[0], col_value[1], col_value[2]); + + float x = (float)(x0 + i * dx); + immVertex2f(pos, x, 0.0f); + immVertex2f(pos, x, y_max); + ++x_ct; + } + + /* draw horizontal lines */ + gridline_range(y0, dx, y_max, &first, &ct); + + for (int i = first; i < first + ct; ++i) { + if (i == 0) + continue; + else if (skip_mod && (i % skip_mod) == 0) { + ++lines_skipped_for_next_unit; + continue; + } + + if (x_ct + y_ct == 0) + immAttrib3ub(col, col_value[0], col_value[1], col_value[2]); + + float y = (float)(y0 + i * dx); + immVertex2f(pos, 0.0f, y); + immVertex2f(pos, x_max, y); + ++y_ct; + } + + return lines_skipped_for_next_unit > 0; +} + +#define GRID_MIN_PX_D 6.0 +#define GRID_MIN_PX_F 6.0f + +static void drawgrid(UnitSettings *unit, ARegion *ar, View3D *v3d, const char **grid_unit) +{ + RegionView3D *rv3d = ar->regiondata; + + double fx = rv3d->persmat[3][0]; + double fy = rv3d->persmat[3][1]; + double fw = rv3d->persmat[3][3]; + + const double wx = 0.5 * ar->winx; /* use double precision to avoid rounding errors */ + const double wy = 0.5 * ar->winy; + + double x = wx * fx / fw; + double y = wy * fy / fw; + + double vec4[4] = { v3d->grid, v3d->grid, 0.0, 1.0 }; + mul_m4_v4d(rv3d->persmat, vec4); + fx = vec4[0]; + fy = vec4[1]; + fw = vec4[3]; + + double dx = fabs(x - wx * fx / fw); + if (dx == 0) dx = fabs(y - wy * fy / fw); + + x += wx; + y += wy; + + /* now x, y, and dx have their final values + * (x,y) is the world origin (0,0,0) mapped to Area-relative screen space + * dx is the distance in pixels between grid lines -- same for horiz or vert grid lines */ + + glLineWidth(1.0f); + +#if 0 /* TODO: write to UI/widget depth buffer, not scene depth */ + glDepthMask(GL_FALSE); /* disable write in zbuffer */ +#endif + + VertexFormat *format = immVertexFormat(); + unsigned int pos = add_attrib(format, "pos", COMP_F32, 2, KEEP_FLOAT); + unsigned int color = add_attrib(format, "color", COMP_U8, 3, NORMALIZE_INT_TO_FLOAT); + + immBindBuiltinProgram(GPU_SHADER_2D_FLAT_COLOR); + + unsigned char col[3], col2[3]; + UI_GetThemeColor3ubv(TH_GRID, col); + + if (unit->system) { + const void *usys; + int len; + + bUnit_GetSystem(unit->system, B_UNIT_LENGTH, &usys, &len); + + bool first = true; + + if (usys) { + int i = len; + while (i--) { + double scalar = bUnit_GetScaler(usys, i); + + double dx_scalar = dx * scalar / (double)unit->scale_length; + if (dx_scalar < (GRID_MIN_PX_D * 2.0)) { + /* very very small grid items are less useful when dealing with units */ + continue; + } + + if (first) { + first = false; + + /* Store the smallest drawn grid size units name so users know how big each grid cell is */ + *grid_unit = bUnit_GetNameDisplay(usys, i); + rv3d->gridview = (float)((scalar * (double)v3d->grid) / (double)unit->scale_length); + + int gridline_ct = gridline_count(ar, x, y, dx_scalar); + if (gridline_ct == 0) + goto drawgrid_cleanup; /* nothing to draw */ + + immBegin(GL_LINES, gridline_ct * 2); + } + + float blend_fac = 1.0f - ((GRID_MIN_PX_F * 2.0f) / (float)dx_scalar); + /* tweak to have the fade a bit nicer */ + blend_fac = (blend_fac * blend_fac) * 2.0f; + CLAMP(blend_fac, 0.3f, 1.0f); + + UI_GetThemeColorBlend3ubv(TH_HIGH_GRAD, TH_GRID, blend_fac, col2); + + const int skip_mod = (i == 0) ? 0 : (int)round(bUnit_GetScaler(usys, i - 1) / scalar); + if (!drawgrid_draw(ar, x, y, dx_scalar, skip_mod, pos, color, col2)) + break; + } + } + } + else { + const double sublines = v3d->gridsubdiv; + const float sublines_fl = v3d->gridsubdiv; + + int grids_to_draw = 2; /* first the faint fine grid, then the bold coarse grid */ + + if (dx < GRID_MIN_PX_D) { + rv3d->gridview *= sublines_fl; + dx *= sublines; + if (dx < GRID_MIN_PX_D) { + rv3d->gridview *= sublines_fl; + dx *= sublines; + if (dx < GRID_MIN_PX_D) { + rv3d->gridview *= sublines_fl; + dx *= sublines; + grids_to_draw = (dx < GRID_MIN_PX_D) ? 0 : 1; + } + } + } + else { + if (dx > (GRID_MIN_PX_D * 10.0)) { /* start blending in */ + rv3d->gridview /= sublines_fl; + dx /= sublines; + if (dx > (GRID_MIN_PX_D * 10.0)) { /* start blending in */ + rv3d->gridview /= sublines_fl; + dx /= sublines; + if (dx > (GRID_MIN_PX_D * 10.0)) { + grids_to_draw = 1; + } + } + } + } + + int gridline_ct = gridline_count(ar, x, y, dx); + if (gridline_ct == 0) + goto drawgrid_cleanup; /* nothing to draw */ + + immBegin(GL_LINES, gridline_ct * 2); + + if (grids_to_draw == 2) { + UI_GetThemeColorBlend3ubv(TH_HIGH_GRAD, TH_GRID, dx / (GRID_MIN_PX_D * 6.0), col2); + if (drawgrid_draw(ar, x, y, dx, v3d->gridsubdiv, pos, color, col2)) + drawgrid_draw(ar, x, y, dx * sublines, 0, pos, color, col); + } + else if (grids_to_draw == 1) { + drawgrid_draw(ar, x, y, dx, 0, pos, color, col); + } + } + + /* draw visible axes */ + /* horizontal line */ + if (0 <= y && y < ar->winy) { + UI_make_axis_color(col, col2, ELEM(rv3d->view, RV3D_VIEW_RIGHT, RV3D_VIEW_LEFT) ? 'Y' : 'X'); + immAttrib3ub(color, col2[0], col2[1], col2[2]); + immVertex2f(pos, 0.0f, y); + immVertex2f(pos, (float)ar->winx, y); + } + + /* vertical line */ + if (0 <= x && x < ar->winx) { + UI_make_axis_color(col, col2, ELEM(rv3d->view, RV3D_VIEW_TOP, RV3D_VIEW_BOTTOM) ? 'Y' : 'Z'); + immAttrib3ub(color, col2[0], col2[1], col2[2]); + immVertex2f(pos, x, 0.0f); + immVertex2f(pos, x, (float)ar->winy); + } + + immEnd(); + +drawgrid_cleanup: + immUnbindProgram(); + +#if 0 /* depth write is left enabled above */ + glDepthMask(GL_TRUE); /* enable write in zbuffer */ +#endif +} + +#undef DEBUG_GRID +#undef GRID_MIN_PX_D +#undef GRID_MIN_PX_F + +static void drawfloor(Scene *scene, View3D *v3d, const char **grid_unit) +{ + /* draw only if there is something to draw */ + if (v3d->gridflag & (V3D_SHOW_FLOOR | V3D_SHOW_X | V3D_SHOW_Y | V3D_SHOW_Z)) { + /* draw how many lines? + * trunc(v3d->gridlines / 2) * 4 + * + 2 for xy axes (possibly with special colors) + * + 1 for z axis (the only line not in xy plane) + * even v3d->gridlines are honored, odd rounded down */ + const int gridlines = v3d->gridlines / 2; + const float grid_scale = ED_view3d_grid_scale(scene, v3d, grid_unit); + const float grid = gridlines * grid_scale; + + const bool show_floor = (v3d->gridflag & V3D_SHOW_FLOOR) && gridlines >= 1; + + bool show_axis_x = v3d->gridflag & V3D_SHOW_X; + bool show_axis_y = v3d->gridflag & V3D_SHOW_Y; + bool show_axis_z = v3d->gridflag & V3D_SHOW_Z; + + unsigned char col_grid[3], col_axis[3]; + + glLineWidth(1.0f); + + UI_GetThemeColor3ubv(TH_GRID, col_grid); + + if (show_floor) { + const unsigned vertex_ct = 2 * (gridlines * 4 + 2); + const int sublines = v3d->gridsubdiv; + + unsigned char col_bg[3], col_grid_emphasise[3], col_grid_light[3]; + + VertexFormat *format = immVertexFormat(); + unsigned int pos = add_attrib(format, "pos", COMP_F32, 2, KEEP_FLOAT); + unsigned int color = add_attrib(format, "color", COMP_U8, 3, NORMALIZE_INT_TO_FLOAT); + + immBindBuiltinProgram(GPU_SHADER_3D_FLAT_COLOR); + + immBegin(GL_LINES, vertex_ct); + + /* draw normal grid lines */ + UI_GetColorPtrShade3ubv(col_grid, col_grid_light, 10); + + for (int a = 1; a <= gridlines; a++) { + /* skip emphasised divider lines */ + if (a % sublines != 0) { + const float line = a * grid_scale; + + immAttrib3ubv(color, col_grid_light); + + immVertex2f(pos, -grid, -line); + immVertex2f(pos, +grid, -line); + immVertex2f(pos, -grid, +line); + immVertex2f(pos, +grid, +line); + + immVertex2f(pos, -line, -grid); + immVertex2f(pos, -line, +grid); + immVertex2f(pos, +line, -grid); + immVertex2f(pos, +line, +grid); + } + } + + /* draw emphasised grid lines */ + UI_GetThemeColor3ubv(TH_BACK, col_bg); + /* emphasise division lines lighter instead of darker, if background is darker than grid */ + UI_GetColorPtrShade3ubv(col_grid, col_grid_emphasise, + (col_grid[0] + col_grid[1] + col_grid[2] + 30 > + col_bg[0] + col_bg[1] + col_bg[2]) ? 20 : -10); + + if (sublines <= gridlines) { + immAttrib3ubv(color, col_grid_emphasise); + + for (int a = sublines; a <= gridlines; a += sublines) { + const float line = a * grid_scale; + + immVertex2f(pos, -grid, -line); + immVertex2f(pos, +grid, -line); + immVertex2f(pos, -grid, +line); + immVertex2f(pos, +grid, +line); + + immVertex2f(pos, -line, -grid); + immVertex2f(pos, -line, +grid); + immVertex2f(pos, +line, -grid); + immVertex2f(pos, +line, +grid); + } + } + + /* draw X axis */ + if (show_axis_x) { + show_axis_x = false; /* drawing now, won't need to draw later */ + UI_make_axis_color(col_grid, col_axis, 'X'); + immAttrib3ubv(color, col_axis); + } + else + immAttrib3ubv(color, col_grid_emphasise); + + immVertex2f(pos, -grid, 0.0f); + immVertex2f(pos, +grid, 0.0f); + + /* draw Y axis */ + if (show_axis_y) { + show_axis_y = false; /* drawing now, won't need to draw later */ + UI_make_axis_color(col_grid, col_axis, 'Y'); + immAttrib3ubv(color, col_axis); + } + else + immAttrib3ubv(color, col_grid_emphasise); + + immVertex2f(pos, 0.0f, -grid); + immVertex2f(pos, 0.0f, +grid); + + immEnd(); + immUnbindProgram(); + + /* done with XY plane */ + } + + if (show_axis_x || show_axis_y || show_axis_z) { + /* draw axis lines -- sometimes grid floor is off, other times we still need to draw the Z axis */ + + VertexFormat *format = immVertexFormat(); + unsigned int pos = add_attrib(format, "pos", COMP_F32, 3, KEEP_FLOAT); + unsigned int color = add_attrib(format, "color", COMP_U8, 3, NORMALIZE_INT_TO_FLOAT); + + immBindBuiltinProgram(GPU_SHADER_3D_FLAT_COLOR); + immBegin(GL_LINES, (show_axis_x + show_axis_y + show_axis_z) * 2); + + if (show_axis_x) { + UI_make_axis_color(col_grid, col_axis, 'X'); + immAttrib3ubv(color, col_axis); + immVertex3f(pos, -grid, 0.0f, 0.0f); + immVertex3f(pos, +grid, 0.0f, 0.0f); + } + + if (show_axis_y) { + UI_make_axis_color(col_grid, col_axis, 'Y'); + immAttrib3ubv(color, col_axis); + immVertex3f(pos, 0.0f, -grid, 0.0f); + immVertex3f(pos, 0.0f, +grid, 0.0f); + } + + if (show_axis_z) { + UI_make_axis_color(col_grid, col_axis, 'Z'); + immAttrib3ubv(color, col_axis); + immVertex3f(pos, 0.0f, 0.0f, -grid); + immVertex3f(pos, 0.0f, 0.0f, +grid); + } + + immEnd(); + immUnbindProgram(); + } + } +} + +void DRW_draw_grid(void) +{ + /* TODO viewport + * Missing is the flags to check whether to draw it + * for now now we are using the flags in v3d itself. + * + * Also for now always assume depth is there, so we + * draw on top of it. + */ + /** + * Calculate pixel-size factor once, is used for lamps and object centers. + * Used by #ED_view3d_pixel_size and typically not accessed directly. + * + * \note #BKE_camera_params_compute_viewplane' also calculates a pixel-size value, + * passed to #RE_SetPixelSize, in ortho mode this is compatible with this value, + * but in perspective mode its offset by the near-clip. + * + * 'RegionView3D.pixsize' is used for viewport drawing, not rendering. + */ + const bContext *C = DRW_get_context(); + Scene *scene = CTX_data_scene(C); + View3D *v3d = CTX_wm_view3d(C); + ARegion *ar = CTX_wm_region(C); + RegionView3D *rv3d = ar->regiondata; + + const bool draw_floor = (rv3d->view == RV3D_VIEW_USER) || (rv3d->persp != RV3D_ORTHO); + const char *grid_unit = NULL; + + /* ortho grid goes first, does not write to depth buffer and doesn't need depth test so it will override + * objects if done last + * needs to be done always, gridview is adjusted in drawgrid() now, but only for ortho views. + */ + rv3d->gridview = ED_view3d_grid_scale(scene, v3d, &grid_unit); + + glEnable(GL_DEPTH_TEST); + glDepthFunc(GL_LESS); + glDepthMask(GL_TRUE); + + if (!draw_floor) { + ED_region_pixelspace(ar); + *(&grid_unit) = NULL; /* drawgrid need this to detect/affect smallest valid unit... */ + drawgrid(&scene->unit, ar, v3d, &grid_unit); + + glMatrixMode(GL_PROJECTION); + glLoadMatrixf((float *)rv3d->winmat); + glMatrixMode(GL_MODELVIEW); + glLoadMatrixf((float *)rv3d->viewmat); + } + else { + drawfloor(scene, v3d, &grid_unit); + } +} + +/* ************************* Background ************************** */ + +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); + } +} + +/* **************************** 3D Cursor ******************************** */ + +static bool is_cursor_visible(Scene *scene) +{ + Object *ob = OBACT; + + /* don't draw cursor in paint modes, but with a few exceptions */ + if (ob && ob->mode & OB_MODE_ALL_PAINT) { + /* exception: object is in weight paint and has deforming armature in pose mode */ + if (ob->mode & OB_MODE_WEIGHT_PAINT) { + if (BKE_object_pose_armature_get(ob) != NULL) { + return true; + } + } + /* exception: object in texture paint mode, clone brush, use_clone_layer disabled */ + else if (ob->mode & OB_MODE_TEXTURE_PAINT) { + const Paint *p = BKE_paint_get_active(scene); + + if (p && p->brush && p->brush->imagepaint_tool == PAINT_TOOL_CLONE) { + if ((scene->toolsettings->imapaint.flag & IMAGEPAINT_PROJECT_LAYER_CLONE) == 0) { + return true; + } + } + } + + /* no exception met? then don't draw cursor! */ + return false; + } + + return true; +} + +void DRW_draw_cursor(void) +{ + const bContext *C = DRW_get_context(); + View3D *v3d = CTX_wm_view3d(C); + RegionView3D *rv3d = CTX_wm_region_view3d(C); + Scene *scene = CTX_data_scene(C); + + glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); + glDepthMask(GL_FALSE); + glDisable(GL_DEPTH_TEST); + glLineWidth(1.0f); + + if (is_cursor_visible(scene)) { + float *co = ED_view3d_cursor3d_get(scene, v3d); + unsigned char crosshair_color[3]; + + const float f5 = 0.25f; + const float f10 = 0.5f; + const float f20 = 1.0f; + + VertexFormat *format = immVertexFormat(); + unsigned int pos = add_attrib(format, "pos", COMP_F32, 2, KEEP_FLOAT); + unsigned int color = add_attrib(format, "color", COMP_U8, 3, NORMALIZE_INT_TO_FLOAT); + unsigned int wpos = add_attrib(format, "world_pos", COMP_F32, 3, KEEP_FLOAT); + + /* XXX Using instance shader without instance */ + immBindBuiltinProgram(GPU_SHADER_3D_SCREENSPACE_VARIYING_COLOR); + immUniform1f("size", U.widget_unit); + immUniform1f("pixel_size", *DRW_viewport_pixelsize_get()); + immUniformArray3fv("screen_vecs", DRW_viewport_screenvecs_get(), 2); + immUniformMatrix4fv("ViewProjectionMatrix", rv3d->persmat); + + const int segments = 16; + + immBegin(GL_LINE_LOOP, segments); + immAttrib3fv(wpos, co); + + for (int i = 0; i < segments; ++i) { + float angle = 2 * M_PI * ((float)i / (float)segments); + float x = f10 * cosf(angle); + float y = f10 * sinf(angle); + + if (i % 2 == 0) + immAttrib3ub(color, 255, 0, 0); + else + immAttrib3ub(color, 255, 255, 255); + + immVertex2f(pos, x, y); + } + immEnd(); + + UI_GetThemeColor3ubv(TH_VIEW_OVERLAY, crosshair_color); + + immBegin(GL_LINES, 8); + immAttrib3ubv(color, crosshair_color); + immAttrib3fv(wpos, co); + + immVertex2f(pos, -f20, 0); + immVertex2f(pos, -f5, 0); + immVertex2f(pos, +f5, 0); + immVertex2f(pos, +f20, 0); + immVertex2f(pos, 0, -f20); + immVertex2f(pos, 0, -f5); + immVertex2f(pos, 0, +f5); + immVertex2f(pos, 0, +f20); + immEnd(); + + immUnbindProgram(); + } +} + +/* **************************** 3D Manipulator ******************************** */ + +void DRW_draw_manipulator(void) +{ + const bContext *C = DRW_get_context(); + View3D *v3d = CTX_wm_view3d(C); + v3d->zbuf = false; + BIF_draw_manipulator(C); +} diff --git a/source/blender/draw/intern/draw_view.h b/source/blender/draw/intern/draw_view.h new file mode 100644 index 00000000000..b400ceeffa2 --- /dev/null +++ b/source/blender/draw/intern/draw_view.h @@ -0,0 +1,35 @@ +/* + * 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_view.h + * \ingroup draw + */ + +#ifndef __DRAW_VIEW_H__ +#define __DRAW_VIEW_H__ + +void DRW_draw_grid(void); +void DRW_draw_region_info(void); +void DRW_draw_background(void); +void DRW_draw_cursor(void); +void DRW_draw_manipulator(void); + +#endif /* __DRAW_VIEW_H__ */
\ No newline at end of file diff --git a/source/blender/draw/modes/edit_armature_mode.c b/source/blender/draw/modes/edit_armature_mode.c new file mode 100644 index 00000000000..e55a368c9be --- /dev/null +++ b/source/blender/draw/modes/edit_armature_mode.c @@ -0,0 +1,114 @@ +/* + * 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/modes/edit_armature_mode.c + * \ingroup draw + */ + +#include "DRW_engine.h" +#include "DRW_render.h" + +#include "DNA_armature_types.h" + +#include "draw_mode_pass.h" + +#include "edit_armature_mode.h" + +/* keep it under MAX_PASSES */ +typedef struct EDIT_ARMATURE_PassList { + struct DRWPass *non_meshes_pass; + struct DRWPass *ob_center_pass; + struct DRWPass *wire_outline_pass; + struct DRWPass *bone_solid_pass; + struct DRWPass *bone_wire_pass; +} EDIT_ARMATURE_PassList; + +void EDIT_ARMATURE_cache_init(void) +{ + EDIT_ARMATURE_PassList *psl = DRW_mode_pass_list_get(); + static struct GPUShader *depth_sh; + + if (!depth_sh) { + depth_sh = DRW_shader_create_3D_depth_only(); + } + + DRW_mode_passes_setup(NULL, + NULL, + &psl->wire_outline_pass, + &psl->non_meshes_pass, + &psl->ob_center_pass, + &psl->bone_solid_pass, + &psl->bone_wire_pass); +} + +void EDIT_ARMATURE_cache_populate(Object *ob) +{ + bArmature *arm = ob->data; + + switch (ob->type) { + case OB_ARMATURE: + /* detect Edit Armature mode */ + if (arm->edbo) + DRW_shgroup_armature_edit(ob); + else + DRW_shgroup_armature_object(ob); + break; + case OB_MESH: + break; + case OB_LAMP: + DRW_shgroup_lamp(ob); + break; + case OB_CAMERA: + case OB_EMPTY: + DRW_shgroup_empty(ob); + break; + case OB_SPEAKER: + DRW_shgroup_speaker(ob); + break; + default: + break; + } + + DRW_shgroup_object_center(ob); + DRW_shgroup_relationship_lines(ob); +} + +void EDIT_ARMATURE_cache_finish(void) +{ + /* Do nothing */ +} + +void EDIT_ARMATURE_draw(void) +{ + EDIT_ARMATURE_PassList *psl = DRW_mode_pass_list_get(); + + DRW_draw_pass(psl->bone_solid_pass); + DRW_draw_pass(psl->bone_wire_pass); + DRW_draw_pass(psl->wire_outline_pass); + DRW_draw_pass(psl->non_meshes_pass); + DRW_draw_pass(psl->ob_center_pass); +} + +void EDIT_ARMATURE_collection_settings_create(CollectionEngineSettings *ces) +{ + BLI_assert(ces); + //BKE_collection_engine_property_add_int(ces, "show_occlude_wire", false); +} diff --git a/source/blender/draw/modes/edit_armature_mode.h b/source/blender/draw/modes/edit_armature_mode.h new file mode 100644 index 00000000000..89354cdf938 --- /dev/null +++ b/source/blender/draw/modes/edit_armature_mode.h @@ -0,0 +1,37 @@ +/* + * 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/modes/edit_armature_mode.h + * \ingroup draw + */ + +#ifndef __EDIT_ARMATURE_MODE_H__ +#define __EDIT_ARMATURE_MODE_H__ + +struct Object; + +void EDIT_ARMATURE_cache_init(void); +void EDIT_ARMATURE_cache_populate(struct Object *ob); +void EDIT_ARMATURE_cache_finish(void); + +void EDIT_ARMATURE_draw(void); + +#endif /* __EDIT_ARMATURE_MODE_H__ */
\ No newline at end of file diff --git a/source/blender/draw/modes/edit_mesh_mode.c b/source/blender/draw/modes/edit_mesh_mode.c new file mode 100644 index 00000000000..d2299158e44 --- /dev/null +++ b/source/blender/draw/modes/edit_mesh_mode.c @@ -0,0 +1,119 @@ +/* + * 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/modes/edit_mesh_mode.c + * \ingroup draw + */ + +#include "DRW_engine.h" +#include "DRW_render.h" + +#include "draw_mode_pass.h" + +#include "edit_mesh_mode.h" + +/* keep it under MAX_PASSES */ +typedef struct EDIT_MESH_PassList { + struct DRWPass *non_meshes_pass; + struct DRWPass *ob_center_pass; + struct DRWPass *wire_outline_pass; + struct DRWPass *depth_pass_hidden_wire; +} EDIT_MESH_PassList; + +static DRWShadingGroup *depth_shgrp_hidden_wire; + +void EDIT_MESH_cache_init(void) +{ + EDIT_MESH_PassList *psl = DRW_mode_pass_list_get(); + static struct GPUShader *depth_sh; + + if (!depth_sh) { + depth_sh = DRW_shader_create_3D_depth_only(); + } + + psl->depth_pass_hidden_wire = DRW_pass_create("Depth Pass Hidden Wire", DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS | DRW_STATE_CULL_BACK); + depth_shgrp_hidden_wire = DRW_shgroup_create(depth_sh, psl->depth_pass_hidden_wire); + + DRW_mode_passes_setup(NULL, + NULL, + &psl->wire_outline_pass, + &psl->non_meshes_pass, + &psl->ob_center_pass, + NULL, + NULL); +} + +void EDIT_MESH_cache_populate(Object *ob) +{ + struct Batch *geom; + + CollectionEngineSettings *ces_mode_ed = BKE_object_collection_engine_get(ob, COLLECTION_MODE_EDIT, ""); + bool do_occlude_wire = BKE_collection_engine_property_value_get_bool(ces_mode_ed, "show_occlude_wire"); + + switch (ob->type) { + case OB_MESH: + geom = DRW_cache_surface_get(ob); + if (do_occlude_wire) { + DRW_shgroup_call_add(depth_shgrp_hidden_wire, geom, ob->obmat); + DRW_shgroup_wire_outline(ob, true, false, true); + } + break; + case OB_LAMP: + DRW_shgroup_lamp(ob); + break; + case OB_CAMERA: + case OB_EMPTY: + DRW_shgroup_empty(ob); + break; + case OB_SPEAKER: + DRW_shgroup_speaker(ob); + break; + case OB_ARMATURE: + DRW_shgroup_armature_object(ob); + break; + default: + break; + } + + DRW_shgroup_object_center(ob); + DRW_shgroup_relationship_lines(ob); +} + +void EDIT_MESH_cache_finish(void) +{ + /* Do nothing */ +} + +void EDIT_MESH_draw(void) +{ + EDIT_MESH_PassList *psl = DRW_mode_pass_list_get(); + + DRW_draw_pass(psl->depth_pass_hidden_wire); + DRW_draw_pass(psl->wire_outline_pass); + DRW_draw_pass(psl->non_meshes_pass); + DRW_draw_pass(psl->ob_center_pass); +} + +void EDIT_MESH_collection_settings_create(CollectionEngineSettings *ces) +{ + BLI_assert(ces); + BKE_collection_engine_property_add_int(ces, "show_occlude_wire", false); +} diff --git a/source/blender/draw/modes/edit_mesh_mode.h b/source/blender/draw/modes/edit_mesh_mode.h new file mode 100644 index 00000000000..bb1794a5ed3 --- /dev/null +++ b/source/blender/draw/modes/edit_mesh_mode.h @@ -0,0 +1,37 @@ +/* + * 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/modes/edit_mesh_mode.h + * \ingroup draw + */ + +#ifndef __EDIT_MESH_MODE_H__ +#define __EDIT_MESH_MODE_H__ + +struct Object; + +void EDIT_MESH_cache_init(void); +void EDIT_MESH_cache_populate(struct Object *ob); +void EDIT_MESH_cache_finish(void); + +void EDIT_MESH_draw(void); + +#endif /* __EDIT_MESH_MODE_H__ */
\ No newline at end of file diff --git a/source/blender/draw/modes/object_mode.c b/source/blender/draw/modes/object_mode.c new file mode 100644 index 00000000000..e9fec871528 --- /dev/null +++ b/source/blender/draw/modes/object_mode.c @@ -0,0 +1,108 @@ +/* + * 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/modes/object_mode.c + * \ingroup draw + */ + +#include "DRW_engine.h" +#include "DRW_render.h" + +#include "draw_mode_pass.h" + +#include "object_mode.h" + +/* keep it under MAX_PASSES */ +typedef struct OBJECT_PassList { + struct DRWPass *non_meshes_pass; + struct DRWPass *ob_center_pass; + struct DRWPass *wire_outline_pass; + struct DRWPass *bone_solid_pass; + struct DRWPass *bone_wire_pass; +} OBJECT_PassList; + +void OBJECT_cache_init(void) +{ + OBJECT_PassList *psl = DRW_mode_pass_list_get(); + + DRW_mode_passes_setup(NULL, + NULL, + &psl->wire_outline_pass, + &psl->non_meshes_pass, + &psl->ob_center_pass, + &psl->bone_solid_pass, + &psl->bone_wire_pass); +} + +void OBJECT_cache_populate(Object *ob) +{ + CollectionEngineSettings *ces_mode_ob = BKE_object_collection_engine_get(ob, COLLECTION_MODE_OBJECT, ""); + + bool do_wire = BKE_collection_engine_property_value_get_bool(ces_mode_ob, "show_wire"); + bool do_outlines = ((ob->base_flag & BASE_SELECTED) != 0) || do_wire; + + switch (ob->type) { + case OB_MESH: + DRW_shgroup_wire_outline(ob, do_wire, false, do_outlines); + break; + case OB_LAMP: + DRW_shgroup_lamp(ob); + break; + case OB_CAMERA: + case OB_EMPTY: + DRW_shgroup_empty(ob); + break; + case OB_SPEAKER: + DRW_shgroup_speaker(ob); + break; + case OB_ARMATURE: + DRW_shgroup_armature_object(ob); + break; + default: + break; + } + + DRW_shgroup_object_center(ob); + DRW_shgroup_relationship_lines(ob); +} + +void OBJECT_cache_finish(void) +{ + /* Do nothing */ +} + +void OBJECT_draw(void) +{ + OBJECT_PassList *psl = DRW_mode_pass_list_get(); + + DRW_draw_pass(psl->bone_wire_pass); + DRW_draw_pass(psl->bone_solid_pass); + DRW_draw_pass(psl->wire_outline_pass); + DRW_draw_pass(psl->non_meshes_pass); + DRW_draw_pass(psl->ob_center_pass); +} + +void OBJECT_collection_settings_create(CollectionEngineSettings *ces) +{ + BLI_assert(ces); + BKE_collection_engine_property_add_int(ces, "show_wire", false); + BKE_collection_engine_property_add_int(ces, "show_backface_culling", false); +} diff --git a/source/blender/draw/modes/object_mode.h b/source/blender/draw/modes/object_mode.h new file mode 100644 index 00000000000..fda9096203d --- /dev/null +++ b/source/blender/draw/modes/object_mode.h @@ -0,0 +1,37 @@ +/* + * 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/modes/object_mode.h + * \ingroup draw + */ + +#ifndef __OBJECT_MODE_H__ +#define __OBJECT_MODE_H__ + +struct Object; + +void OBJECT_cache_init(void); +void OBJECT_cache_populate(struct Object *ob); +void OBJECT_cache_finish(void); + +void OBJECT_draw(void); + +#endif /* __OBJECT_MODE_H__ */
\ No newline at end of file diff --git a/source/blender/editors/animation/anim_channels_defines.c b/source/blender/editors/animation/anim_channels_defines.c index 57302c18a88..f41c4741eff 100644 --- a/source/blender/editors/animation/anim_channels_defines.c +++ b/source/blender/editors/animation/anim_channels_defines.c @@ -68,6 +68,8 @@ #include "BKE_nla.h" #include "BKE_context.h" +#include "GPU_immediate.h" + #include "UI_interface.h" #include "UI_interface_icons.h" #include "UI_resources.h" @@ -119,11 +121,10 @@ static void acf_generic_root_backdrop(bAnimContext *ac, bAnimListElem *ale, floa /* set backdrop drawing color */ acf->get_backdrop_color(ac, ale, color); - glColor3fv(color); /* rounded corners on LHS only - top only when expanded, but bottom too when collapsed */ UI_draw_roundbox_corner_set((expanded) ? UI_CNR_TOP_LEFT : (UI_CNR_TOP_LEFT | UI_CNR_BOTTOM_LEFT)); - UI_draw_roundbox_gl_mode(GL_POLYGON, offset, yminc, v2d->cur.xmax + EXTRA_SCROLL_PAD, ymaxc, 8); + UI_draw_roundbox_gl_mode_3fvAlpha(GL_TRIANGLE_FAN, offset, yminc, v2d->cur.xmax + EXTRA_SCROLL_PAD, ymaxc, 8, color, 1.0f); } @@ -141,13 +142,19 @@ static void acf_generic_dataexpand_backdrop(bAnimContext *ac, bAnimListElem *ale View2D *v2d = &ac->ar->v2d; short offset = (acf->get_offset) ? acf->get_offset(ac, ale) : 0; float color[3]; - + + unsigned pos = add_attrib(immVertexFormat(), "pos", GL_FLOAT, 2, KEEP_FLOAT); + /* set backdrop drawing color */ acf->get_backdrop_color(ac, ale, color); - glColor3fv(color); - + + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + immUniformColor3fv(color); + /* no rounded corner - just rectangular box */ - glRectf(offset, yminc, v2d->cur.xmax + EXTRA_SCROLL_PAD, ymaxc); + immRectf(pos, offset, yminc, v2d->cur.xmax + EXTRA_SCROLL_PAD, ymaxc); + + immUnbindProgram(); } /* helper method to test if group colors should be drawn */ @@ -224,13 +231,19 @@ static void acf_generic_channel_backdrop(bAnimContext *ac, bAnimListElem *ale, f View2D *v2d = &ac->ar->v2d; short offset = (acf->get_offset) ? acf->get_offset(ac, ale) : 0; float color[3]; + + unsigned pos = add_attrib(immVertexFormat(), "pos", GL_FLOAT, 2, KEEP_FLOAT); /* set backdrop drawing color */ acf->get_backdrop_color(ac, ale, color); - glColor3fv(color); + + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + immUniformColor3fv(color); /* no rounded corners - just rectangular box */ - glRectf(offset, yminc, v2d->cur.xmax + EXTRA_SCROLL_PAD, ymaxc); + immRectf(pos, offset, yminc, v2d->cur.xmax + EXTRA_SCROLL_PAD, ymaxc); + + immUnbindProgram(); } /* Indention + Offset ------------------------------------------- */ @@ -421,14 +434,13 @@ static void acf_summary_backdrop(bAnimContext *ac, bAnimListElem *ale, float ymi /* set backdrop drawing color */ acf->get_backdrop_color(ac, ale, color); - glColor3fv(color); /* rounded corners on LHS only * - top and bottom * - special hack: make the top a bit higher, since we are first... */ UI_draw_roundbox_corner_set(UI_CNR_TOP_LEFT | UI_CNR_BOTTOM_LEFT); - UI_draw_roundbox_gl_mode(GL_POLYGON, 0, yminc - 2, v2d->cur.xmax + EXTRA_SCROLL_PAD, ymaxc, 8); + UI_draw_roundbox_gl_mode_3fvAlpha(GL_TRIANGLE_FAN, 0, yminc - 2, v2d->cur.xmax + EXTRA_SCROLL_PAD, ymaxc, 8, color, 1.0f); } /* name for summary entries */ @@ -617,7 +629,7 @@ static bAnimChannelType ACF_SCENE = static int acf_object_icon(bAnimListElem *ale) { - Base *base = (Base *)ale->data; + BaseLegacy *base = (BaseLegacy *)ale->data; Object *ob = base->object; /* icon depends on object-type */ @@ -652,7 +664,7 @@ static int acf_object_icon(bAnimListElem *ale) /* name for object */ static void acf_object_name(bAnimListElem *ale, char *name) { - Base *base = (Base *)ale->data; + BaseLegacy *base = (BaseLegacy *)ale->data; Object *ob = base->object; /* just copy the name... */ @@ -672,7 +684,7 @@ static bool acf_object_name_prop(bAnimListElem *ale, PointerRNA *ptr, PropertyRN /* check if some setting exists for this channel */ static bool acf_object_setting_valid(bAnimContext *ac, bAnimListElem *ale, eAnimChannel_Settings setting) { - Base *base = (Base *)ale->data; + BaseLegacy *base = (BaseLegacy *)ale->data; Object *ob = base->object; switch (setting) { @@ -729,7 +741,7 @@ static int acf_object_setting_flag(bAnimContext *UNUSED(ac), eAnimChannel_Settin /* get pointer to the setting */ static void *acf_object_setting_ptr(bAnimListElem *ale, eAnimChannel_Settings setting, short *type) { - Base *base = (Base *)ale->data; + BaseLegacy *base = (BaseLegacy *)ale->data; Object *ob = base->object; /* clear extra return data first */ @@ -814,11 +826,10 @@ static void acf_group_backdrop(bAnimContext *ac, bAnimListElem *ale, float yminc /* set backdrop drawing color */ acf->get_backdrop_color(ac, ale, color); - glColor3fv(color); /* rounded corners on LHS only - top only when expanded, but bottom too when collapsed */ UI_draw_roundbox_corner_set(expanded ? UI_CNR_TOP_LEFT : (UI_CNR_TOP_LEFT | UI_CNR_BOTTOM_LEFT)); - UI_draw_roundbox_gl_mode(GL_POLYGON, offset, yminc, v2d->cur.xmax + EXTRA_SCROLL_PAD, ymaxc, 8); + UI_draw_roundbox_gl_mode_3fvAlpha(GL_TRIANGLE_FAN, offset, yminc, v2d->cur.xmax + EXTRA_SCROLL_PAD, ymaxc, 8, color, 1.0f); } /* name for group entries */ @@ -1071,11 +1082,10 @@ static void acf_nla_controls_backdrop(bAnimContext *ac, bAnimListElem *ale, floa /* set backdrop drawing color */ acf->get_backdrop_color(ac, ale, color); - glColor3fv(color); - /* rounded corners on LHS only - top only when expanded, but bottom too when collapsed */ + /* rounded corners on LHS only - top only when expanded, but bottom too when collapsed */ UI_draw_roundbox_corner_set(expanded ? UI_CNR_TOP_LEFT : (UI_CNR_TOP_LEFT | UI_CNR_BOTTOM_LEFT)); - UI_draw_roundbox_gl_mode(GL_POLYGON, offset, yminc, v2d->cur.xmax + EXTRA_SCROLL_PAD, ymaxc, 5); + UI_draw_roundbox_gl_mode_3fvAlpha(GL_TRIANGLE_FAN, offset, yminc, v2d->cur.xmax + EXTRA_SCROLL_PAD, ymaxc, 5, color, 1.0f); } /* name for nla controls expander entries */ @@ -2018,7 +2028,7 @@ static int acf_dspart_setting_flag(bAnimContext *UNUSED(ac), eAnimChannel_Settin switch (setting) { case ACHANNEL_SETTING_EXPAND: /* expanded */ - return PART_DS_EXPAND; + return 0; case ACHANNEL_SETTING_MUTE: /* mute (only in NLA) */ return ADT_NLA_EVAL_OFF; @@ -2036,22 +2046,18 @@ static int acf_dspart_setting_flag(bAnimContext *UNUSED(ac), eAnimChannel_Settin } /* get pointer to the setting */ -static void *acf_dspart_setting_ptr(bAnimListElem *ale, eAnimChannel_Settings setting, short *type) +static void *acf_dspart_setting_ptr(bAnimListElem *UNUSED(ale), eAnimChannel_Settings setting, short *type) { - ParticleSettings *part = (ParticleSettings *)ale->data; - /* clear extra return data first */ *type = 0; switch (setting) { case ACHANNEL_SETTING_EXPAND: /* expanded */ - return GET_ACF_FLAG_PTR(part->flag, type); + return NULL; case ACHANNEL_SETTING_SELECT: /* selected */ case ACHANNEL_SETTING_MUTE: /* muted (for NLA only) */ case ACHANNEL_SETTING_VISIBLE: /* visible (for Graph Editor only) */ - if (part->adt) - return GET_ACF_FLAG_PTR(part->adt->flag, type); return NULL; default: /* unsupported */ @@ -3420,24 +3426,20 @@ static void acf_nlaaction_backdrop(bAnimContext *ac, bAnimListElem *ale, float y */ nla_action_get_color(adt, (bAction *)ale->data, color); - if (adt && (adt->flag & ADT_NLA_EDIT_ON)) { - /* Yes, the color vector has 4 components, BUT we only want to be using 3 of them! */ - glColor3fv(color); - } - else { - float alpha = (adt && (adt->flag & ADT_NLA_SOLO_TRACK)) ? 0.3f : 1.0f; - glColor4f(color[0], color[1], color[2], alpha); - } - - /* only on top left corner, to show that this channel sits on top of the preceding ones + if (adt && (adt->flag & ADT_NLA_EDIT_ON)) + color[3] = 1.0f; + else + color[3] = (adt && (adt->flag & ADT_NLA_SOLO_TRACK)) ? 0.3f : 1.0f; + + /* only on top left corner, to show that this channel sits on top of the preceding ones * while still linking into the action line strip to the right */ UI_draw_roundbox_corner_set(UI_CNR_TOP_LEFT); - + /* draw slightly shifted up vertically to look like it has more separation from other channels, * but we then need to slightly shorten it so that it doesn't look like it overlaps */ - UI_draw_roundbox_gl_mode(GL_POLYGON, offset, yminc + NLACHANNEL_SKIP, (float)v2d->cur.xmax, ymaxc + NLACHANNEL_SKIP - 1, 8); + UI_draw_roundbox_gl_mode(GL_TRIANGLE_FAN, offset, yminc + NLACHANNEL_SKIP, (float)v2d->cur.xmax, ymaxc + NLACHANNEL_SKIP - 1, 8, color); } /* name for nla action entries */ @@ -3860,15 +3862,20 @@ void ANIM_channel_draw(bAnimContext *ac, bAnimListElem *ale, float yminc, float /* for F-Curves, draw color-preview of curve behind checkbox */ if (ELEM(ale->type, ANIMTYPE_FCURVE, ANIMTYPE_NLACURVE)) { FCurve *fcu = (FCurve *)ale->data; + unsigned pos = add_attrib(immVertexFormat(), "pos", GL_FLOAT, 2, KEEP_FLOAT); + + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); /* F-Curve channels need to have a special 'color code' box drawn, which is colored with whatever * color the curve has stored */ - glColor3fv(fcu->color); + immUniformColor3fv(fcu->color); /* just a solid color rect */ - glRectf(offset, yminc, offset + ICON_WIDTH, ymaxc); + immRectf(pos, offset, yminc, offset + ICON_WIDTH, ymaxc); + + immUnbindProgram(); } /* icon is drawn as widget now... */ if (acf->has_setting(ac, ale, ACHANNEL_SETTING_VISIBLE)) { @@ -3893,27 +3900,39 @@ void ANIM_channel_draw(bAnimContext *ac, bAnimListElem *ale, float yminc, float if (acf->name && !achannel_is_being_renamed(ac, acf, channel_index)) { const uiFontStyle *fstyle = UI_FSTYLE_WIDGET; char name[ANIM_CHAN_NAME_SIZE]; /* hopefully this will be enough! */ - + unsigned char col[4]; + /* set text color */ /* XXX: if active, highlight differently? */ + if (selected) - UI_ThemeColor(TH_TEXT_HI); + UI_GetThemeColor4ubv(TH_TEXT_HI, col); else - UI_ThemeColor(TH_TEXT); - + UI_GetThemeColor4ubv(TH_TEXT, col); + /* get name */ acf->name(ale, name); offset += 3; - UI_fontstyle_draw_simple(fstyle, offset, ytext, name); + UI_fontstyle_draw_simple(fstyle, offset, ytext, name, col); /* draw red underline if channel is disabled */ if (ELEM(ale->type, ANIMTYPE_FCURVE, ANIMTYPE_NLACURVE) && (ale->flag & FCURVE_DISABLED)) { + unsigned pos = add_attrib(immVertexFormat(), "pos", GL_FLOAT, 2, KEEP_FLOAT); + + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + /* FIXME: replace hardcoded color here, and check on extents! */ - glColor3f(1.0f, 0.0f, 0.0f); - glLineWidth(2.0); - fdrawline((float)(offset), yminc, - (float)(v2d->cur.xmax), yminc); + immUniformColor3f(1.0f, 0.0f, 0.0f); + + glLineWidth(2.0f); + + immBegin(GL_LINES, 2); + immVertex2f(pos, (float)offset, yminc); + immVertex2f(pos, (float)v2d->cur.xmax, yminc); + immEnd(); + + immUnbindProgram(); } } @@ -3927,10 +3946,13 @@ void ANIM_channel_draw(bAnimContext *ac, bAnimListElem *ale, float yminc, float short draw_sliders = 0; float ymin_ofs = 0.0f; float color[3]; + unsigned pos = add_attrib(immVertexFormat(), "pos", GL_FLOAT, 2, KEEP_FLOAT); + + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); /* get and set backdrop color */ acf->get_backdrop_color(ac, ale, color); - glColor3fv(color); + immUniformColor3fv(color); /* check if we need to show the sliders */ if ((ac->sl) && ELEM(ac->spacetype, SPACE_ACTION, SPACE_IPO)) { @@ -3988,7 +4010,9 @@ void ANIM_channel_draw(bAnimContext *ac, bAnimListElem *ale, float yminc, float * - starts from the point where the first toggle/slider starts, * - ends past the space that might be reserved for a scroller */ - glRectf(v2d->cur.xmax - (float)offset, yminc + ymin_ofs, v2d->cur.xmax + EXTRA_SCROLL_PAD, ymaxc); + immRectf(pos, v2d->cur.xmax - (float)offset, yminc + ymin_ofs, v2d->cur.xmax + EXTRA_SCROLL_PAD, ymaxc); + + immUnbindProgram(); } } diff --git a/source/blender/editors/animation/anim_channels_edit.c b/source/blender/editors/animation/anim_channels_edit.c index 117b8549712..22578b6a518 100644 --- a/source/blender/editors/animation/anim_channels_edit.c +++ b/source/blender/editors/animation/anim_channels_edit.c @@ -57,6 +57,7 @@ #include "BKE_context.h" #include "BKE_mask.h" #include "BKE_global.h" +#include "BKE_scene.h" #include "UI_view2d.h" @@ -2682,31 +2683,31 @@ static int mouse_anim_channels(bContext *C, bAnimContext *ac, int channel_index, { bDopeSheet *ads = (bDopeSheet *)ac->data; Scene *sce = (Scene *)ads->source; - Base *base = (Base *)ale->data; + BaseLegacy *base = (BaseLegacy *)ale->data; Object *ob = base->object; AnimData *adt = ob->adt; /* set selection status */ if (selectmode == SELECT_INVERT) { /* swap select */ - base->flag ^= SELECT; - ob->flag = base->flag; + base->flag_legacy ^= SELECT; + BKE_scene_base_flag_sync_from_base(base); if (adt) adt->flag ^= ADT_UI_SELECTED; } else { - Base *b; + BaseLegacy *b; /* deselect all */ /* TODO: should this deselect all other types of channels too? */ for (b = sce->base.first; b; b = b->next) { - b->flag &= ~SELECT; - b->object->flag = b->flag; + b->flag_legacy &= ~SELECT; + BKE_scene_base_flag_sync_from_base(b); if (b->object->adt) b->object->adt->flag &= ~(ADT_UI_SELECTED | ADT_UI_ACTIVE); } /* select object now */ - base->flag |= SELECT; + base->flag_legacy |= SELECT; ob->flag |= SELECT; if (adt) adt->flag |= ADT_UI_SELECTED; } diff --git a/source/blender/editors/animation/anim_draw.c b/source/blender/editors/animation/anim_draw.c index 98900812bb2..1d71ba8dc34 100644 --- a/source/blender/editors/animation/anim_draw.c +++ b/source/blender/editors/animation/anim_draw.c @@ -64,6 +64,8 @@ #include "UI_resources.h" #include "UI_view2d.h" +#include "GPU_immediate.h" + /* *************************************************** */ /* CURRENT FRAME DRAWING */ @@ -71,6 +73,9 @@ static void draw_cfra_number(Scene *scene, View2D *v2d, const float cfra, const bool time) { const uiFontStyle *fstyle = UI_FSTYLE_WIDGET; + VertexFormat *format = immVertexFormat(); + unsigned int pos = add_attrib(format, "pos", GL_FLOAT, 2, KEEP_FLOAT); + unsigned char col[4]; float xscale, yscale, x, y; char numstr[32] = " t"; /* t is the character to start replacing from */ int slen; @@ -96,15 +101,19 @@ static void draw_cfra_number(Scene *scene, View2D *v2d, const float cfra, const /* get starting coordinates for drawing */ x = cfra * xscale; y = 0.9f * U.widget_unit; - + + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + /* draw green box around/behind text */ - UI_ThemeColorShade(TH_CFRAME, 0); - glRectf(x, y, x + slen, y + 0.75f * U.widget_unit); - + immUniformThemeColorShade(TH_CFRAME, 0); + + immRectf(pos, x, y, x + slen, y + 0.75f * U.widget_unit); + immUnbindProgram(); + /* draw current frame number - black text */ - UI_ThemeColor(TH_TEXT); - UI_fontstyle_draw_simple(fstyle, x - 0.25f * U.widget_unit, y + 0.15f * U.widget_unit, numstr); - + UI_GetThemeColor4ubv(TH_TEXT, col); + UI_fontstyle_draw_simple(fstyle, x - 0.25f * U.widget_unit, y + 0.15f * U.widget_unit, numstr, col); + /* restore view transform */ glScalef(xscale, 1.0, 1.0); } @@ -114,18 +123,24 @@ void ANIM_draw_cfra(const bContext *C, View2D *v2d, short flag) { Scene *scene = CTX_data_scene(C); - /* Draw a light green line to indicate current frame */ - UI_ThemeColor(TH_CFRAME); - const float time = scene->r.cfra + scene->r.subframe; const float x = (float)(time * scene->r.framelen); glLineWidth((flag & DRAWCFRA_WIDE) ? 3.0 : 2.0); - glBegin(GL_LINES); - glVertex2f(x, v2d->cur.ymin - 500.0f); /* XXX arbitrary... want it go to bottom */ - glVertex2f(x, v2d->cur.ymax); - glEnd(); + VertexFormat *format = immVertexFormat(); + unsigned pos = add_attrib(format, "pos", GL_FLOAT, 2, KEEP_FLOAT); + + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + + /* Draw a light green line to indicate current frame */ + immUniformThemeColor(TH_CFRAME); + + immBegin(GL_LINES, 2); + immVertex2f(pos, x, v2d->cur.ymin - 500.0f); /* XXX arbitrary... want it go to bottom */ + immVertex2f(pos, x, v2d->cur.ymax); + immEnd(); + immUnbindProgram(); /* Draw current frame number in a little box */ if (flag & DRAWCFRA_SHOW_NUMBOX) { @@ -147,17 +162,24 @@ void ANIM_draw_previewrange(const bContext *C, View2D *v2d, int end_frame_width) if (PRVRANGEON) { glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glEnable(GL_BLEND); - glColor4f(0.0f, 0.0f, 0.0f, 0.4f); - + + VertexFormat *format = immVertexFormat(); + unsigned pos = add_attrib(format, "pos", GL_FLOAT, 2, KEEP_FLOAT); + + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + immUniformColor4f(0.0f, 0.0f, 0.0f, 0.4f); + /* only draw two separate 'curtains' if there's no overlap between them */ if (PSFRA < PEFRA + end_frame_width) { - glRectf(v2d->cur.xmin, v2d->cur.ymin, (float)PSFRA, v2d->cur.ymax); - glRectf((float)(PEFRA + end_frame_width), v2d->cur.ymin, v2d->cur.xmax, v2d->cur.ymax); + immRectf(pos, v2d->cur.xmin, v2d->cur.ymin, (float)PSFRA, v2d->cur.ymax); + immRectf(pos, (float)(PEFRA + end_frame_width), v2d->cur.ymin, v2d->cur.xmax, v2d->cur.ymax); } else { - glRectf(v2d->cur.xmin, v2d->cur.ymin, v2d->cur.xmax, v2d->cur.ymax); + immRectf(pos, v2d->cur.xmin, v2d->cur.ymin, v2d->cur.xmax, v2d->cur.ymax); } - + + immUnbindProgram(); + glDisable(GL_BLEND); } } diff --git a/source/blender/editors/animation/anim_filter.c b/source/blender/editors/animation/anim_filter.c index 2f73eb6b71c..7b6d30469a4 100644 --- a/source/blender/editors/animation/anim_filter.c +++ b/source/blender/editors/animation/anim_filter.c @@ -601,7 +601,7 @@ static bAnimListElem *make_new_animlistelem(void *data, short datatype, ID *owne } case ANIMTYPE_OBJECT: { - Base *base = (Base *)data; + BaseLegacy *base = (BaseLegacy *)data; Object *ob = base->object; ale->flag = ob->flag; @@ -1683,7 +1683,7 @@ static size_t animdata_filter_gpencil(bAnimContext *ac, ListBase *anim_data, voi if (ads->filterflag & ADS_FILTER_GP_3DONLY) { Scene *scene = (Scene *)ads->source; - Base *base; + BaseLegacy *base; /* Active scene's GPencil block first - No parent item needed... */ if (scene->gpd) { @@ -1714,7 +1714,7 @@ static size_t animdata_filter_gpencil(bAnimContext *ac, ListBase *anim_data, voi } /* check selection and object type filters */ - if ( (ads->filterflag & ADS_FILTER_ONLYSEL) && !((base->flag & SELECT) /*|| (base == scene->basact)*/) ) { + if ( (ads->filterflag & ADS_FILTER_ONLYSEL) && !((base->flag_legacy & SELECT) /*|| (base == scene->basact)*/) ) { /* only selected should be shown */ continue; } @@ -2573,7 +2573,7 @@ static size_t animdata_filter_ds_obanim(bAnimContext *ac, ListBase *anim_data, b } /* get animation channels from object2 */ -static size_t animdata_filter_dopesheet_ob(bAnimContext *ac, ListBase *anim_data, bDopeSheet *ads, Base *base, int filter_mode) +static size_t animdata_filter_dopesheet_ob(bAnimContext *ac, ListBase *anim_data, bDopeSheet *ads, BaseLegacy *base, int filter_mode) { ListBase tmp_data = {NULL, NULL}; Object *ob = base->object; @@ -2629,7 +2629,7 @@ static size_t animdata_filter_dopesheet_ob(bAnimContext *ac, ListBase *anim_data if (filter_mode & ANIMFILTER_LIST_CHANNELS) { /* check if filtering by selection */ // XXX: double-check on this - most of the time, a lot of tools need to filter out these channels! - if (ANIMCHANNEL_SELOK((base->flag & SELECT))) { + if (ANIMCHANNEL_SELOK((base->flag_legacy & SELECT))) { /* check if filtering by active status */ if (ANIMCHANNEL_ACTIVEOK(ob)) { ANIMCHANNEL_NEW_CHANNEL(base, ANIMTYPE_OBJECT, ob); @@ -2853,7 +2853,7 @@ static size_t animdata_filter_dopesheet_movieclips(bAnimContext *ac, ListBase *a } /* Helper for animdata_filter_dopesheet() - For checking if an object should be included or not */ -static bool animdata_filter_base_is_ok(bDopeSheet *ads, Scene *scene, Base *base, int filter_mode) +static bool animdata_filter_base_is_ok(bDopeSheet *ads, Scene *scene, BaseLegacy *base, int filter_mode) { Object *ob = base->object; @@ -2906,7 +2906,7 @@ static bool animdata_filter_base_is_ok(bDopeSheet *ads, Scene *scene, Base *base } /* check selection and object type filters */ - if ((ads->filterflag & ADS_FILTER_ONLYSEL) && !((base->flag & SELECT) /*|| (base == sce->basact)*/)) { + if ((ads->filterflag & ADS_FILTER_ONLYSEL) && !((base->flag_legacy & SELECT) /*|| (base == sce->basact)*/)) { /* only selected should be shown */ return false; } @@ -2927,28 +2927,28 @@ static bool animdata_filter_base_is_ok(bDopeSheet *ads, Scene *scene, Base *base /* Helper for animdata_filter_ds_sorted_bases() - Comparison callback for two Base pointers... */ static int ds_base_sorting_cmp(const void *base1_ptr, const void *base2_ptr) { - const Base *b1 = *((const Base **)base1_ptr); - const Base *b2 = *((const Base **)base2_ptr); + const BaseLegacy *b1 = *((const BaseLegacy **)base1_ptr); + const BaseLegacy *b2 = *((const BaseLegacy **)base2_ptr); return strcmp(b1->object->id.name + 2, b2->object->id.name + 2); } /* Get a sorted list of all the bases - for inclusion in dopesheet (when drawing channels) */ -static Base **animdata_filter_ds_sorted_bases(bDopeSheet *ads, Scene *scene, int filter_mode, size_t *r_usable_bases) +static BaseLegacy **animdata_filter_ds_sorted_bases(bDopeSheet *ads, Scene *scene, int filter_mode, size_t *r_usable_bases) { /* Create an array with space for all the bases, but only containing the usable ones */ size_t tot_bases = BLI_listbase_count(&scene->base); size_t num_bases = 0; - Base **sorted_bases = MEM_mallocN(sizeof(Base *) * tot_bases, "Dopesheet Usable Sorted Bases"); - for (Base *base = scene->base.first; base; base = base->next) { + BaseLegacy **sorted_bases = MEM_mallocN(sizeof(BaseLegacy *) * tot_bases, "Dopesheet Usable Sorted Bases"); + for (BaseLegacy *base = scene->base.first; base; base = base->next) { if (animdata_filter_base_is_ok(ads, scene, base, filter_mode)) { sorted_bases[num_bases++] = base; } } /* Sort this list of pointers (based on the names) */ - qsort(sorted_bases, num_bases, sizeof(Base *), ds_base_sorting_cmp); + qsort(sorted_bases, num_bases, sizeof(BaseLegacy *), ds_base_sorting_cmp); /* Return list of sorted bases */ *r_usable_bases = num_bases; @@ -3002,7 +3002,7 @@ static size_t animdata_filter_dopesheet(bAnimContext *ac, ListBase *anim_data, b { /* Filter list of bases (i.e. objects), sort them, then add their contents normally... */ // TODO: Cache the old sorted order - if the set of bases hasn't changed, don't re-sort... - Base **sorted_bases; + BaseLegacy **sorted_bases; size_t num_bases; sorted_bases = animdata_filter_ds_sorted_bases(ads, scene, filter_mode, &num_bases); @@ -3022,7 +3022,7 @@ static size_t animdata_filter_dopesheet(bAnimContext *ac, ListBase *anim_data, b /* Filter and add contents of each base (i.e. object) without them sorting first * NOTE: This saves performance in cases where order doesn't matter */ - for (Base *base = scene->base.first; base; base = base->next) { + for (BaseLegacy *base = scene->base.first; base; base = base->next) { if (animdata_filter_base_is_ok(ads, scene, base, filter_mode)) { /* since we're still here, this object should be usable */ items += animdata_filter_dopesheet_ob(ac, anim_data, ads, base, filter_mode); diff --git a/source/blender/editors/animation/anim_markers.c b/source/blender/editors/animation/anim_markers.c index 823cde75334..cc5957003b6 100644 --- a/source/blender/editors/animation/anim_markers.c +++ b/source/blender/editors/animation/anim_markers.c @@ -36,7 +36,7 @@ #include "DNA_object_types.h" #include "BLI_blenlib.h" -#include "BLI_math_base.h" +#include "BLI_math.h" #include "BLI_utildefines.h" #include "BLT_translation.h" @@ -59,6 +59,8 @@ #include "BIF_gl.h" #include "BIF_glutil.h" +#include "GPU_immediate.h" + #include "UI_interface.h" #include "UI_interface_icons.h" #include "UI_view2d.h" @@ -348,19 +350,24 @@ static void draw_marker( if (flag & DRAW_MARKERS_LINES) #endif { + unsigned int pos = add_attrib(immVertexFormat(), "pos", GL_FLOAT, 2, KEEP_FLOAT); + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); setlinestyle(3); - if (marker->flag & SELECT) - glColor4ub(255, 255, 255, 96); - else - glColor4ub(0, 0, 0, 96); - - glBegin(GL_LINES); - glVertex2f(xpos + 0.5f, 12.0f); - glVertex2f(xpos + 0.5f, (v2d->cur.ymax + 12.0f) * yscale); - glEnd(); - + if (marker->flag & SELECT) { + immUniformColor4ub(255, 255, 255, 96); + } + else { + immUniformColor4ub(0, 0, 0, 96); + } + + immBegin(GL_LINES, 2); + immVertex2f(pos, xpos + 0.5f, 12.0f); + immVertex2f(pos, xpos + 0.5f, (v2d->cur.ymax + 12.0f) * yscale); + immEnd(); setlinestyle(0); + + immUnbindProgram(); } /* 5 px to offset icon to align properly, space / pixels corrects for zoom */ @@ -380,19 +387,20 @@ static void draw_marker( /* and the marker name too, shifted slightly to the top-right */ if (marker->name[0]) { + unsigned char text_col[4]; float x, y; /* minimal y coordinate which wouldn't be occluded by scroll */ int min_y = 17.0f * UI_DPI_FAC; if (marker->flag & SELECT) { - UI_ThemeColor(TH_TEXT_HI); + UI_GetThemeColor4ubv(TH_TEXT_HI, text_col); x = xpos + 4.0f * UI_DPI_FAC; y = (ypixels <= 39.0f * UI_DPI_FAC) ? (ypixels - 10.0f * UI_DPI_FAC) : 29.0f * UI_DPI_FAC; y = max_ii(y, min_y); } else { - UI_ThemeColor(TH_TEXT); + UI_GetThemeColor4ubv(TH_TEXT, text_col); if ((marker->frame <= cfra) && (marker->frame + 5 > cfra)) { x = xpos + 8.0f * UI_DPI_FAC; y = (ypixels <= 39.0f * UI_DPI_FAC) ? (ypixels - 10.0f * UI_DPI_FAC) : 29.0f * UI_DPI_FAC; @@ -406,14 +414,11 @@ static void draw_marker( #ifdef DURIAN_CAMERA_SWITCH if (marker->camera && (marker->camera->restrictflag & OB_RESTRICT_RENDER)) { - float col[4]; - glGetFloatv(GL_CURRENT_COLOR, col); - col[3] = 0.4; - glColor4fv(col); + text_col[3] = 100; } #endif - UI_fontstyle_draw_simple(fstyle, x, y, marker->name); + UI_fontstyle_draw_simple(fstyle, x, y, marker->name, text_col); } } @@ -440,15 +445,20 @@ void ED_markers_draw(const bContext *C, int flag) v2d = UI_view2d_fromcontext(C); if (flag & DRAW_MARKERS_MARGIN) { + unsigned int pos = add_attrib(immVertexFormat(), "pos", GL_FLOAT, 2, KEEP_FLOAT); + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + const unsigned char shade[4] = {0, 0, 0, 16}; - glColor4ubv(shade); + immUniformColor4ubv(shade); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - glRectf(v2d->cur.xmin, 0, v2d->cur.xmax, UI_MARKER_MARGIN_Y); + immRectf(pos, v2d->cur.xmin, 0, v2d->cur.xmax, UI_MARKER_MARGIN_Y); glDisable(GL_BLEND); + + immUnbindProgram(); } /* no time correction for framelen! space is drawn with old values */ @@ -1124,7 +1134,7 @@ static int ed_marker_select(bContext *C, const wmEvent *event, bool extend, bool if (camera) { Scene *scene = CTX_data_scene(C); - Base *base; + BaseLegacy *base; TimeMarker *marker; int sel = 0; diff --git a/source/blender/editors/animation/keyframes_draw.c b/source/blender/editors/animation/keyframes_draw.c index 5f675e690b9..c8d141eab07 100644 --- a/source/blender/editors/animation/keyframes_draw.c +++ b/source/blender/editors/animation/keyframes_draw.c @@ -52,7 +52,8 @@ #include "BKE_fcurve.h" -#include "BIF_gl.h" +#include "GPU_draw.h" +#include "GPU_immediate.h" #include "UI_resources.h" #include "UI_view2d.h" @@ -463,49 +464,15 @@ bool actkeyblock_is_valid(ActKeyBlock *ab, DLRBT_Tree *keys) /* *************************** Keyframe Drawing *************************** */ -/* coordinates for diamond shape */ -static const float _unit_diamond_shape[4][2] = { - {0.0f, 1.0f}, /* top vert */ - {1.0f, 0.0f}, /* mid-right */ - {0.0f, -1.0f}, /* bottom vert */ - {-1.0f, 0.0f} /* mid-left */ -}; - -/* draw a simple diamond shape with OpenGL */ -void draw_keyframe_shape(float x, float y, float xscale, float hsize, short sel, short key_type, short mode, float alpha) +void draw_keyframe_shape(float x, float y, float size, bool sel, short key_type, short mode, float alpha, + unsigned int pos_id, unsigned int size_id, unsigned int color_id, unsigned int outline_color_id) { - static GLuint displist1 = 0; - static GLuint displist2 = 0; - - /* initialize 2 display lists for diamond shape - one empty, one filled */ - if (displist1 == 0) { - displist1 = glGenLists(1); - glNewList(displist1, GL_COMPILE); - - glBegin(GL_LINE_LOOP); - glVertex2fv(_unit_diamond_shape[0]); - glVertex2fv(_unit_diamond_shape[1]); - glVertex2fv(_unit_diamond_shape[2]); - glVertex2fv(_unit_diamond_shape[3]); - glEnd(); - - glEndList(); - } - if (displist2 == 0) { - displist2 = glGenLists(1); - glNewList(displist2, GL_COMPILE); - - glBegin(GL_QUADS); - glVertex2fv(_unit_diamond_shape[0]); - glVertex2fv(_unit_diamond_shape[1]); - glVertex2fv(_unit_diamond_shape[2]); - glVertex2fv(_unit_diamond_shape[3]); - glEnd(); - - glEndList(); - } - - /* tweak size of keyframe shape according to type of keyframe + bool draw_fill = ELEM(mode, KEYFRAME_SHAPE_INSIDE, KEYFRAME_SHAPE_BOTH); + bool draw_outline = ELEM(mode, KEYFRAME_SHAPE_FRAME, KEYFRAME_SHAPE_BOTH); + + if (!(draw_fill || draw_outline)) return; /* TODO: assert this? */ + + /* tweak size of keyframe shape according to type of keyframe * - 'proper' keyframes have key_type = 0, so get drawn at full size */ switch (key_type) { @@ -513,120 +480,93 @@ void draw_keyframe_shape(float x, float y, float xscale, float hsize, short sel, break; case BEZT_KEYTYPE_BREAKDOWN: /* slightly smaller than normal keyframe */ - hsize *= 0.85f; + size *= 0.85f; break; case BEZT_KEYTYPE_MOVEHOLD: /* slightly smaller than normal keyframes (but by less than for breakdowns) */ - //hsize *= 0.72f; - hsize *= 0.95f; + //size *= 0.72f; + size *= 0.95f; break; case BEZT_KEYTYPE_EXTREME: /* slightly larger */ - hsize *= 1.2f; + size *= 1.2f; break; default: - hsize -= 0.5f * key_type; - break; + size -= 0.5f * key_type; } - - /* adjust view transform before starting */ - glTranslatef(x, y, 0.0f); - glScalef(1.0f / xscale * hsize, hsize, 1.0f); - - /* anti-aliased lines for more consistent appearance */ - glEnable(GL_LINE_SMOOTH); - + + unsigned char fill_col[4]; + unsigned char outline_col[4]; + /* draw! */ - if (ELEM(mode, KEYFRAME_SHAPE_INSIDE, KEYFRAME_SHAPE_BOTH)) { - float inner_col[4]; - + if (draw_fill) { /* get interior colors from theme (for selected and unselected only) */ switch (key_type) { case BEZT_KEYTYPE_BREAKDOWN: /* bluish frames (default theme) */ - { - if (sel) UI_GetThemeColor4fv(TH_KEYTYPE_BREAKDOWN_SELECT, inner_col); - else UI_GetThemeColor4fv(TH_KEYTYPE_BREAKDOWN, inner_col); + UI_GetThemeColor4ubv(sel ? TH_KEYTYPE_BREAKDOWN_SELECT : TH_KEYTYPE_BREAKDOWN, fill_col); break; - } case BEZT_KEYTYPE_EXTREME: /* reddish frames (default theme) */ - { - if (sel) UI_GetThemeColor4fv(TH_KEYTYPE_EXTREME_SELECT, inner_col); - else UI_GetThemeColor4fv(TH_KEYTYPE_EXTREME, inner_col); + UI_GetThemeColor4ubv(sel ? TH_KEYTYPE_EXTREME_SELECT : TH_KEYTYPE_EXTREME, fill_col); break; - } case BEZT_KEYTYPE_JITTER: /* greenish frames (default theme) */ - { - if (sel) UI_GetThemeColor4fv(TH_KEYTYPE_JITTER_SELECT, inner_col); - else UI_GetThemeColor4fv(TH_KEYTYPE_JITTER, inner_col); + UI_GetThemeColor4ubv(sel ? TH_KEYTYPE_JITTER_SELECT : TH_KEYTYPE_JITTER, fill_col); break; - } case BEZT_KEYTYPE_MOVEHOLD: /* similar to traditional keyframes, but different... */ - { /* XXX: Should these get their own theme options instead? */ - if (sel) UI_GetThemeColorShade4fv(TH_STRIP_SELECT, 35, inner_col); - else UI_GetThemeColorShade4fv(TH_STRIP, 50, inner_col); - - inner_col[3] = 1.0f; /* full opacity, to avoid problems with visual glitches */ + if (sel) UI_GetThemeColorShade3ubv(TH_STRIP_SELECT, 35, fill_col); + else UI_GetThemeColorShade3ubv(TH_STRIP, 50, fill_col); + fill_col[3] = 255; /* full opacity, to avoid problems with visual glitches */ break; - } case BEZT_KEYTYPE_KEYFRAME: /* traditional yellowish frames (default theme) */ default: - { - if (sel) UI_GetThemeColor4fv(TH_KEYTYPE_KEYFRAME_SELECT, inner_col); - else UI_GetThemeColor4fv(TH_KEYTYPE_KEYFRAME, inner_col); - break; - } + UI_GetThemeColor4ubv(sel ? TH_KEYTYPE_KEYFRAME_SELECT : TH_KEYTYPE_KEYFRAME, fill_col); } /* NOTE: we don't use the straight alpha from the theme, or else effects such as * graying out protected/muted channels doesn't work correctly! */ - inner_col[3] *= alpha; - glColor4fv(inner_col); - - /* draw the "filled in" interior poly now */ - glCallList(displist2); + fill_col[3] *= alpha; + + if (!draw_outline) { + /* force outline color to match */ + outline_col[0] = fill_col[0]; + outline_col[1] = fill_col[1]; + outline_col[2] = fill_col[2]; + outline_col[3] = fill_col[3]; + } } - - if (ELEM(mode, KEYFRAME_SHAPE_FRAME, KEYFRAME_SHAPE_BOTH)) { - float border_col[4]; - + + if (draw_outline) { /* exterior - black frame */ - if (sel) UI_GetThemeColor4fv(TH_KEYBORDER_SELECT, border_col); - else UI_GetThemeColor4fv(TH_KEYBORDER, border_col); - - border_col[3] *= alpha; - glColor4fv(border_col); - - glCallList(displist1); + UI_GetThemeColor4ubv(sel ? TH_KEYBORDER_SELECT : TH_KEYBORDER, outline_col); + outline_col[3] *= alpha; + + if (!draw_fill) { + /* fill color needs to be (outline.rgb, 0) */ + fill_col[0] = outline_col[0]; + fill_col[1] = outline_col[1]; + fill_col[2] = outline_col[2]; + fill_col[3] = 0; + } } - - glDisable(GL_LINE_SMOOTH); - - /* restore view transform */ - glScalef(xscale / hsize, 1.0f / hsize, 1.0f); - glTranslatef(-x, -y, 0.0f); + + immAttrib1f(size_id, size); + immAttrib4ubv(color_id, fill_col); + immAttrib4ubv(outline_color_id, outline_col); + immVertex2f(pos_id, x, y); } static void draw_keylist(View2D *v2d, DLRBT_Tree *keys, DLRBT_Tree *blocks, float ypos, float yscale_fac, bool channelLocked) { - ActKeyColumn *ak; - ActKeyBlock *ab; - float alpha; - float xscale; - - const float iconsize = (U.widget_unit / 4.0f) * yscale_fac; - const float mhsize = iconsize * 0.7f; + const float iconsize = U.widget_unit * 0.25f * yscale_fac; + const float mhsize = iconsize * 0.7f; glEnable(GL_BLEND); - /* get View2D scaling factor */ - UI_view2d_scale_get(v2d, &xscale, NULL); - /* locked channels are less strongly shown, as feedback for locked channels in DopeSheet */ /* TODO: allow this opacity factor to be themed? */ - alpha = (channelLocked) ? 0.25f : 1.0f; + float alpha = channelLocked ? 0.25f : 1.0f; /* draw keyblocks */ if (blocks) { @@ -644,45 +584,59 @@ static void draw_keylist(View2D *v2d, DLRBT_Tree *keys, DLRBT_Tree *blocks, floa sel_mhcol[3] *= 0.8f; copy_v4_v4(unsel_mhcol, unsel_color); unsel_mhcol[3] *= 0.8f; - + + unsigned int pos_id = add_attrib(immVertexFormat(), "pos", COMP_F32, 2, KEEP_FLOAT); + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); /* NOTE: the tradeoff for changing colors between each draw is dwarfed by the cost of checking validity */ - for (ab = blocks->first; ab; ab = ab->next) { + for (ActKeyBlock *ab = blocks->first; ab; ab = ab->next) { if (actkeyblock_is_valid(ab, keys)) { if (ab->flag & ACTKEYBLOCK_FLAG_MOVING_HOLD) { /* draw "moving hold" long-keyframe block - slightly smaller */ - if (ab->sel) - glColor4fv(sel_mhcol); - else - glColor4fv(unsel_mhcol); - - glRectf(ab->start, ypos - mhsize, ab->end, ypos + mhsize); + immUniformColor4fv(ab->sel ? sel_mhcol : unsel_mhcol); + immRectf(pos_id, ab->start, ypos - mhsize, ab->end, ypos + mhsize); } else { /* draw standard long-keyframe block */ - if (ab->sel) - glColor4fv(sel_color); - else - glColor4fv(unsel_color); - - glRectf(ab->start, ypos - iconsize, ab->end, ypos + iconsize); + immUniformColor4fv(ab->sel ? sel_color : unsel_color); + immRectf(pos_id, ab->start, ypos - iconsize, ab->end, ypos + iconsize); } } } + immUnbindProgram(); } - /* draw keys */ if (keys) { - for (ak = keys->first; ak; ak = ak->next) { + /* count keys */ + unsigned int key_ct = 0; + for (ActKeyColumn *ak = keys->first; ak; ak = ak->next) { /* optimization: if keyframe doesn't appear within 5 units (screenspace) in visible area, don't draw * - this might give some improvements, since we current have to flip between view/region matrices */ - if (IN_RANGE_INCL(ak->cfra, v2d->cur.xmin, v2d->cur.xmax) == 0) - continue; - - /* draw using OpenGL - uglier but faster */ - /* NOTE1: a previous version of this didn't work nice for some intel cards - * NOTE2: if we wanted to go back to icons, these are icon = (ak->sel & SELECT) ? ICON_SPACE2 : ICON_SPACE3; */ - draw_keyframe_shape(ak->cfra, ypos, xscale, iconsize, (ak->sel & SELECT), ak->key_type, KEYFRAME_SHAPE_BOTH, alpha); + if (IN_RANGE_INCL(ak->cfra, v2d->cur.xmin, v2d->cur.xmax)) + key_ct++; + } + + if (key_ct > 0) { + /* draw keys */ + VertexFormat *format = immVertexFormat(); + unsigned int pos_id = add_attrib(format, "pos", COMP_F32, 2, KEEP_FLOAT); + unsigned int size_id = add_attrib(format, "size", COMP_F32, 1, KEEP_FLOAT); + unsigned int color_id = add_attrib(format, "color", COMP_U8, 4, NORMALIZE_INT_TO_FLOAT); + unsigned int outline_color_id = add_attrib(format, "outlineColor", COMP_U8, 4, NORMALIZE_INT_TO_FLOAT); + immBindBuiltinProgram(GPU_SHADER_KEYFRAME_DIAMOND); + GPU_enable_program_point_size(); + immBegin(PRIM_POINTS, key_ct); + + for (ActKeyColumn *ak = keys->first; ak; ak = ak->next) { + if (IN_RANGE_INCL(ak->cfra, v2d->cur.xmin, v2d->cur.xmax)) { + draw_keyframe_shape(ak->cfra, ypos, iconsize, (ak->sel & SELECT), ak->key_type, KEYFRAME_SHAPE_BOTH, alpha, + pos_id, size_id, color_id, outline_color_id); + } + } + + immEnd(); + GPU_disable_program_point_size(); + immUnbindProgram(); } } @@ -938,7 +892,7 @@ void ob_to_keylist(bDopeSheet *ads, Object *ob, DLRBT_Tree *keys, DLRBT_Tree *bl int filter; bAnimListElem dummychan = {NULL}; - Base dummybase = {NULL}; + BaseLegacy dummybase = {NULL}; if (ob == NULL) return; diff --git a/source/blender/editors/animation/keyframes_edit.c b/source/blender/editors/animation/keyframes_edit.c index 4571df0f077..f4922fec385 100644 --- a/source/blender/editors/animation/keyframes_edit.c +++ b/source/blender/editors/animation/keyframes_edit.c @@ -193,7 +193,7 @@ static short ob_keyframes_loop(KeyframeEditData *ked, bDopeSheet *ads, Object *o int ret = 0; bAnimListElem dummychan = {NULL}; - Base dummybase = {NULL}; + BaseLegacy dummybase = {NULL}; if (ob == NULL) return 0; diff --git a/source/blender/editors/armature/armature_intern.h b/source/blender/editors/armature/armature_intern.h index b39b4bd81ee..d75193a46ff 100644 --- a/source/blender/editors/armature/armature_intern.h +++ b/source/blender/editors/armature/armature_intern.h @@ -37,7 +37,7 @@ struct wmOperatorType; struct bContext; struct Scene; struct Object; -struct Base; +struct BaseLegacy; struct bAction; struct bPoseChannel; @@ -248,7 +248,7 @@ void armature_select_mirrored(struct bArmature *arm); void armature_tag_unselect(struct bArmature *arm); void *get_nearest_bone(struct bContext *C, short findunsel, int x, int y); -void *get_bone_from_selectbuffer(struct Scene *scene, struct Base *base, unsigned int *buffer, short hits, short findunsel, bool do_nearest); +void *get_bone_from_selectbuffer(struct Scene *scene, struct BaseLegacy *base, unsigned int *buffer, short hits, short findunsel, bool do_nearest); int bone_looper(struct Object *ob, struct Bone *bone, void *data, int (*bone_func)(struct Object *, struct Bone *, void *)); diff --git a/source/blender/editors/armature/armature_relations.c b/source/blender/editors/armature/armature_relations.c index 1c342657eec..0dc97483dfc 100644 --- a/source/blender/editors/armature/armature_relations.c +++ b/source/blender/editors/armature/armature_relations.c @@ -50,6 +50,7 @@ #include "BKE_depsgraph.h" #include "BKE_fcurve.h" #include "BKE_global.h" +#include "BKE_layer.h" #include "BKE_main.h" #include "BKE_report.h" @@ -400,7 +401,7 @@ int join_armature_exec(bContext *C, wmOperator *op) } /* Free the old object data */ - ED_base_object_free_and_unlink(bmain, scene, base); + ED_base_object_free_and_unlink(bmain, scene, base->object); } } CTX_DATA_END; @@ -579,6 +580,7 @@ static int separate_armature_exec(bContext *C, wmOperator *op) { Main *bmain = CTX_data_main(C); Scene *scene = CTX_data_scene(C); + SceneLayer *sl = CTX_data_scene_layer(C); Object *obedit = CTX_data_edit_object(C); Object *oldob, *newob; Base *oldbase, *newbase; @@ -602,14 +604,18 @@ static int separate_armature_exec(bContext *C, wmOperator *op) /* TODO: use context iterators for this? */ CTX_DATA_BEGIN(C, Base *, base, visible_bases) { - if (base->object == obedit) base->flag |= SELECT; - else base->flag &= ~SELECT; + if (base->object == obedit) { + ED_object_base_select(base, BA_SELECT); + } + else { + ED_object_base_select(base, BA_DESELECT); + } } CTX_DATA_END; /* 1) store starting settings and exit editmode */ oldob = obedit; - oldbase = BASACT; + oldbase = sl->basact; oldob->mode &= ~OB_MODE_POSE; //oldbase->flag &= ~OB_POSEMODE; @@ -617,13 +623,13 @@ static int separate_armature_exec(bContext *C, wmOperator *op) ED_armature_edit_free(obedit->data); /* 2) duplicate base */ - newbase = ED_object_add_duplicate(bmain, scene, oldbase, USER_DUP_ARM); /* only duplicate linked armature */ + newbase = ED_object_add_duplicate(bmain, scene, sl, oldbase, USER_DUP_ARM); /* only duplicate linked armature */ DAG_relations_tag_update(bmain); newob = newbase->object; - newbase->flag &= ~SELECT; - - + newbase->flag &= ~BASE_SELECTED; + + /* 3) remove bones that shouldn't still be around on both armatures */ separate_armature_bones(oldob, 1); separate_armature_bones(newob, 0); diff --git a/source/blender/editors/armature/armature_select.c b/source/blender/editors/armature/armature_select.c index e9946abba0b..1f994a7f13e 100644 --- a/source/blender/editors/armature/armature_select.c +++ b/source/blender/editors/armature/armature_select.c @@ -74,7 +74,7 @@ Bone *get_indexed_bone(Object *ob, int index) /* See if there are any selected bones in this buffer */ /* only bones from base are checked on */ -void *get_bone_from_selectbuffer(Scene *scene, Base *base, unsigned int *buffer, short hits, short findunsel, bool do_nearest) +void *get_bone_from_selectbuffer(Scene *scene, BaseLegacy *base, unsigned int *buffer, short hits, short findunsel, bool do_nearest) { Object *obedit = scene->obedit; // XXX get from context Bone *bone; diff --git a/source/blender/editors/armature/editarmature_sketch.c b/source/blender/editors/armature/editarmature_sketch.c index f6c04e9570a..4d9ba351c3a 100644 --- a/source/blender/editors/armature/editarmature_sketch.c +++ b/source/blender/editors/armature/editarmature_sketch.c @@ -142,7 +142,7 @@ void BIF_makeListTemplates(const bContext *C) Object *obedit = CTX_data_edit_object(C); Scene *scene = CTX_data_scene(C); ToolSettings *ts = CTX_data_tool_settings(C); - Base *base; + BaseLegacy *base; int index = 0; if (TEMPLATES_HASH != NULL) { diff --git a/source/blender/editors/armature/pose_select.c b/source/blender/editors/armature/pose_select.c index 44470c1f827..903d309cb1f 100644 --- a/source/blender/editors/armature/pose_select.c +++ b/source/blender/editors/armature/pose_select.c @@ -132,7 +132,7 @@ void ED_pose_bone_select(Object *ob, bPoseChannel *pchan, bool select) /* called from editview.c, for mode-less pose selection */ /* assumes scene obact and basact is still on old situation */ -int ED_do_pose_selectbuffer(Scene *scene, Base *base, unsigned int *buffer, short hits, +int ED_do_pose_selectbuffer(Scene *scene, BaseLegacy *base, unsigned int *buffer, short hits, bool extend, bool deselect, bool toggle, bool do_nearest) { Object *ob = base->object; diff --git a/source/blender/editors/curve/editcurve.c b/source/blender/editors/curve/editcurve.c index 47f42ab5321..f6528658490 100644 --- a/source/blender/editors/curve/editcurve.c +++ b/source/blender/editors/curve/editcurve.c @@ -50,6 +50,7 @@ #include "BKE_fcurve.h" #include "BKE_global.h" #include "BKE_key.h" +#include "BKE_layer.h" #include "BKE_library.h" #include "BKE_main.h" #include "BKE_report.h" @@ -1285,6 +1286,7 @@ static int separate_exec(bContext *C, wmOperator *op) { Main *bmain = CTX_data_main(C); Scene *scene = CTX_data_scene(C); + SceneLayer *sl = CTX_data_scene_layer(C); Object *oldob, *newob; Base *oldbase, *newbase; Curve *oldcu, *newcu; @@ -1312,7 +1314,7 @@ static int separate_exec(bContext *C, wmOperator *op) } /* 2. duplicate the object and data */ - newbase = ED_object_add_duplicate(bmain, scene, oldbase, 0); /* 0 = fully linked */ + newbase = ED_object_add_duplicate(bmain, scene, sl, oldbase, 0); /* 0 = fully linked */ DAG_relations_tag_update(bmain); newob = newbase->object; @@ -6038,7 +6040,7 @@ int join_curve_exec(bContext *C, wmOperator *op) } } - ED_base_object_free_and_unlink(bmain, scene, base); + ED_base_object_free_and_unlink(bmain, scene, base->object); } } } diff --git a/source/blender/editors/curve/editcurve_paint.c b/source/blender/editors/curve/editcurve_paint.c index 34e026a3ef4..7b93e00b86d 100644 --- a/source/blender/editors/curve/editcurve_paint.c +++ b/source/blender/editors/curve/editcurve_paint.c @@ -48,6 +48,10 @@ #include "BIF_gl.h" #include "BIF_glutil.h" +#include "GPU_batch.h" +#include "GPU_immediate.h" +#include "GPU_matrix.h" + #include "curve_intern.h" #include "UI_resources.h" @@ -465,39 +469,44 @@ static void curve_draw_stroke_3d(const struct bContext *UNUSED(C), ARegion *UNUS Object *obedit = cdd->vc.obedit; Curve *cu = obedit->data; - UI_ThemeColor(TH_WIRE); - if (cu->ext2 > 0.0f) { - GLUquadricObj *qobj = gluNewQuadric(); - - gluQuadricDrawStyle(qobj, GLU_FILL); - BLI_mempool_iter iter; const struct StrokeElem *selem; const float location_zero[3] = {0}; const float *location_prev = location_zero; + float color[3]; + UI_GetThemeColor3fv(TH_WIRE, color); + + Batch *sphere = Batch_get_sphere(0); + Batch_set_builtin_program(sphere, GPU_SHADER_3D_UNIFORM_COLOR); + Batch_Uniform3fv(sphere, "color", color); + /* scale to edit-mode space */ - glPushMatrix(); - glMultMatrixf(obedit->obmat); + gpuMatrixBegin3D_legacy(); + gpuPushMatrix(); + gpuMultMatrix3D(obedit->obmat); BLI_mempool_iternew(cdd->stroke_elem_pool, &iter); for (selem = BLI_mempool_iterstep(&iter); selem; selem = BLI_mempool_iterstep(&iter)) { - glTranslatef( + gpuTranslate3f( selem->location_local[0] - location_prev[0], selem->location_local[1] - location_prev[1], selem->location_local[2] - location_prev[2]); location_prev = selem->location_local; + const float radius = stroke_elem_radius(cdd, selem); - gluSphere(qobj, radius, 12, 8); + + gpuScaleUniform(radius); + Batch_draw(sphere); + gpuScaleUniform(1.0f / radius); location_prev = selem->location_local; } - glPopMatrix(); - - gluDeleteQuadric(qobj); + gpuPopMatrix(); + gpuMatrixEnd(); } if (stroke_len > 1) { @@ -514,30 +523,45 @@ static void curve_draw_stroke_3d(const struct bContext *UNUSED(C), ARegion *UNUS } { + VertexFormat *format = immVertexFormat(); + unsigned pos = add_attrib(format, "pos", GL_FLOAT, 3, KEEP_FLOAT); + immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR); + glEnable(GL_BLEND); glEnable(GL_LINE_SMOOTH); - glEnableClientState(GL_VERTEX_ARRAY); - glVertexPointer(3, GL_FLOAT, 0, coord_array); - - cpack(0x0); + imm_cpack(0x0); + immBegin(GL_LINE_STRIP, stroke_len); glLineWidth(3.0f); - glDrawArrays(GL_LINE_STRIP, 0, stroke_len); - if (v3d->zbuf) + if (v3d->zbuf) { glDisable(GL_DEPTH_TEST); + } + + for (int i = 0; i < stroke_len; i++) { + immVertex3fv(pos, coord_array[i]); + } - cpack(0xffffffff); + immEnd(); + + imm_cpack(0xffffffff); + immBegin(GL_LINE_STRIP, stroke_len); glLineWidth(1.0f); - glDrawArrays(GL_LINE_STRIP, 0, stroke_len); - if (v3d->zbuf) - glEnable(GL_DEPTH_TEST); + for (int i = 0; i < stroke_len; i++) { + immVertex3fv(pos, coord_array[i]); + } - glDisableClientState(GL_VERTEX_ARRAY); + immEnd(); + + if (v3d->zbuf) { + glEnable(GL_DEPTH_TEST); + } glDisable(GL_BLEND); glDisable(GL_LINE_SMOOTH); + + immUnbindProgram(); } MEM_freeN(coord_array); @@ -686,6 +710,7 @@ static bool curve_draw_init(bContext *C, wmOperator *op, bool is_invoke) } else { cdd->vc.scene = CTX_data_scene(C); + cdd->vc.sl = CTX_data_scene_layer(C); cdd->vc.obedit = CTX_data_edit_object(C); } diff --git a/source/blender/editors/curve/editfont.c b/source/blender/editors/curve/editfont.c index 57e731874b4..d86091aaa77 100644 --- a/source/blender/editors/curve/editfont.c +++ b/source/blender/editors/curve/editfont.c @@ -420,6 +420,7 @@ static void txt_add_object(bContext *C, TextLine *firstline, int totline, const { Main *bmain = CTX_data_main(C); Scene *scene = CTX_data_scene(C); + SceneLayer *sl = CTX_data_scene_layer(C); Curve *cu; Object *obedit; Base *base; @@ -429,8 +430,8 @@ static void txt_add_object(bContext *C, TextLine *firstline, int totline, const int a; float rot[3] = {0.f, 0.f, 0.f}; - obedit = BKE_object_add(bmain, scene, OB_FONT, NULL); - base = scene->basact; + obedit = BKE_object_add(bmain, scene, sl, OB_FONT, NULL); + base = sl->basact; /* seems to assume view align ? TODO - look into this, could be an operator option */ ED_object_base_init_transform(C, base, NULL, rot); diff --git a/source/blender/editors/gpencil/drawgpencil.c b/source/blender/editors/gpencil/drawgpencil.c index a542bf8fa11..05eb51fb02f 100644 --- a/source/blender/editors/gpencil/drawgpencil.c +++ b/source/blender/editors/gpencil/drawgpencil.c @@ -60,9 +60,11 @@ #include "WM_api.h" -#include "BIF_gl.h" #include "BIF_glutil.h" +#include "GPU_immediate.h" +#include "GPU_draw.h" + #include "ED_gpencil.h" #include "ED_screen.h" #include "ED_view3d.h" @@ -94,97 +96,194 @@ typedef enum eDrawStrokeFlags { /* thickness above which we should use special drawing */ #define GP_DRAWTHICKNESS_SPECIAL 3 +/* conversion utility (float --> normalized unsigned byte) */ +#define F2UB(x) (unsigned char)(255.0f * x) + /* ----- Tool Buffer Drawing ------ */ -/* helper function to set color of buffer point */ -static void gp_set_tpoint_color(tGPspoint *pt, float ink[4]) +/* helper functions to set color of buffer point */ + +static void gp_set_tpoint_varying_color(const tGPspoint *pt, const float ink[4], unsigned attrib_id) { float alpha = ink[3] * pt->strength; CLAMP(alpha, GPENCIL_STRENGTH_MIN, 1.0f); - glColor4f(ink[0], ink[1], ink[2], alpha); + immAttrib4ub(attrib_id, F2UB(ink[0]), F2UB(ink[1]), F2UB(ink[2]), F2UB(alpha)); } -/* helper function to set color of point */ -static void gp_set_point_color(bGPDspoint *pt, float ink[4]) +static void gp_set_point_uniform_color(const bGPDspoint *pt, const float ink[4]) { float alpha = ink[3] * pt->strength; CLAMP(alpha, GPENCIL_STRENGTH_MIN, 1.0f); - glColor4f(ink[0], ink[1], ink[2], alpha); + immUniform4f("color", ink[0], ink[1], ink[2], alpha); } -/* helper function to set color and point */ -static void gp_set_color_and_tpoint(tGPspoint *pt, float ink[4]) +static void gp_set_point_varying_color(const bGPDspoint *pt, const float ink[4], unsigned attrib_id) { - gp_set_tpoint_color(pt, ink); - glVertex2iv(&pt->x); + float alpha = ink[3] * pt->strength; + CLAMP(alpha, GPENCIL_STRENGTH_MIN, 1.0f); + immAttrib4ub(attrib_id, F2UB(ink[0]), F2UB(ink[1]), F2UB(ink[2]), F2UB(alpha)); +} + +/* draw fills for buffer stroke */ +static void gp_draw_stroke_buffer_fill(const tGPspoint *points, int totpoints, float ink[4]) +{ + if (totpoints < 3) { + return; + } + int tot_triangles = totpoints - 2; + /* allocate memory for temporary areas */ + unsigned int(*tmp_triangles)[3] = MEM_mallocN(sizeof(*tmp_triangles) * tot_triangles, "GP Stroke buffer temp triangulation"); + float(*points2d)[2] = MEM_mallocN(sizeof(*points2d) * totpoints, "GP Stroke buffer temp 2d points"); + + /* Convert points to array and triangulate + * Here a cache is not used because while drawing the information changes all the time, so the cache + * would be recalculated constantly, so it is better to do direct calculation for each function call + */ + for (int i = 0; i < totpoints; i++) { + const tGPspoint *pt = &points[i]; + points2d[i][0] = pt->x; + points2d[i][1] = pt->y; + } + BLI_polyfill_calc((const float(*)[2])points2d, (unsigned int)totpoints, 0, (unsigned int(*)[3])tmp_triangles); + + /* draw triangulation data */ + if (tot_triangles > 0) { + VertexFormat *format = immVertexFormat(); + unsigned pos = add_attrib(format, "pos", GL_INT, 2, CONVERT_INT_TO_FLOAT); + unsigned color = add_attrib(format, "color", GL_UNSIGNED_BYTE, 4, NORMALIZE_INT_TO_FLOAT); + + immBindBuiltinProgram(GPU_SHADER_2D_SMOOTH_COLOR); + + /* Draw all triangles for filling the polygon */ + immBegin(GL_TRIANGLES, tot_triangles * 3); + /* TODO: use batch instead of immediate mode, to share vertices */ + + const tGPspoint *pt; + for (int i = 0; i < tot_triangles; i++) { + /* vertex 1 */ + pt = &points[tmp_triangles[i][0]]; + gp_set_tpoint_varying_color(pt, ink, color); + immVertex2iv(pos, &pt->x); + /* vertex 2 */ + pt = &points[tmp_triangles[i][1]]; + gp_set_tpoint_varying_color(pt, ink, color); + immVertex2iv(pos, &pt->x); + /* vertex 3 */ + pt = &points[tmp_triangles[i][2]]; + gp_set_tpoint_varying_color(pt, ink, color); + immVertex2iv(pos, &pt->x); + } + + immEnd(); + immUnbindProgram(); + } + + /* clear memory */ + if (tmp_triangles) { + MEM_freeN(tmp_triangles); + } + if (points2d) { + MEM_freeN(points2d); + } } /* draw stroke defined in buffer (simple ogl lines/points for now, as dotted lines) */ -static void gp_draw_stroke_buffer(tGPspoint *points, int totpoints, short thickness, - short dflag, short sflag, float ink[4]) +static void gp_draw_stroke_buffer(const tGPspoint *points, int totpoints, short thickness, + short dflag, short sflag, float ink[4], float fill_ink[4]) { - tGPspoint *pt; - int i; - + int draw_points = 0; + /* error checking */ if ((points == NULL) || (totpoints <= 0)) return; - + /* check if buffer can be drawn */ if (dflag & (GP_DRAWDATA_ONLY3D | GP_DRAWDATA_ONLYV2D)) return; - + + if (sflag & GP_STROKE_ERASER) { + /* don't draw stroke at all! */ + return; + } + + VertexFormat *format = immVertexFormat(); + unsigned pos = add_attrib(format, "pos", GL_INT, 2, CONVERT_INT_TO_FLOAT); + unsigned color = add_attrib(format, "color", GL_UNSIGNED_BYTE, 4, NORMALIZE_INT_TO_FLOAT); + + const tGPspoint *pt = points; + if (totpoints == 1) { /* if drawing a single point, draw it larger */ glPointSize((float)(thickness + 2) * points->pressure); - glBegin(GL_POINTS); - - gp_set_color_and_tpoint(points, ink); - glEnd(); - } - else if (sflag & GP_STROKE_ERASER) { - /* don't draw stroke at all! */ + immBindBuiltinProgram(GPU_SHADER_3D_POINT_FIXED_SIZE_VARYING_COLOR); + immBegin(GL_POINTS, 1); + gp_set_tpoint_varying_color(pt, ink, color); + immVertex2iv(pos, &pt->x); } else { float oldpressure = points[0].pressure; - + /* draw stroke curve */ if (G.debug & G_DEBUG) setlinestyle(2); - + glLineWidth(max_ff(oldpressure * thickness, 1.0)); - glBegin(GL_LINE_STRIP); - - for (i = 0, pt = points; i < totpoints && pt; i++, pt++) { + immBindBuiltinProgram(GPU_SHADER_2D_SMOOTH_COLOR); + immBeginAtMost(GL_LINE_STRIP, totpoints); + + /* TODO: implement this with a geometry shader to draw one continuous tapered stroke */ + + for (int i = 0; i < totpoints; i++, pt++) { /* if there was a significant pressure change, stop the curve, change the thickness of the stroke, * and continue drawing again (since line-width cannot change in middle of GL_LINE_STRIP) */ if (fabsf(pt->pressure - oldpressure) > 0.2f) { - glEnd(); + /* need to have 2 points to avoid immEnd assert error */ + if (draw_points < 2) { + gp_set_tpoint_varying_color(pt - 1, ink, color); + immVertex2iv(pos, &(pt - 1)->x); + } + + immEnd(); + draw_points = 0; + glLineWidth(max_ff(pt->pressure * thickness, 1.0f)); - glBegin(GL_LINE_STRIP); - + immBeginAtMost(GL_LINE_STRIP, totpoints - i + 1); + /* need to roll-back one point to ensure that there are no gaps in the stroke */ if (i != 0) { - gp_set_color_and_tpoint((pt - 1), ink); + gp_set_tpoint_varying_color(pt - 1, ink, color); + immVertex2iv(pos, &(pt - 1)->x); + ++draw_points; } - - /* now the point we want... */ - gp_set_color_and_tpoint(pt, ink); - - oldpressure = pt->pressure; - } - else { - gp_set_color_and_tpoint(pt, ink); + + oldpressure = pt->pressure; /* reset our threshold */ } + + /* now the point we want */ + gp_set_tpoint_varying_color(pt, ink, color); + immVertex2iv(pos, &pt->x); + ++draw_points; + } + /* need to have 2 points to avoid immEnd assert error */ + if (draw_points < 2) { + gp_set_tpoint_varying_color(pt - 1, ink, color); + immVertex2iv(pos, &(pt - 1)->x); } - glEnd(); if (G.debug & G_DEBUG) setlinestyle(0); } + + immEnd(); + immUnbindProgram(); + + // draw fill + if (fill_ink[3] > GPENCIL_ALPHA_OPACITY_THRESH) { + gp_draw_stroke_buffer_fill(points, totpoints, fill_ink); + } } /* --------- 2D Stroke Drawing Helpers --------- */ /* change in parameter list */ -static void gp_calc_2d_stroke_fxy(float pt[3], short sflag, int offsx, int offsy, int winx, int winy, float r_co[2]) +static void gp_calc_2d_stroke_fxy(const float pt[3], short sflag, int offsx, int offsy, int winx, int winy, float r_co[2]) { if (sflag & GP_STROKE_2DSPACE) { r_co[0] = pt[0]; @@ -210,203 +309,141 @@ static void gp_calc_2d_stroke_fxy(float pt[3], short sflag, int offsx, int offsy /* draw a 2D buffer stroke in "volumetric" style * NOTE: the stroke buffer doesn't have any coordinate offsets/transforms */ -static void gp_draw_stroke_volumetric_buffer(tGPspoint *points, int totpoints, short thickness, - short dflag, short UNUSED(sflag), float ink[4]) +static void gp_draw_stroke_volumetric_buffer(const tGPspoint *points, int totpoints, short thickness, + short dflag, const float ink[4]) { - GLUquadricObj *qobj = gluNewQuadric(); - float modelview[4][4]; - - tGPspoint *pt; - int i; - /* error checking */ if ((points == NULL) || (totpoints <= 0)) return; - + /* check if buffer can be drawn */ if (dflag & (GP_DRAWDATA_ONLY3D | GP_DRAWDATA_ONLYV2D)) return; - - /* get basic matrix - should be camera space (i.e "identity") */ - glGetFloatv(GL_MODELVIEW_MATRIX, (float *)modelview); - - /* draw points */ - glPushMatrix(); - - for (i = 0, pt = points; i < totpoints; i++, pt++) { - /* set the transformed position */ - // TODO: scale should change based on zoom level, which requires proper translation mult too! - modelview[3][0] = pt->x; - modelview[3][1] = pt->y; - - glLoadMatrixf((float *)modelview); - - /* draw the disk using the current state... */ - gp_set_tpoint_color(pt, ink); - gluDisk(qobj, 0.0, pt->pressure * thickness, 32, 1); - - - modelview[3][0] = modelview[3][1] = 0.0f; + + VertexFormat *format = immVertexFormat(); + unsigned pos = add_attrib(format, "pos", GL_FLOAT, 2, KEEP_FLOAT); + unsigned size = add_attrib(format, "size", GL_FLOAT, 1, KEEP_FLOAT); + unsigned color = add_attrib(format, "color", GL_UNSIGNED_BYTE, 4, NORMALIZE_INT_TO_FLOAT); + + immBindBuiltinProgram(GPU_SHADER_3D_POINT_VARYING_SIZE_VARYING_COLOR); + GPU_enable_program_point_size(); + immBegin(GL_POINTS, totpoints); + + const tGPspoint *pt = points; + for (int i = 0; i < totpoints; i++, pt++) { + gp_set_tpoint_varying_color(pt, ink, color); + immAttrib1f(size, pt->pressure * thickness); /* TODO: scale based on view transform (zoom level) */ + immVertex2f(pos, pt->x, pt->y); } - glPopMatrix(); - gluDeleteQuadric(qobj); + immEnd(); + immUnbindProgram(); + GPU_disable_program_point_size(); } /* draw a 2D strokes in "volumetric" style */ -static void gp_draw_stroke_volumetric_2d(bGPDspoint *points, int totpoints, short thickness, - short dflag, short sflag, +static void gp_draw_stroke_volumetric_2d(const bGPDspoint *points, int totpoints, short thickness, + short UNUSED(dflag), short sflag, int offsx, int offsy, int winx, int winy, - float diff_mat[4][4], float ink[4]) + const float diff_mat[4][4], const float ink[4]) { - GLUquadricObj *qobj = gluNewQuadric(); - float modelview[4][4]; - float baseloc[3]; - float scalefac = 1.0f; - - bGPDspoint *pt; - int i; - float fpt[3]; - - /* HACK: We need a scale factor for the drawing in the image editor, - * which seems to use 1 unit as it's maximum size, whereas everything - * else assumes 1 unit = 1 pixel. Otherwise, we only get a massive blob. - */ - if ((dflag & GP_DRAWDATA_IEDITHACK) && (dflag & GP_DRAWDATA_ONLYV2D)) { - scalefac = 0.001f; - } - - /* get basic matrix */ - glGetFloatv(GL_MODELVIEW_MATRIX, (float *)modelview); - copy_v3_v3(baseloc, modelview[3]); - - /* draw points */ - glPushMatrix(); - - for (i = 0, pt = points; i < totpoints; i++, pt++) { - /* color of point */ - gp_set_point_color(pt, ink); - - /* set the transformed position */ + VertexFormat *format = immVertexFormat(); + unsigned pos = add_attrib(format, "pos", GL_FLOAT, 2, KEEP_FLOAT); + unsigned size = add_attrib(format, "size", GL_FLOAT, 1, KEEP_FLOAT); + unsigned color = add_attrib(format, "color", GL_UNSIGNED_BYTE, 4, NORMALIZE_INT_TO_FLOAT); + + immBindBuiltinProgram(GPU_SHADER_3D_POINT_VARYING_SIZE_VARYING_COLOR); + GPU_enable_program_point_size(); + immBegin(GL_POINTS, totpoints); + + const bGPDspoint *pt = points; + for (int i = 0; i < totpoints; i++, pt++) { + /* transform position to 2D */ float co[2]; - + float fpt[3]; + mul_v3_m4v3(fpt, diff_mat, &pt->x); gp_calc_2d_stroke_fxy(fpt, sflag, offsx, offsy, winx, winy, co); - translate_m4(modelview, co[0], co[1], 0.0f); - - glLoadMatrixf((float *)modelview); - - /* draw the disk using the current state... */ - gluDisk(qobj, 0.0, pt->pressure * thickness * scalefac, 32, 1); - - /* restore matrix */ - copy_v3_v3(modelview[3], baseloc); + + gp_set_point_varying_color(pt, ink, color); + immAttrib1f(size, pt->pressure * thickness); /* TODO: scale based on view transform */ + immVertex2f(pos, co[0], co[1]); } - - glPopMatrix(); - gluDeleteQuadric(qobj); + + immEnd(); + immUnbindProgram(); + GPU_disable_program_point_size(); } /* draw a 3D stroke in "volumetric" style */ static void gp_draw_stroke_volumetric_3d( - bGPDspoint *points, int totpoints, short thickness, - short UNUSED(dflag), short UNUSED(sflag), float diff_mat[4][4], float ink[4]) + const bGPDspoint *points, int totpoints, short thickness, + const float ink[4]) { - GLUquadricObj *qobj = gluNewQuadric(); - - float base_modelview[4][4], modelview[4][4]; - float base_loc[3]; - - bGPDspoint *pt; - int i; - float fpt[3]; - - /* Get the basic modelview matrix we use for performing calculations */ - glGetFloatv(GL_MODELVIEW_MATRIX, (float *)base_modelview); - copy_v3_v3(base_loc, base_modelview[3]); - - /* Create the basic view-aligned billboard matrix we're going to actually draw qobj with: - * - We need to knock out the rotation so that we are - * simply left with a camera-facing billboard - * - The scale factors here are chosen so that the thickness - * is relatively reasonable. Otherwise, it gets far too - * large! - */ - scale_m4_fl(modelview, 0.1f); - - /* draw each point as a disk... */ - glPushMatrix(); - - for (i = 0, pt = points; i < totpoints && pt; i++, pt++) { - /* color of point */ - gp_set_point_color(pt, ink); - - mul_v3_m4v3(fpt, diff_mat, &pt->x); - - /* apply translation to base_modelview, so that the translated point is put in the right place */ - translate_m4(base_modelview, fpt[0], fpt[1], fpt[2]); - - /* copy the translation component to the billboard matrix we're going to use, - * then reset the base matrix to the original values so that we can do the same - * for the next point without accumulation/pollution effects - */ - copy_v3_v3(modelview[3], base_modelview[3]); /* copy offset value */ - copy_v3_v3(base_modelview[3], base_loc); /* restore */ - - /* apply our billboard matrix for drawing... */ - glLoadMatrixf((float *)modelview); - - /* draw the disk using the current state... */ - gluDisk(qobj, 0.0, pt->pressure * thickness, 32, 1); + VertexFormat *format = immVertexFormat(); + unsigned pos = add_attrib(format, "pos", GL_FLOAT, 3, KEEP_FLOAT); + unsigned size = add_attrib(format, "size", GL_FLOAT, 1, KEEP_FLOAT); + unsigned color = add_attrib(format, "color", GL_UNSIGNED_BYTE, 4, NORMALIZE_INT_TO_FLOAT); + + immBindBuiltinProgram(GPU_SHADER_3D_POINT_VARYING_SIZE_VARYING_COLOR); + GPU_enable_program_point_size(); + immBegin(GL_POINTS, totpoints); + + const bGPDspoint *pt = points; + for (int i = 0; i < totpoints && pt; i++, pt++) { + gp_set_point_varying_color(pt, ink, color); + immAttrib1f(size, pt->pressure * thickness); /* TODO: scale based on view transform */ + immVertex3fv(pos, &pt->x); /* we can adjust size in vertex shader based on view/projection! */ } - - glPopMatrix(); - gluDeleteQuadric(qobj); + + immEnd(); + immUnbindProgram(); + GPU_disable_program_point_size(); } /* --------------- Stroke Fills ----------------- */ /* Get points of stroke always flat to view not affected by camera view or view position */ -static void gp_stroke_2d_flat(bGPDspoint *points, int totpoints, float(*points2d)[2], int *r_direction) +static void gp_stroke_2d_flat(const bGPDspoint *points, int totpoints, float(*points2d)[2], int *r_direction) { - bGPDspoint *pt0 = &points[0]; - bGPDspoint *pt1 = &points[1]; - bGPDspoint *pt3 = &points[(int)(totpoints * 0.75)]; - + const bGPDspoint *pt0 = &points[0]; + const bGPDspoint *pt1 = &points[1]; + const bGPDspoint *pt3 = &points[(int)(totpoints * 0.75)]; + float locx[3]; float locy[3]; float loc3[3]; float normal[3]; - + /* local X axis (p0 -> p1) */ sub_v3_v3v3(locx, &pt1->x, &pt0->x); - + /* point vector at 3/4 */ sub_v3_v3v3(loc3, &pt3->x, &pt0->x); - + /* vector orthogonal to polygon plane */ cross_v3_v3v3(normal, locx, loc3); - + /* local Y axis (cross to normal/x axis) */ cross_v3_v3v3(locy, normal, locx); - + /* Normalize vectors */ normalize_v3(locx); normalize_v3(locy); - + /* Get all points in local space */ for (int i = 0; i < totpoints; i++) { - bGPDspoint *pt = &points[i]; + const bGPDspoint *pt = &points[i]; float loc[3]; - + /* Get local space using first point as origin */ sub_v3_v3v3(loc, &pt->x, &pt0->x); - + points2d[i][0] = dot_v3v3(loc, locx); points2d[i][1] = dot_v3v3(loc, locy); } - + /* Concave (-1), Convex (1), or Autodetect (0)? */ *r_direction = (int)locy[2]; } @@ -416,14 +453,14 @@ static void gp_stroke_2d_flat(bGPDspoint *points, int totpoints, float(*points2d static void gp_triangulate_stroke_fill(bGPDstroke *gps) { BLI_assert(gps->totpoints >= 3); - + /* allocate memory for temporary areas */ gps->tot_triangles = gps->totpoints - 2; unsigned int (*tmp_triangles)[3] = MEM_mallocN(sizeof(*tmp_triangles) * gps->tot_triangles, "GP Stroke temp triangulation"); float (*points2d)[2] = MEM_mallocN(sizeof(*points2d) * gps->totpoints, "GP Stroke temp 2d points"); - + int direction = 0; - + /* convert to 2d and triangulate */ gp_stroke_2d_flat(gps->points, gps->totpoints, points2d, &direction); BLI_polyfill_calc((const float(*)[2])points2d, (unsigned int)gps->totpoints, direction, (unsigned int(*)[3])tmp_triangles); @@ -438,7 +475,7 @@ static void gp_triangulate_stroke_fill(bGPDstroke *gps) else { gps->triangles = MEM_recallocN(gps->triangles, sizeof(*gps->triangles) * gps->tot_triangles); } - + for (int i = 0; i < gps->tot_triangles; i++) { bGPDtriangle *stroke_triangle = &gps->triangles[i]; stroke_triangle->v1 = tmp_triangles[i][0]; @@ -450,15 +487,15 @@ static void gp_triangulate_stroke_fill(bGPDstroke *gps) /* No triangles needed - Free anything allocated previously */ if (gps->triangles) MEM_freeN(gps->triangles); - + gps->triangles = NULL; } - + /* disable recalculation flag */ if (gps->flag & GP_STROKE_RECALC_CACHES) { gps->flag &= ~GP_STROKE_RECALC_CACHES; } - + /* clear memory */ if (tmp_triangles) MEM_freeN(tmp_triangles); if (points2d) MEM_freeN(points2d); @@ -468,42 +505,55 @@ static void gp_triangulate_stroke_fill(bGPDstroke *gps) /* draw fills for shapes */ static void gp_draw_stroke_fill( bGPdata *gpd, bGPDstroke *gps, - int offsx, int offsy, int winx, int winy, float diff_mat[4][4]) + int offsx, int offsy, int winx, int winy, const float diff_mat[4][4], const float color[4]) { - bGPDpalettecolor *palcolor; - int i; float fpt[3]; BLI_assert(gps->totpoints >= 3); - palcolor = ED_gpencil_stroke_getcolor(gpd, gps); + bGPDpalettecolor *palcolor = ED_gpencil_stroke_getcolor(gpd, gps); /* Triangulation fill if high quality flag is enabled */ if (palcolor->flag & PC_COLOR_HQ_FILL) { - bGPDtriangle *stroke_triangle; - bGPDspoint *pt; - /* Calculate triangles cache for filling area (must be done only after changes) */ if ((gps->flag & GP_STROKE_RECALC_CACHES) || (gps->tot_triangles == 0) || (gps->triangles == NULL)) { gp_triangulate_stroke_fill(gps); } - /* Draw all triangles for filling the polygon (cache must be calculated before) */ BLI_assert(gps->tot_triangles >= 1); - glBegin(GL_TRIANGLES); - for (i = 0, stroke_triangle = gps->triangles; i < gps->tot_triangles; i++, stroke_triangle++) { + + unsigned pos; + if (gps->flag & GP_STROKE_3DSPACE) { + pos = add_attrib(immVertexFormat(), "pos", GL_FLOAT, 3, KEEP_FLOAT); + immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR); + } + else { + pos = add_attrib(immVertexFormat(), "pos", GL_FLOAT, 2, KEEP_FLOAT); + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + } + + immUniformColor4fv(color); + + /* Draw all triangles for filling the polygon (cache must be calculated before) */ + immBegin(GL_TRIANGLES, gps->tot_triangles * 3); + /* TODO: use batch instead of immediate mode, to share vertices */ + + bGPDtriangle *stroke_triangle = gps->triangles; + bGPDspoint *pt; + + for (int i = 0; i < gps->tot_triangles; i++, stroke_triangle++) { if (gps->flag & GP_STROKE_3DSPACE) { /* vertex 1 */ pt = &gps->points[stroke_triangle->v1]; mul_v3_m4v3(fpt, diff_mat, &pt->x); - glVertex3fv(fpt); + immVertex3fv(pos, fpt); /* vertex 2 */ pt = &gps->points[stroke_triangle->v2]; mul_v3_m4v3(fpt, diff_mat, &pt->x); - glVertex3fv(fpt); + immVertex3fv(pos, fpt); /* vertex 3 */ pt = &gps->points[stroke_triangle->v3]; mul_v3_m4v3(fpt, diff_mat, &pt->x); - glVertex3fv(fpt); + immVertex3fv(pos, fpt); } else { float co[2]; @@ -511,21 +561,25 @@ static void gp_draw_stroke_fill( pt = &gps->points[stroke_triangle->v1]; mul_v3_m4v3(fpt, diff_mat, &pt->x); gp_calc_2d_stroke_fxy(fpt, gps->flag, offsx, offsy, winx, winy, co); - glVertex2fv(co); + immVertex2fv(pos, co); /* vertex 2 */ pt = &gps->points[stroke_triangle->v2]; mul_v3_m4v3(fpt, diff_mat, &pt->x); gp_calc_2d_stroke_fxy(fpt, gps->flag, offsx, offsy, winx, winy, co); - glVertex2fv(co); + immVertex2fv(pos, co); /* vertex 3 */ pt = &gps->points[stroke_triangle->v3]; mul_v3_m4v3(fpt, diff_mat, &pt->x); gp_calc_2d_stroke_fxy(fpt, gps->flag, offsx, offsy, winx, winy, co); - glVertex2fv(co); + immVertex2fv(pos, co); } } - glEnd(); + + immEnd(); + immUnbindProgram(); } + +#if 0 /* convert to modern GL only if needed */ else { /* As an initial implementation, we use the OpenGL filled polygon drawing * here since it's the easiest option to implement for this case. It does @@ -537,10 +591,10 @@ static void gp_draw_stroke_fill( * created using old versions of Blender which may have depended on the artifacts * the old fills created. */ - bGPDspoint *pt; + bGPDspoint *pt = gps->points; glBegin(GL_POLYGON); - for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) { + for (int i = 0; i < gps->totpoints; i++, pt++) { if (gps->flag & GP_STROKE_3DSPACE) { mul_v3_m4v3(fpt, diff_mat, &pt->x); glVertex3fv(fpt); @@ -555,159 +609,186 @@ static void gp_draw_stroke_fill( glEnd(); } +#endif } /* ----- Existing Strokes Drawing (3D and Point) ------ */ /* draw a given stroke - just a single dot (only one point) */ static void gp_draw_stroke_point( - bGPDspoint *points, short thickness, short dflag, short sflag, - int offsx, int offsy, int winx, int winy, float diff_mat[4][4], float ink[4]) + const bGPDspoint *points, short thickness, short UNUSED(dflag), short sflag, + int offsx, int offsy, int winx, int winy, const float diff_mat[4][4], const float ink[4]) { - float fpt[3]; - bGPDspoint *pt = &points[0]; - - /* color of point */ - gp_set_point_color(pt, ink); + const bGPDspoint *pt = points; - /* set point thickness (since there's only one of these) */ - glPointSize((float)(thickness + 2) * points->pressure); - /* get final position using parent matrix */ + float fpt[3]; mul_v3_m4v3(fpt, diff_mat, &pt->x); - /* draw point */ + VertexFormat *format = immVertexFormat(); + unsigned pos = add_attrib(format, "pos", GL_FLOAT, 3, KEEP_FLOAT); + if (sflag & GP_STROKE_3DSPACE) { - glBegin(GL_POINTS); - glVertex3fv(fpt); - glEnd(); + immBindBuiltinProgram(GPU_SHADER_3D_POINT_UNIFORM_SIZE_UNIFORM_COLOR_SMOOTH); } else { - float co[2]; - - /* get coordinates of point */ + immBindBuiltinProgram(GPU_SHADER_2D_POINT_UNIFORM_SIZE_UNIFORM_COLOR_SMOOTH); + + /* get 2D coordinates of point */ + float co[3] = { 0.0f }; gp_calc_2d_stroke_fxy(fpt, sflag, offsx, offsy, winx, winy, co); - - /* if thickness is less than GP_DRAWTHICKNESS_SPECIAL, simple dot looks ok - * - also mandatory in if Image Editor 'image-based' dot - */ - if ((thickness < GP_DRAWTHICKNESS_SPECIAL) || - ((dflag & GP_DRAWDATA_IEDITHACK) && (sflag & GP_STROKE_2DSPACE))) - { - glBegin(GL_POINTS); - glVertex2fv(co); - glEnd(); - } - else { - /* draw filled circle as is done in circf (but without the matrix push/pops which screwed things up) */ - GLUquadricObj *qobj = gluNewQuadric(); - - gluQuadricDrawStyle(qobj, GLU_FILL); - - /* need to translate drawing position, but must reset after too! */ - glTranslate2fv(co); - gluDisk(qobj, 0.0, thickness, 32, 1); - glTranslatef(-co[0], -co[1], 0.0); - - gluDeleteQuadric(qobj); - } + copy_v3_v3(fpt, co); } + + gp_set_point_uniform_color(pt, ink); + /* set point thickness (since there's only one of these) */ + immUniform1f("size", (float)(thickness + 2) * pt->pressure); + + immBegin(GL_POINTS, 1); + immVertex3fv(pos, fpt); + immEnd(); + + immUnbindProgram(); } /* draw a given stroke in 3d (i.e. in 3d-space), using simple ogl lines */ -static void gp_draw_stroke_3d(bGPDspoint *points, int totpoints, short thickness, bool debug, - short UNUSED(sflag), float diff_mat[4][4], float ink[4], bool cyclic) +static void gp_draw_stroke_3d(const bGPDspoint *points, int totpoints, short thickness, bool UNUSED(debug), + short UNUSED(sflag), const float diff_mat[4][4], const float ink[4], bool cyclic) { - bGPDspoint *pt, *pt2; float curpressure = points[0].pressure; - int i; float fpt[3]; float cyclic_fpt[3]; + int draw_points = 0; + + /* if cyclic needs one vertex more */ + int cyclic_add = 0; + if (cyclic) { + ++cyclic_add; + } + + + VertexFormat *format = immVertexFormat(); + unsigned pos = add_attrib(format, "pos", GL_FLOAT, 3, KEEP_FLOAT); + unsigned color = add_attrib(format, "color", GL_UNSIGNED_BYTE, 4, NORMALIZE_INT_TO_FLOAT); + + immBindBuiltinProgram(GPU_SHADER_3D_SMOOTH_COLOR); + + /* TODO: implement this with a geometry shader to draw one continuous tapered stroke */ /* draw stroke curve */ glLineWidth(max_ff(curpressure * thickness, 1.0f)); - glBegin(GL_LINE_STRIP); - for (i = 0, pt = points; i < totpoints && pt; i++, pt++) { - gp_set_point_color(pt, ink); + immBeginAtMost(GL_LINE_STRIP, totpoints + cyclic_add); + const bGPDspoint *pt = points; + for (int i = 0; i < totpoints; i++, pt++) { + gp_set_point_varying_color(pt, ink, color); /* if there was a significant pressure change, stop the curve, change the thickness of the stroke, * and continue drawing again (since line-width cannot change in middle of GL_LINE_STRIP) * Note: we want more visible levels of pressures when thickness is bigger. */ if (fabsf(pt->pressure - curpressure) > 0.2f / (float)thickness) { - glEnd(); + /* if the pressure changes before get at least 2 vertices, need to repeat last point to avoid assert in immEnd() */ + if (draw_points < 2) { + const bGPDspoint *pt2 = pt - 1; + mul_v3_m4v3(fpt, diff_mat, &pt2->x); + immVertex3fv(pos, fpt); + } + immEnd(); + draw_points = 0; + curpressure = pt->pressure; glLineWidth(max_ff(curpressure * thickness, 1.0f)); - glBegin(GL_LINE_STRIP); - + immBeginAtMost(GL_LINE_STRIP, totpoints - i + 1 + cyclic_add); + /* need to roll-back one point to ensure that there are no gaps in the stroke */ if (i != 0) { - pt2 = pt - 1; + const bGPDspoint *pt2 = pt - 1; mul_v3_m4v3(fpt, diff_mat, &pt2->x); - glVertex3fv(fpt); + gp_set_point_varying_color(pt2, ink, color); + immVertex3fv(pos, fpt); + ++draw_points; } - - /* now the point we want... */ - mul_v3_m4v3(fpt, diff_mat, &pt->x); - glVertex3fv(fpt); } - else { - mul_v3_m4v3(fpt, diff_mat, &pt->x); - glVertex3fv(fpt); - } - /* saves first point to use in cyclic */ - if (i == 0) { + + /* now the point we want */ + mul_v3_m4v3(fpt, diff_mat, &pt->x); + immVertex3fv(pos, fpt); + ++draw_points; + + if (cyclic && i == 0) { + /* save first point to use in cyclic */ copy_v3_v3(cyclic_fpt, fpt); } } - /* if cyclic draw line to first point */ + if (cyclic) { - glVertex3fv(cyclic_fpt); + /* draw line to first point to complete the cycle */ + immVertex3fv(pos, cyclic_fpt); + ++draw_points; + } + + /* if less of two points, need to repeat last point to avoid assert in immEnd() */ + if (draw_points < 2) { + const bGPDspoint *pt2 = pt - 1; + mul_v3_m4v3(fpt, diff_mat, &pt2->x); + gp_set_point_varying_color(pt2, ink, color); + immVertex3fv(pos, fpt); } - glEnd(); + immEnd(); + immUnbindProgram(); + +#if 0 /* convert to modern GL only if needed */ /* draw debug points of curve on top? */ /* XXX: for now, we represent "selected" strokes in the same way as debug, which isn't used anymore */ if (debug) { glPointSize((float)(thickness + 2)); - + glBegin(GL_POINTS); - for (i = 0, pt = points; i < totpoints && pt; i++, pt++) { + const bGPDspoint *pt = points; + for (int i = 0; i < totpoints; i++, pt++) { mul_v3_m4v3(fpt, diff_mat, &pt->x); glVertex3fv(fpt); } glEnd(); - } +#endif } /* ----- Fancy 2D-Stroke Drawing ------ */ /* draw a given stroke in 2d */ -static void gp_draw_stroke_2d(bGPDspoint *points, int totpoints, short thickness_s, short dflag, short sflag, - bool debug, int offsx, int offsy, int winx, int winy, float diff_mat[4][4], float ink[4]) +static void gp_draw_stroke_2d(const bGPDspoint *points, int totpoints, short thickness_s, short dflag, short sflag, + bool debug, int offsx, int offsy, int winx, int winy, const float diff_mat[4][4], const float ink[4]) { /* otherwise thickness is twice that of the 3D view */ float thickness = (float)thickness_s * 0.5f; - + /* strokes in Image Editor need a scale factor, since units there are not pixels! */ float scalefac = 1.0f; if ((dflag & GP_DRAWDATA_IEDITHACK) && (dflag & GP_DRAWDATA_ONLYV2D)) { scalefac = 0.001f; } - + + /* TODO: fancy++ with the magic of shaders */ + /* tessellation code - draw stroke as series of connected quads with connection * edges rotated to minimize shrinking artifacts, and rounded endcaps */ { - bGPDspoint *pt1, *pt2; + const bGPDspoint *pt1, *pt2; float pm[2]; int i; float fpt[3]; - - glShadeModel(GL_FLAT); - glBegin(GL_QUADS); - + + VertexFormat *format = immVertexFormat(); + unsigned pos = add_attrib(format, "pos", GL_FLOAT, 2, KEEP_FLOAT); + unsigned color = add_attrib(format, "color", GL_UNSIGNED_BYTE, 4, NORMALIZE_INT_TO_FLOAT); + + /* this code previously used glShadeModel(GL_FLAT) */ + immBindBuiltinProgram(GPU_SHADER_2D_FLAT_COLOR); + immBegin(GL_QUADS, (totpoints - 2) * 4 + 12); + for (i = 0, pt1 = points, pt2 = points + 1; i < (totpoints - 1); i++, pt1++, pt2++) { float s0[2], s1[2]; /* segment 'center' points */ float t0[2], t1[2]; /* tessellated coordinates */ @@ -721,19 +802,19 @@ static void gp_draw_stroke_2d(bGPDspoint *points, int totpoints, short thickness mul_v3_m4v3(fpt, diff_mat, &pt2->x); gp_calc_2d_stroke_fxy(fpt, sflag, offsx, offsy, winx, winy, s1); - + /* calculate gradient and normal - 'angle'=(ny/nx) */ m1[1] = s1[1] - s0[1]; m1[0] = s1[0] - s0[0]; normalize_v2(m1); m2[1] = -m1[0]; m2[0] = m1[1]; - + /* always use pressure from first point here */ pthick = (pt1->pressure * thickness * scalefac); - + /* color of point */ - gp_set_point_color(pt1, ink); + gp_set_point_varying_color(pt1, ink, color); /* if the first segment, start of segment is segment's normal */ if (i == 0) { @@ -744,40 +825,40 @@ static void gp_draw_stroke_2d(bGPDspoint *points, int totpoints, short thickness mt[1] = m2[1] * pthick * 0.5f; sc[0] = s0[0] - (m1[0] * pthick * 0.75f); sc[1] = s0[1] - (m1[1] * pthick * 0.75f); - + t0[0] = sc[0] - mt[0]; t0[1] = sc[1] - mt[1]; t1[0] = sc[0] + mt[0]; t1[1] = sc[1] + mt[1]; - - glVertex2fv(t0); - glVertex2fv(t1); - + + immVertex2fv(pos, t0); + immVertex2fv(pos, t1); + /* calculate points for start of segment */ mt[0] = m2[0] * pthick; mt[1] = m2[1] * pthick; - + t0[0] = s0[0] - mt[0]; t0[1] = s0[1] - mt[1]; t1[0] = s0[0] + mt[0]; t1[1] = s0[1] + mt[1]; - + /* draw this line twice (first to finish off start cap, then for stroke) */ - glVertex2fv(t1); - glVertex2fv(t0); - glVertex2fv(t0); - glVertex2fv(t1); + immVertex2fv(pos, t1); + immVertex2fv(pos, t0); + immVertex2fv(pos, t0); + immVertex2fv(pos, t1); } /* if not the first segment, use bisector of angle between segments */ else { float mb[2]; /* bisector normal */ float athick, dfac; /* actual thickness, difference between thicknesses */ - + /* calculate gradient of bisector (as average of normals) */ mb[0] = (pm[0] + m2[0]) / 2; mb[1] = (pm[1] + m2[1]) / 2; normalize_v2(mb); - + /* calculate gradient to apply * - as basis, use just pthick * bisector gradient * - if cross-section not as thick as it should be, add extra padding to fix it @@ -786,49 +867,48 @@ static void gp_draw_stroke_2d(bGPDspoint *points, int totpoints, short thickness mt[1] = mb[1] * pthick; athick = len_v2(mt); dfac = pthick - (athick * 2); - + if (((athick * 2.0f) < pthick) && (IS_EQF(athick, pthick) == 0)) { mt[0] += (mb[0] * dfac); mt[1] += (mb[1] * dfac); } - + /* calculate points for start of segment */ t0[0] = s0[0] - mt[0]; t0[1] = s0[1] - mt[1]; t1[0] = s0[0] + mt[0]; t1[1] = s0[1] + mt[1]; - + /* draw this line twice (once for end of current segment, and once for start of next) */ - glVertex2fv(t1); - glVertex2fv(t0); - glVertex2fv(t0); - glVertex2fv(t1); + immVertex2fv(pos, t1); + immVertex2fv(pos, t0); + immVertex2fv(pos, t0); + immVertex2fv(pos, t1); } - + /* if last segment, also draw end of segment (defined as segment's normal) */ if (i == totpoints - 2) { /* for once, we use second point's pressure (otherwise it won't be drawn) */ pthick = (pt2->pressure * thickness * scalefac); - + /* color of point */ - gp_set_point_color(pt2, ink); + gp_set_point_varying_color(pt2, ink, color); /* calculate points for end of segment */ mt[0] = m2[0] * pthick; mt[1] = m2[1] * pthick; - + t0[0] = s1[0] - mt[0]; t0[1] = s1[1] - mt[1]; t1[0] = s1[0] + mt[0]; t1[1] = s1[1] + mt[1]; - + /* draw this line twice (once for end of stroke, and once for endcap)*/ - glVertex2fv(t1); - glVertex2fv(t0); - glVertex2fv(t0); - glVertex2fv(t1); - - + immVertex2fv(pos, t1); + immVertex2fv(pos, t0); + immVertex2fv(pos, t0); + immVertex2fv(pos, t1); + /* draw end cap as last step * - make points slightly closer to center (about halfway across) */ @@ -836,34 +916,33 @@ static void gp_draw_stroke_2d(bGPDspoint *points, int totpoints, short thickness mt[1] = m2[1] * pthick * 0.5f; sc[0] = s1[0] + (m1[0] * pthick * 0.75f); sc[1] = s1[1] + (m1[1] * pthick * 0.75f); - + t0[0] = sc[0] - mt[0]; t0[1] = sc[1] - mt[1]; t1[0] = sc[0] + mt[0]; t1[1] = sc[1] + mt[1]; - - glVertex2fv(t1); - glVertex2fv(t0); + + immVertex2fv(pos, t1); + immVertex2fv(pos, t0); } - + /* store stroke's 'natural' normal for next stroke to use */ copy_v2_v2(pm, m2); } - - glEnd(); - glShadeModel(GL_SMOOTH); + + immEnd(); + immUnbindProgram(); } - + +#if 0 /* convert to modern GL only if needed */ /* draw debug points of curve on top? (original stroke points) */ if (debug) { - bGPDspoint *pt; - int i; - float fpt[3]; - glPointSize((float)(thickness_s + 2)); - + glBegin(GL_POINTS); - for (i = 0, pt = points; i < totpoints && pt; i++, pt++) { + const bGPDspoint *pt = points; + for (int i = 0; i < totpoints && pt; i++, pt++) { + float fpt[3]; float co[2]; mul_v3_m4v3(fpt, diff_mat, &pt->x); gp_calc_2d_stroke_fxy(fpt, sflag, offsx, offsy, winx, winy, co); @@ -871,6 +950,9 @@ static void gp_draw_stroke_2d(bGPDspoint *points, int totpoints, short thickness } glEnd(); } +#else + UNUSED_VARS(debug); +#endif } /* ----- Strokes Drawing ------ */ @@ -884,41 +966,41 @@ static bool gp_can_draw_stroke(const bGPDstroke *gps, const int dflag) return false; if (!(dflag & GP_DRAWDATA_ONLY3D) && (gps->flag & GP_STROKE_3DSPACE)) return false; - + /* 2) Screen Space 2D Strokes */ if ((dflag & GP_DRAWDATA_ONLYV2D) && !(gps->flag & GP_STROKE_2DSPACE)) return false; if (!(dflag & GP_DRAWDATA_ONLYV2D) && (gps->flag & GP_STROKE_2DSPACE)) return false; - + /* 3) Image Space (2D) */ if ((dflag & GP_DRAWDATA_ONLYI2D) && !(gps->flag & GP_STROKE_2DIMAGE)) return false; if (!(dflag & GP_DRAWDATA_ONLYI2D) && (gps->flag & GP_STROKE_2DIMAGE)) return false; - - + /* skip stroke if it doesn't have any valid data */ if ((gps->points == NULL) || (gps->totpoints < 1)) return false; - + /* stroke can be drawn */ return true; } /* draw a set of strokes */ static void gp_draw_strokes( - bGPdata *gpd, bGPDframe *gpf, int offsx, int offsy, int winx, int winy, int dflag, + bGPdata *gpd, const bGPDframe *gpf, int offsx, int offsy, int winx, int winy, int dflag, bool debug, short lthick, const float opacity, const float tintcolor[4], - const bool onion, const bool custonion, float diff_mat[4][4]) + const bool onion, const bool custonion, const float diff_mat[4][4]) { - bGPDstroke *gps; float tcolor[4]; float tfill[4]; short sthickness; float ink[4]; - for (gps = gpf->strokes.first; gps; gps = gps->next) { + GPU_enable_program_point_size(); + + for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) { /* check if stroke can be drawn */ if (gp_can_draw_stroke(gps, dflag) == false) { continue; @@ -936,6 +1018,10 @@ static void gp_draw_strokes( /* calculate thickness */ sthickness = gps->thickness + lthick; + if (sthickness <= 0) { + continue; + } + /* check which stroke-drawer to use */ if (dflag & GP_DRAWDATA_ONLY3D) { const int no_xray = (dflag & GP_DRAWDATA_NO_XRAY); @@ -962,19 +1048,20 @@ static void gp_draw_strokes( interp_v3_v3v3(tfill, palcolor->fill, tintcolor, tintcolor[3]); tfill[3] = palcolor->fill[3] * opacity; if (tfill[3] > GPENCIL_ALPHA_OPACITY_THRESH) { + const float *color; if (!onion) { - glColor4fv(tfill); + color = tfill; } else { if (custonion) { - glColor4fv(tintcolor); + color = tintcolor; } else { ARRAY_SET_ITEMS(tfill, UNPACK3(palcolor->fill), tintcolor[3]); - glColor4fv(tfill); + color = tfill; } } - gp_draw_stroke_fill(gpd, gps, offsx, offsy, winx, winy, diff_mat); + gp_draw_stroke_fill(gpd, gps, offsx, offsy, winx, winy, diff_mat, color); } } @@ -996,7 +1083,7 @@ static void gp_draw_strokes( } if (palcolor->flag & PC_COLOR_VOLUMETRIC) { /* volumetric stroke drawing */ - gp_draw_stroke_volumetric_3d(gps->points, gps->totpoints, sthickness, dflag, gps->flag, diff_mat, ink); + gp_draw_stroke_volumetric_3d(gps->points, gps->totpoints, sthickness, ink); } else { /* 3D Lines - OpenGL primitives-based */ @@ -1027,20 +1114,21 @@ static void gp_draw_strokes( interp_v3_v3v3(tfill, palcolor->fill, tintcolor, tintcolor[3]); tfill[3] = palcolor->fill[3] * opacity; if (tfill[3] > GPENCIL_ALPHA_OPACITY_THRESH) { + const float *color; if (!onion) { - glColor4fv(tfill); + color = tfill; } else { if (custonion) { - glColor4fv(tintcolor); + color = tintcolor; } else { ARRAY_SET_ITEMS(tfill, palcolor->fill[0], palcolor->fill[1], palcolor->fill[2], tintcolor[3]); - glColor4fv(tfill); + color = tfill; } } - gp_draw_stroke_fill(gpd, gps, offsx, offsy, winx, winy, diff_mat); + gp_draw_stroke_fill(gpd, gps, offsx, offsy, winx, winy, diff_mat, color); } } @@ -1078,15 +1166,15 @@ static void gp_draw_strokes( } } } + + GPU_disable_program_point_size(); } /* Draw selected verts for strokes being edited */ static void gp_draw_strokes_edit( - bGPdata *gpd, bGPDframe *gpf, int offsx, int offsy, int winx, int winy, short dflag, - short lflag, float diff_mat[4][4], float alpha) + bGPdata *gpd, const bGPDframe *gpf, int offsx, int offsy, int winx, int winy, short dflag, + short lflag, const float diff_mat[4][4], float alpha) { - bGPDstroke *gps; - /* if alpha 0 do not draw */ if (alpha == 0.0f) return; @@ -1100,36 +1188,32 @@ static void gp_draw_strokes_edit( glGetIntegerv(GL_DEPTH_WRITEMASK, &mask_orig); glDepthMask(0); glEnable(GL_DEPTH_TEST); - + /* first arg is normally rv3d->dist, but this isn't * available here and seems to work quite well without */ bglPolygonOffset(1.0f, 1.0f); #if 0 - glEnable(GL_POLYGON_OFFSET_LINE); + glEnable(GL_POLYGON_OFFSET_LINE); /* do we want LINE or POINT here? (merwin) */ glPolygonOffset(-1.0f, -1.0f); #endif } } - - - /* draw stroke verts */ - for (gps = gpf->strokes.first; gps; gps = gps->next) { - bGPDspoint *pt; - float vsize, bsize; - int i; - float fpt[3]; + GPU_enable_program_point_size(); + + /* draw stroke verts */ + for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) { /* check if stroke can be drawn */ if (gp_can_draw_stroke(gps, dflag) == false) continue; - + /* Optimisation: only draw points for selected strokes * We assume that selected points can only occur in * strokes that are selected too. */ if ((gps->flag & GP_STROKE_SELECT) == 0) continue; - + /* verify palette color lock */ { bGPDpalettecolor *palcolor = ED_gpencil_stroke_getcolor(gpd, gps); @@ -1148,7 +1232,8 @@ static void gp_draw_strokes_edit( * they stand out more. * - We use the theme setting for size of the unselected verts */ - bsize = UI_GetThemeValuef(TH_GP_VERTEX_SIZE); + float bsize = UI_GetThemeValuef(TH_GP_VERTEX_SIZE); + float vsize; if ((int)bsize > 8) { vsize = 10.0f; bsize = 8.0f; @@ -1156,89 +1241,83 @@ static void gp_draw_strokes_edit( else { vsize = bsize + 2; } - - /* First Pass: Draw all the verts (i.e. these become the unselected state) */ + /* for now, we assume that the base color of the points is not too close to the real color */ /* set color using palette */ bGPDpalettecolor *palcolor = ED_gpencil_stroke_getcolor(gpd, gps); - glColor3fv(palcolor->color); - glPointSize(bsize); - - glBegin(GL_POINTS); - for (i = 0, pt = gps->points; i < gps->totpoints && pt; i++, pt++) { + float selectColor[4]; + UI_GetThemeColor3fv(TH_GP_VERTEX_SELECT, selectColor); + selectColor[3] = alpha; + + VertexFormat *format = immVertexFormat(); + unsigned pos; /* specified later */ + unsigned size = add_attrib(format, "size", GL_FLOAT, 1, KEEP_FLOAT); + unsigned color = add_attrib(format, "color", GL_FLOAT, 3, KEEP_FLOAT); + + if (gps->flag & GP_STROKE_3DSPACE) { + pos = add_attrib(format, "pos", GL_FLOAT, 3, KEEP_FLOAT); + immBindBuiltinProgram(GPU_SHADER_3D_POINT_VARYING_SIZE_VARYING_COLOR); + } + else { + pos = add_attrib(format, "pos", GL_FLOAT, 2, KEEP_FLOAT); + immBindBuiltinProgram(GPU_SHADER_2D_POINT_VARYING_SIZE_VARYING_COLOR); + } + + immBegin(GL_POINTS, gps->totpoints); + + /* Draw start and end point differently if enabled stroke direction hint */ + bool show_direction_hint = (gpd->flag & GP_DATA_SHOW_DIRECTION) && (gps->totpoints > 1); + + /* Draw all the stroke points (selected or not) */ + bGPDspoint *pt = gps->points; + float fpt[3]; + for (int i = 0; i < gps->totpoints; i++, pt++) { + /* size and color first */ + if (show_direction_hint && i == 0) { + /* start point in green bigger */ + immAttrib3f(color, 0.0f, 1.0f, 0.0f); + immAttrib1f(size, vsize + 4); + } + else if (show_direction_hint && (i == gps->totpoints - 1)) { + /* end point in red smaller */ + immAttrib3f(color, 1.0f, 0.0f, 0.0f); + immAttrib1f(size, vsize + 1); + } + else if (pt->flag & GP_SPOINT_SELECT) { + immAttrib3fv(color, selectColor); + immAttrib1f(size, vsize); + } + else { + immAttrib3fv(color, palcolor->color); + immAttrib1f(size, bsize); + } + + /* then position */ if (gps->flag & GP_STROKE_3DSPACE) { mul_v3_m4v3(fpt, diff_mat, &pt->x); - glVertex3fv(fpt); + immVertex3fv(pos, fpt); } else { float co[2]; mul_v3_m4v3(fpt, diff_mat, &pt->x); gp_calc_2d_stroke_fxy(fpt, gps->flag, offsx, offsy, winx, winy, co); - glVertex2fv(co); + immVertex2fv(pos, co); } } - glEnd(); - - - /* Second Pass: Draw only verts which are selected */ - float curColor[4]; - UI_GetThemeColor3fv(TH_GP_VERTEX_SELECT, curColor); - glColor4f(curColor[0], curColor[1], curColor[2], alpha); - - glPointSize(vsize); - - glBegin(GL_POINTS); - for (i = 0, pt = gps->points; i < gps->totpoints && pt; i++, pt++) { - if (pt->flag & GP_SPOINT_SELECT) { - if (gps->flag & GP_STROKE_3DSPACE) { - mul_v3_m4v3(fpt, diff_mat, &pt->x); - glVertex3fv(fpt); - } - else { - float co[2]; - - mul_v3_m4v3(fpt, diff_mat, &pt->x); - gp_calc_2d_stroke_fxy(fpt, gps->flag, offsx, offsy, winx, winy, co); - glVertex2fv(co); - } - } - } - glEnd(); - /* Draw start and end point if enabled stroke direction hint */ - if ((gpd->flag & GP_DATA_SHOW_DIRECTION) && (gps->totpoints > 1)) { - bGPDspoint *p; - - glPointSize(vsize + 4); - glBegin(GL_POINTS); - - /* start point in green bigger */ - glColor3f(0.0f, 1.0f, 0.0f); - p = &gps->points[0]; - mul_v3_m4v3(fpt, diff_mat, &p->x); - glVertex3fv(fpt); - glEnd(); + immEnd(); + immUnbindProgram(); + } - /* end point in red smaller */ - glPointSize(vsize + 1); - glBegin(GL_POINTS); + GPU_disable_program_point_size(); - glColor3f(1.0f, 0.0f, 0.0f); - p = &gps->points[gps->totpoints - 1]; - mul_v3_m4v3(fpt, diff_mat, &p->x); - glVertex3fv(fpt); - glEnd(); - } - } - - /* clear depth mask */ if (dflag & GP_DRAWDATA_ONLY3D) { if (no_xray) { glDepthMask(mask_orig); glDisable(GL_DEPTH_TEST); - + bglPolygonOffset(0.0, 0.0); #if 0 glDisable(GL_POLYGON_OFFSET_LINE); @@ -1252,8 +1331,8 @@ static void gp_draw_strokes_edit( /* draw onion-skinning for a layer */ static void gp_draw_onionskins( - bGPdata *gpd, bGPDlayer *gpl, bGPDframe *gpf, int offsx, int offsy, int winx, int winy, - int UNUSED(cfra), int dflag, bool debug, float diff_mat[4][4]) + bGPdata *gpd, const bGPDlayer *gpl, const bGPDframe *gpf, int offsx, int offsy, int winx, int winy, + int UNUSED(cfra), int dflag, bool debug, const float diff_mat[4][4]) { const float default_color[3] = {UNPACK3(U.gpencil_new_layer_col)}; const float alpha = 1.0f; @@ -1266,17 +1345,14 @@ static void gp_draw_onionskins( else { copy_v3_v3(color, default_color); } - + if (gpl->gstep > 0) { - bGPDframe *gf; - float fac; - /* draw previous frames first */ - for (gf = gpf->prev; gf; gf = gf->prev) { + for (bGPDframe *gf = gpf->prev; gf; gf = gf->prev) { /* check if frame is drawable */ if ((gpf->framenum - gf->framenum) <= gpl->gstep) { /* alpha decreases with distance from curframe index */ - fac = 1.0f - ((float)(gpf->framenum - gf->framenum) / (float)(gpl->gstep + 1)); + float fac = 1.0f - ((float)(gpf->framenum - gf->framenum) / (float)(gpl->gstep + 1)); color[3] = alpha * fac * 0.66f; gp_draw_strokes(gpd, gf, offsx, offsy, winx, winy, dflag, debug, gpl->thickness, 1.0f, color, true, gpl->flag & GP_LAYER_GHOST_PREVCOL, diff_mat); @@ -1296,8 +1372,7 @@ static void gp_draw_onionskins( else { /* don't draw - disabled */ } - - + /* 2) Now draw next frames */ if (gpl->flag & GP_LAYER_GHOST_NEXTCOL) { copy_v3_v3(color, gpl->gcolor_next); @@ -1305,17 +1380,14 @@ static void gp_draw_onionskins( else { copy_v3_v3(color, default_color); } - + if (gpl->gstep_next > 0) { - bGPDframe *gf; - float fac; - /* now draw next frames */ - for (gf = gpf->next; gf; gf = gf->next) { + for (bGPDframe *gf = gpf->next; gf; gf = gf->next) { /* check if frame is drawable */ if ((gf->framenum - gpf->framenum) <= gpl->gstep_next) { /* alpha decreases with distance from curframe index */ - fac = 1.0f - ((float)(gf->framenum - gpf->framenum) / (float)(gpl->gstep_next + 1)); + float fac = 1.0f - ((float)(gf->framenum - gpf->framenum) / (float)(gpl->gstep_next + 1)); color[3] = alpha * fac * 0.66f; gp_draw_strokes(gpd, gf, offsx, offsy, winx, winy, dflag, debug, gpl->thickness, 1.0f, color, true, gpl->flag & GP_LAYER_GHOST_NEXTCOL, diff_mat); @@ -1335,7 +1407,6 @@ static void gp_draw_onionskins( else { /* don't draw - disabled */ } - } /* draw interpolate strokes (used only while operator is running) */ @@ -1373,29 +1444,27 @@ void ED_gp_draw_interpolation(tGPDinterpolate *tgpi, const int type) /* loop over gpencil data layers, drawing them */ static void gp_draw_data_layers( - bGPDbrush *brush, float alpha, bGPdata *gpd, + const bGPDbrush *brush, float alpha, bGPdata *gpd, int offsx, int offsy, int winx, int winy, int cfra, int dflag) { - bGPDlayer *gpl; float diff_mat[4][4]; - for (gpl = gpd->layers.first; gpl; gpl = gpl->next) { - bGPDframe *gpf; + for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) { /* calculate parent position */ ED_gpencil_parent_location(gpl, diff_mat); - bool debug = (gpl->flag & GP_LAYER_DRAWDEBUG) ? true : false; + bool debug = (gpl->flag & GP_LAYER_DRAWDEBUG); short lthick = brush->thickness + gpl->thickness; - + /* don't draw layer if hidden */ if (gpl->flag & GP_LAYER_HIDE) continue; - + /* get frame to draw */ - gpf = BKE_gpencil_layer_getframe(gpl, cfra, 0); + bGPDframe *gpf = BKE_gpencil_layer_getframe(gpl, cfra, 0); if (gpf == NULL) continue; - + /* set basic stroke thickness */ glLineWidth(lthick); @@ -1407,10 +1476,10 @@ static void gp_draw_data_layers( if (condition) dflag |= (draw_flag_value); \ else dflag &= ~(draw_flag_value); \ } (void)0 - + /* xray... */ GP_DRAWFLAG_APPLY((gpl->flag & GP_LAYER_NO_XRAY), GP_DRAWDATA_NO_XRAY); - + /* volumetric strokes... */ GP_DRAWFLAG_APPLY((gpl->flag & GP_LAYER_VOLUMETRIC), GP_DRAWDATA_VOLUMETRIC); @@ -1434,11 +1503,11 @@ static void gp_draw_data_layers( */ gp_draw_onionskins(gpd, gpl, gpf, offsx, offsy, winx, winy, cfra, dflag, debug, diff_mat); } - + /* draw the strokes already in active frame */ gp_draw_strokes(gpd, gpf, offsx, offsy, winx, winy, dflag, debug, gpl->thickness, gpl->opacity, gpl->tintcolor, false, false, diff_mat); - + /* Draw verts of selected strokes * - when doing OpenGL renders, we don't want to be showing these, as that ends up flickering * - locked layers can't be edited, so there's no point showing these verts @@ -1453,16 +1522,13 @@ static void gp_draw_data_layers( { gp_draw_strokes_edit(gpd, gpf, offsx, offsy, winx, winy, dflag, gpl->flag, diff_mat, alpha); } - + /* Check if may need to draw the active stroke cache, only if this layer is the active layer * that is being edited. (Stroke buffer is currently stored in gp-data) */ if (ED_gpencil_session_active() && (gpl->flag & GP_LAYER_ACTIVE) && (gpf->flag & GP_FRAME_PAINT)) { - /* Set color for drawing buffer stroke - since this may not be set yet */ - // glColor4fv(gpl->color); - /* Buffer stroke needs to be drawn with a different linestyle * to help differentiate them from normal strokes. * @@ -1471,89 +1537,94 @@ static void gp_draw_data_layers( */ if (gpd->sflag & PC_COLOR_VOLUMETRIC) { gp_draw_stroke_volumetric_buffer(gpd->sbuffer, gpd->sbuffer_size, lthick, - dflag, gpd->sbuffer_sflag, gpd->scolor); + dflag, gpd->scolor); } else { - gp_draw_stroke_buffer(gpd->sbuffer, gpd->sbuffer_size, lthick, dflag, gpd->sbuffer_sflag, gpd->scolor); + gp_draw_stroke_buffer(gpd->sbuffer, gpd->sbuffer_size, lthick, dflag, gpd->sbuffer_sflag, gpd->scolor, gpd->sfill); } } } } /* draw a short status message in the top-right corner */ -static void gp_draw_status_text(bGPdata *gpd, ARegion *ar) +static void gp_draw_status_text(const bGPdata *gpd, ARegion *ar) { rcti rect; - + /* Cannot draw any status text when drawing OpenGL Renders */ if (G.f & G_RENDER_OGL) return; - + /* Get bounds of region - Necessary to avoid problems with region overlap */ ED_region_visible_rect(ar, &rect); - + /* for now, this should only be used to indicate when we are in stroke editmode */ if (gpd->flag & GP_DATA_STROKE_EDITMODE) { const char *printable = IFACE_("GPencil Stroke Editing"); float printable_size[2]; - int xco, yco; - - BLF_width_and_height_default(printable, BLF_DRAW_STR_DUMMY_MAX, &printable_size[0], &printable_size[1]); - - xco = (rect.xmax - U.widget_unit) - (int)printable_size[0]; - yco = (rect.ymax - U.widget_unit); + + int font_id = BLF_default(); + + BLF_width_and_height(font_id, printable, BLF_DRAW_STR_DUMMY_MAX, &printable_size[0], &printable_size[1]); + int xco = (rect.xmax - U.widget_unit) - (int)printable_size[0]; + int yco = (rect.ymax - U.widget_unit); + /* text label */ - UI_ThemeColor(TH_TEXT_HI); + UI_FontThemeColor(font_id, TH_TEXT_HI); #ifdef WITH_INTERNATIONAL BLF_draw_default(xco, yco, 0.0f, printable, BLF_DRAW_STR_DUMMY_MAX); #else BLF_draw_default_ascii(xco, yco, 0.0f, printable, BLF_DRAW_STR_DUMMY_MAX); #endif - + /* grease pencil icon... */ // XXX: is this too intrusive? glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glEnable(GL_BLEND); - + xco -= U.widget_unit; yco -= (int)printable_size[1] / 2; UI_icon_draw(xco, yco, ICON_GREASEPENCIL); - + glDisable(GL_BLEND); } } /* draw grease-pencil datablock */ static void gp_draw_data( - bGPDbrush *brush, float alpha, bGPdata *gpd, + const bGPDbrush *brush, float alpha, bGPdata *gpd, int offsx, int offsy, int winx, int winy, int cfra, int dflag) { +#if 0 /* disable to see if really needed. re-enable or delete by Dec 2016 */ /* reset line drawing style (in case previous user didn't reset) */ setlinestyle(0); - +#endif + /* turn on smooth lines (i.e. anti-aliasing) */ glEnable(GL_LINE_SMOOTH); - + /* XXX: turn on some way of ensuring that the polygon edges get smoothed * GL_POLYGON_SMOOTH is nasty and shouldn't be used, as it ends up * creating internal white rays due to the ways it accumulates stuff */ - + /* turn on alpha-blending */ glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); glEnable(GL_BLEND); - + /* draw! */ gp_draw_data_layers(brush, alpha, gpd, offsx, offsy, winx, winy, cfra, dflag); - + /* turn off alpha blending, then smooth lines */ glDisable(GL_BLEND); // alpha blending glDisable(GL_LINE_SMOOTH); // smooth lines - + +#if 0 /* disable to see if really needed. re-enable or delete by Dec 2016 */ /* restore initial gl conditions */ glColor4f(0, 0, 0, 1); +#endif } /* if we have strokes for scenes (3d view)/clips (movie clip editor) @@ -1588,7 +1659,7 @@ static void gp_draw_data_all(Scene *scene, bGPdata *gpd, int offsx, int offsy, i } } } - + /* scene/clip data has already been drawn, only object/track data is drawn here * if gpd_source == gpd, we don't have any object/track data and we can skip */ if (gpd_source == NULL || (gpd_source && gpd_source != gpd)) { @@ -1614,28 +1685,27 @@ void ED_gpencil_draw_2dimage(const bContext *C) ScrArea *sa = CTX_wm_area(C); ARegion *ar = CTX_wm_region(C); Scene *scene = CTX_data_scene(C); - bGPdata *gpd; + int offsx, offsy, sizex, sizey; int dflag = GP_DRAWDATA_NOSTATUS; - - gpd = ED_gpencil_data_get_active(C); // XXX + + bGPdata *gpd = ED_gpencil_data_get_active(C); // XXX if (gpd == NULL) return; - + /* calculate rect */ switch (sa->spacetype) { case SPACE_IMAGE: /* image */ case SPACE_CLIP: /* clip */ { - /* just draw using standard scaling (settings here are currently ignored anyways) */ /* FIXME: the opengl poly-strokes don't draw at right thickness when done this way, so disabled */ offsx = 0; offsy = 0; sizex = ar->winx; sizey = ar->winy; - + wmOrtho2(ar->v2d.cur.xmin, ar->v2d.cur.xmax, ar->v2d.cur.ymin, ar->v2d.cur.ymax); - + dflag |= GP_DRAWDATA_ONLYV2D | GP_DRAWDATA_IEDITHACK; break; } @@ -1646,7 +1716,7 @@ void ED_gpencil_draw_2dimage(const bContext *C) offsy = 0; sizex = ar->winx; sizey = ar->winy; - + /* NOTE: I2D was used in 2.4x, but the old settings for that have been deprecated * and everything moved to standard View2d */ @@ -1658,77 +1728,74 @@ void ED_gpencil_draw_2dimage(const bContext *C) offsy = 0; sizex = ar->winx; sizey = ar->winy; - + dflag |= GP_DRAWDATA_ONLYI2D; break; } - + if (ED_screen_animation_playing(wm)) { /* don't show onionskins during animation playback/scrub (i.e. it obscures the poses) * OpenGL Renders (i.e. final output), or depth buffer (i.e. not real strokes) */ dflag |= GP_DRAWDATA_NO_ONIONS; } - - + /* draw it! */ gp_draw_data_all(scene, gpd, offsx, offsy, sizex, sizey, CFRA, dflag, sa->spacetype); } /* draw grease-pencil sketches to specified 2d-view assuming that matrices are already set correctly - * Note: this gets called twice - first time with onlyv2d=1 to draw 'canvas' strokes, - * second time with onlyv2d=0 for screen-aligned strokes */ + * Note: this gets called twice - first time with onlyv2d=true to draw 'canvas' strokes, + * second time with onlyv2d=false for screen-aligned strokes */ void ED_gpencil_draw_view2d(const bContext *C, bool onlyv2d) { wmWindowManager *wm = CTX_wm_manager(C); ScrArea *sa = CTX_wm_area(C); ARegion *ar = CTX_wm_region(C); Scene *scene = CTX_data_scene(C); - bGPdata *gpd; int dflag = 0; /* check that we have grease-pencil stuff to draw */ if (sa == NULL) return; - gpd = ED_gpencil_data_get_active(C); // XXX + bGPdata *gpd = ED_gpencil_data_get_active(C); // XXX if (gpd == NULL) return; - + /* special hack for Image Editor */ /* FIXME: the opengl poly-strokes don't draw at right thickness when done this way, so disabled */ if (ELEM(sa->spacetype, SPACE_IMAGE, SPACE_CLIP)) dflag |= GP_DRAWDATA_IEDITHACK; - + /* draw it! */ if (onlyv2d) dflag |= (GP_DRAWDATA_ONLYV2D | GP_DRAWDATA_NOSTATUS); if (ED_screen_animation_playing(wm)) dflag |= GP_DRAWDATA_NO_ONIONS; - + gp_draw_data_all(scene, gpd, 0, 0, ar->winx, ar->winy, CFRA, dflag, sa->spacetype); - + /* draw status text (if in screen/pixel-space) */ - if (onlyv2d == false) { + if (!onlyv2d) { gp_draw_status_text(gpd, ar); } } /* draw grease-pencil sketches to specified 3d-view assuming that matrices are already set correctly - * Note: this gets called twice - first time with only3d=1 to draw 3d-strokes, - * second time with only3d=0 for screen-aligned strokes */ + * Note: this gets called twice - first time with only3d=true to draw 3d-strokes, + * second time with only3d=false for screen-aligned strokes */ void ED_gpencil_draw_view3d(wmWindowManager *wm, Scene *scene, View3D *v3d, ARegion *ar, bool only3d) { - bGPdata *gpd; int dflag = 0; RegionView3D *rv3d = ar->regiondata; int offsx, offsy, winx, winy; - + /* check that we have grease-pencil stuff to draw */ - gpd = ED_gpencil_data_get_active_v3d(scene, v3d); + bGPdata *gpd = ED_gpencil_data_get_active_v3d(scene, v3d); if (gpd == NULL) return; - + /* when rendering to the offscreen buffer we don't want to * deal with the camera border, otherwise map the coords to the camera border. */ if ((rv3d->persp == RV3D_CAMOB) && !(G.f & G_RENDER_OGL)) { rctf rectf; ED_view3d_calc_camera_border(scene, ar, v3d, rv3d, &rectf, true); /* no shift */ - + offsx = iroundf(rectf.xmin); offsy = iroundf(rectf.ymin); winx = iroundf(rectf.xmax - rectf.xmin); @@ -1740,7 +1807,7 @@ void ED_gpencil_draw_view3d(wmWindowManager *wm, Scene *scene, View3D *v3d, AReg winx = ar->winx; winy = ar->winy; } - + /* set flags */ if (only3d) { /* 3D strokes/3D space: @@ -1749,28 +1816,27 @@ void ED_gpencil_draw_view3d(wmWindowManager *wm, Scene *scene, View3D *v3d, AReg */ dflag |= (GP_DRAWDATA_ONLY3D | GP_DRAWDATA_NOSTATUS); } - + if (v3d->flag2 & V3D_RENDER_OVERRIDE) { /* don't draw status text when "only render" flag is set */ dflag |= GP_DRAWDATA_NOSTATUS; } - + if ((wm == NULL) || ED_screen_animation_playing(wm)) { /* don't show onionskins during animation playback/scrub (i.e. it obscures the poses) * OpenGL Renders (i.e. final output), or depth buffer (i.e. not real strokes) */ dflag |= GP_DRAWDATA_NO_ONIONS; } - + /* draw it! */ - gp_draw_data_all(scene, gpd, offsx, offsy, winx, winy, CFRA, dflag, v3d->spacetype); - + gp_draw_data_all(scene, gpd, offsx, offsy, winx, winy, CFRA, dflag, v3d->spacetype); } void ED_gpencil_draw_ex(Scene *scene, bGPdata *gpd, int winx, int winy, const int cfra, const char spacetype) { int dflag = GP_DRAWDATA_NOSTATUS | GP_DRAWDATA_ONLYV2D; - + gp_draw_data_all(scene, gpd, 0, 0, winx, winy, cfra, dflag, spacetype); } diff --git a/source/blender/editors/gpencil/gpencil_brush.c b/source/blender/editors/gpencil/gpencil_brush.c index ec5a42c23a5..8bac80d6a3f 100644 --- a/source/blender/editors/gpencil/gpencil_brush.c +++ b/source/blender/editors/gpencil/gpencil_brush.c @@ -75,9 +75,10 @@ #include "ED_screen.h" #include "ED_view3d.h" -#include "BIF_gl.h" #include "BIF_glutil.h" +#include "GPU_immediate.h" + #include "gpencil_intern.h" /* ************************************************ */ @@ -958,28 +959,28 @@ static bool gpsculpt_brush_apply_clone(bContext *C, tGP_BrushEditData *gso) static void gp_brush_drawcursor(bContext *C, int x, int y, void *UNUSED(customdata)) { GP_EditBrush_Data *brush = gpsculpt_get_brush(CTX_data_scene(C)); - + if (brush) { - glPushMatrix(); - - glTranslatef((float)x, (float)y, 0.0f); - + VertexFormat *format = immVertexFormat(); + unsigned pos = add_attrib(format, "pos", GL_FLOAT, 2, KEEP_FLOAT); + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + glEnable(GL_LINE_SMOOTH); glEnable(GL_BLEND); - + /* Inner Ring: Light color for action of the brush */ /* TODO: toggle between add and remove? */ - glColor4ub(255, 255, 255, 200); - glutil_draw_lined_arc(0.0, M_PI * 2.0, brush->size, 40); - + immUniformColor4ub(255, 255, 255, 200); + imm_draw_lined_circle(pos, x, y, brush->size, 40); + /* Outer Ring: Dark color for contrast on light backgrounds (e.g. gray on white) */ - glColor3ub(30, 30, 30); - glutil_draw_lined_arc(0.0, M_PI * 2.0, brush->size + 1, 40); - + immUniformColor3ub(30, 30, 30); + imm_draw_lined_circle(pos, x, y, brush->size + 1, 40); + + immUnbindProgram(); + glDisable(GL_BLEND); glDisable(GL_LINE_SMOOTH); - - glPopMatrix(); } } diff --git a/source/blender/editors/gpencil/gpencil_convert.c b/source/blender/editors/gpencil/gpencil_convert.c index d0f68c4b8f3..505114869ac 100644 --- a/source/blender/editors/gpencil/gpencil_convert.c +++ b/source/blender/editors/gpencil/gpencil_convert.c @@ -1128,7 +1128,7 @@ static void gp_layer_to_curve(bContext *C, ReportList *reports, bGPdata *gpd, bG Object *ob; Curve *cu; Nurb *nu = NULL; - Base *base_orig = BASACT, *base_new = NULL; + BaseLegacy *base_orig = BASACT, *base_new = NULL; float minmax_weights[2] = {1.0f, 0.0f}; /* camera framing */ @@ -1217,7 +1217,8 @@ static void gp_layer_to_curve(bContext *C, ReportList *reports, bGPdata *gpd, bG /* set the layer and select */ base_new->lay = ob->lay = base_orig ? base_orig->lay : BKE_screen_view3d_layer_active(v3d, scene); - base_new->flag = ob->flag = base_new->flag | SELECT; + base_new->flag_legacy |= SELECT; + BKE_scene_base_flag_sync_from_base(base_new); } /* --- */ diff --git a/source/blender/editors/gpencil/gpencil_paint.c b/source/blender/editors/gpencil/gpencil_paint.c index 5879306b06c..73f393537ba 100644 --- a/source/blender/editors/gpencil/gpencil_paint.c +++ b/source/blender/editors/gpencil/gpencil_paint.c @@ -69,9 +69,10 @@ #include "ED_view3d.h" #include "ED_clip.h" -#include "BIF_gl.h" #include "BIF_glutil.h" +#include "GPU_immediate.h" + #include "RNA_access.h" #include "RNA_define.h" @@ -1546,6 +1547,7 @@ static bool gp_session_initdata(bContext *C, tGPsdata *p) bGPDpalettecolor *palcolor = p->palettecolor; bGPdata *pdata = p->gpd; copy_v4_v4(pdata->scolor, palcolor->color); + copy_v4_v4(pdata->sfill, palcolor->fill); pdata->sflag = palcolor->flag; /* lock axis */ p->lock_axis = ts->gp_sculpt.lock_axis; @@ -1840,28 +1842,28 @@ static void gp_paint_cleanup(tGPsdata *p) static void gpencil_draw_eraser(bContext *UNUSED(C), int x, int y, void *p_ptr) { tGPsdata *p = (tGPsdata *)p_ptr; - + if (p->paintmode == GP_PAINTMODE_ERASER) { - glPushMatrix(); - - glTranslatef((float)x, (float)y, 0.0f); - + VertexFormat *format = immVertexFormat(); + unsigned pos = add_attrib(format, "pos", GL_FLOAT, 2, KEEP_FLOAT); + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + glEnable(GL_LINE_SMOOTH); glEnable(GL_BLEND); - - glColor4ub(255, 100, 100, 20); - glutil_draw_filled_arc(0.0, M_PI * 2.0, p->radius, 40); - - setlinestyle(6); - - glColor4ub(255, 100, 100, 200); - glutil_draw_lined_arc(0.0, M_PI * 2.0, p->radius, 40); - + + immUniformColor4ub(255, 100, 100, 20); + imm_draw_filled_circle(pos, x, y, p->radius, 40); + + setlinestyle(6); /* TODO: handle line stipple in shader */ + + immUniformColor4ub(255, 100, 100, 200); + imm_draw_lined_circle(pos, x, y, p->radius, 40); + + immUnbindProgram(); + setlinestyle(0); glDisable(GL_BLEND); glDisable(GL_LINE_SMOOTH); - - glPopMatrix(); } } diff --git a/source/blender/editors/gpencil/gpencil_utils.c b/source/blender/editors/gpencil/gpencil_utils.c index 76e85f20c36..e3b6b748227 100644 --- a/source/blender/editors/gpencil/gpencil_utils.c +++ b/source/blender/editors/gpencil/gpencil_utils.c @@ -204,7 +204,7 @@ bGPdata *ED_gpencil_data_get_active(const bContext *C) // XXX: this should be removed... We really shouldn't duplicate logic like this! bGPdata *ED_gpencil_data_get_active_v3d(Scene *scene, View3D *v3d) { - Base *base = scene->basact; + BaseLegacy *base = scene->basact; bGPdata *gpd = NULL; /* We have to make sure active object is actually visible and selected, else we must use default scene gpd, * to be consistent with ED_gpencil_data_get_active's behavior. diff --git a/source/blender/editors/include/BIF_glutil.h b/source/blender/editors/include/BIF_glutil.h index d3d2c465d46..2dd922be372 100644 --- a/source/blender/editors/include/BIF_glutil.h +++ b/source/blender/editors/include/BIF_glutil.h @@ -38,23 +38,21 @@ struct bContext; struct ColorManagedViewSettings; struct ColorManagedDisplaySettings; -void fdrawbezier(float vec[4][3]); -void fdrawline(float x1, float y1, float x2, float y2); -void fdrawbox(float x1, float y1, float x2, float y2); -void sdrawline(int x1, int y1, int x2, int y2); -#if 0 -void sdrawtri(int x1, int y1, int x2, int y2); -void sdrawtrifill(int x1, int y1, int x2, int y2); -#endif -void sdrawbox(int x1, int y1, int x2, int y2); - -void sdrawXORline(int x0, int y0, int x1, int y1); -void sdrawXORline4(int nr, int x0, int y0, int x1, int y1); +/* Several functions defined here are being DEPRECATED for Blender 2.8 + * + * Do not use them in new code, and you are encouraged to + * convert existing code to draw without these. + * + * These will be deleted before we ship 2.8! + * - merwin + */ -void fdrawXORellipse(float xofs, float yofs, float hw, float hh); -void fdrawXORcirc(float xofs, float yofs, float rad); +void fdrawline(float x1, float y1, float x2, float y2); /* DEPRECATED */ +void fdrawbox(float x1, float y1, float x2, float y2); /* DEPRECATED */ +void sdrawline(int x1, int y1, int x2, int y2); /* DEPRECATED */ +void sdrawbox(int x1, int y1, int x2, int y2); /* DEPRECATED */ -void fdrawcheckerboard(float x1, float y1, float x2, float y2); +void fdrawcheckerboard(float x1, float y1, float x2, float y2); /* DEPRECATED */ /* OpenGL stipple defines */ extern const unsigned char stipple_halftone[128]; @@ -74,7 +72,7 @@ extern const unsigned char stipple_checker_8px[128]; * \param radius The arc radius. * \param nsegments The number of segments to use in drawing the arc. */ -void glutil_draw_lined_arc(float start, float angle, float radius, int nsegments); +void glutil_draw_lined_arc(float start, float angle, float radius, int nsegments); /* DEPRECATED */ /** * Draw a filled arc with the given \a radius, @@ -87,7 +85,72 @@ void glutil_draw_lined_arc(float start, float angle, float radius, int nsegments * \param radius The arc radius. * \param nsegments The number of segments to use in drawing the arc. */ -void glutil_draw_filled_arc(float start, float angle, float radius, int nsegments); +void glutil_draw_filled_arc(float start, float angle, float radius, int nsegments); /* DEPRECATED */ + +/** + * Draw a circle outline with the given \a radius. + * The circle is centered at \a x, \a y and drawn in the XY plane. + * + * \param pos The vertex attribute number for position. + * \param x Horizontal center. + * \param y Vertical center. + * \param radius The circle's radius. + * \param nsegments The number of segments to use in drawing (more = smoother). + */ +void imm_draw_lined_circle(unsigned pos, float x, float y, float radius, int nsegments); + +/* use this version when VertexFormat has a vec3 position */ +void imm_draw_lined_circle_3D(unsigned pos, float x, float y, float radius, int nsegments); + +/** + * Draw a filled circle with the given \a radius. + * The circle is centered at \a x, \a y and drawn in the XY plane. + * + * \param pos The vertex attribute number for position. + * \param x Horizontal center. + * \param y Vertical center. + * \param radius The circle's radius. + * \param nsegments The number of segments to use in drawing (more = smoother). + */ +void imm_draw_filled_circle(unsigned pos, float x, float y, float radius, int nsegments); + +/** +* Draw a lined box. +* +* \param pos The vertex attribute number for position. +* \param x1 left. +* \param y1 bottom. +* \param x2 right. +* \param y2 top. +*/ +void imm_draw_line_box(unsigned pos, float x1, float y1, float x2, float y2); + +/* use this version when VertexFormat has a vec3 position */ +void imm_draw_line_box_3D(unsigned pos, float x1, float y1, float x2, float y2); + +/* Draw a standard checkerboard to indicate transparent backgrounds */ +void imm_draw_checker_box(float x1, float y1, float x2, float y2); + +/** +* Pack color into 3 bytes +* +* \param x color. +*/ +void imm_cpack(unsigned int x); + +/** +* Draw a cylinder. Replacement for gluCylinder. +* _warning_ : Slow, better use it only if you no other choices. +* +* \param pos The vertex attribute number for position. +* \param nor The vertex attribute number for normal. +* \param base Specifies the radius of the cylinder at z = 0. +* \param top Specifies the radius of the cylinder at z = height. +* \param height Specifies the height of the cylinder. +* \param slices Specifies the number of subdivisions around the z axis. +* \param stacks Specifies the number of subdivisions along the z axis. +*/ +void imm_cylinder(unsigned int pos, unsigned int nor, float base, float top, float height, int slices, int stacks); /** * Returns a float value as obtained by glGetFloatv. @@ -148,6 +211,24 @@ void glaDrawPixelsTex_clipping(float x, float y, int img_w, int img_h, int forma float clip_min_x, float clip_min_y, float clip_max_x, float clip_max_y); /** + * immDrawPixelsTex - Functions like a limited glDrawPixels, but actually draws the + * image using textures, which can be tremendously faster on low-end + * cards, and also avoids problems with the raster position being + * clipped when offscreen. Pixel unpacking parameters and + * the glPixelZoom values are _not_ respected. + * + * \attention This routine makes many assumptions: the rect data + * is expected to be in RGBA byte or float format, and the + * modelview and projection matrices are assumed to define a + * 1-to-1 mapping to screen space. + */ +void immDrawPixelsTex(float x, float y, int img_w, int img_h, int format, int type, int zoomfilter, void *rect, + float xzoom, float yzoom, float color[4]); +void immDrawPixelsTex_clipping(float x, float y, int img_w, int img_h, int format, int type, int zoomfilter, void *rect, + float clip_min_x, float clip_min_y, float clip_max_x, float clip_max_y, + float xzoom, float yzoom, float color[4]); + +/** * glaDrawPixelsAuto - Switches between texture or pixel drawing using UserDef. * only RGBA * needs glaDefine2DArea to be set. @@ -161,6 +242,11 @@ void glaDrawPixelsTexScaled(float x, float y, int img_w, int img_h, int format, void glaDrawPixelsTexScaled_clipping(float x, float y, int img_w, int img_h, int format, int type, int zoomfilter, void *rect, float scaleX, float scaleY, float clip_min_x, float clip_min_y, float clip_max_x, float clip_max_y); +void immDrawPixelsTexScaled(float x, float y, int img_w, int img_h, int format, int type, int zoomfilter, void *rect, float scaleX, float scaleY, + float xzoom, float yzoom, float color[4]); +void immDrawPixelsTexScaled_clipping(float x, float y, int img_w, int img_h, int format, int type, int zoomfilter, void *rect, float scaleX, float scaleY, + float clip_min_x, float clip_min_y, float clip_max_x, float clip_max_y, + float xzoom, float yzoom, float color[4]); /* 2D Drawing Assistance */ /** Define a 2D area (viewport, scissor, matrices) for OpenGL rendering. @@ -176,12 +262,11 @@ void glaDrawPixelsTexScaled_clipping(float x, float y, int img_w, int img_h, int */ void glaDefine2DArea(struct rcti *screen_rect); -typedef struct gla2DDrawInfo gla2DDrawInfo; +#if 0 /* UNUSED */ -/* UNUSED */ -#if 0 +typedef struct gla2DDrawInfo gla2DDrawInfo; -gla2DDrawInfo *glaBegin2DDraw(struct rcti *screen_rect, struct rctf *world_rect); +gla2DDrawInfo *glaBegin2DDraw(struct rcti *screen_rect, struct rctf *world_rect); void gla2DDrawTranslatePt(gla2DDrawInfo *di, float wo_x, float wo_y, int *r_sc_x, int *r_sc_y); void gla2DDrawTranslatePtv(gla2DDrawInfo *di, float world[2], int r_screen[2]); @@ -190,7 +275,8 @@ void glaEnd2DDraw(gla2DDrawInfo *di); /** Adjust the transformation mapping of a 2d area */ void gla2DGetMap(gla2DDrawInfo *di, struct rctf *rect); void gla2DSetMap(gla2DDrawInfo *di, struct rctf *rect); -#endif + +#endif /* UNUSED */ void set_inverted_drawing(int enable); void setlinestyle(int nr); diff --git a/source/blender/editors/include/ED_armature.h b/source/blender/editors/include/ED_armature.h index 7ad61671b1b..867e85487e0 100644 --- a/source/blender/editors/include/ED_armature.h +++ b/source/blender/editors/include/ED_armature.h @@ -35,7 +35,7 @@ extern "C" { #endif struct bArmature; -struct Base; +struct BaseLegacy; struct bContext; struct Bone; struct bPoseChannel; @@ -44,6 +44,7 @@ struct ListBase; struct MeshDeformModifierData; struct DerivedMesh; struct Object; +struct Base; struct ReportList; struct Scene; struct ViewContext; @@ -82,6 +83,12 @@ typedef struct EditBone { short segments; + /* Used for display */ + float disp_mat[4][4]; /* in Armature space, rest pos matrix */ + float disp_tail_mat[4][4]; /* in Armature space, rest pos matrix */ + /* 32 == MAX_BBONE_SUBDIV */ + float disp_bbone_mat[32][4][4]; /* in Armature space, rest pos matrix */ + /* Used to store temporary data */ union { struct EditBone *ebone; @@ -130,7 +137,7 @@ void ED_armature_ebone_listbase_temp_clear(struct ListBase *lb); void ED_armature_deselect_all(struct Object *obedit); void ED_armature_deselect_all_visible(struct Object *obedit); -int ED_do_pose_selectbuffer(struct Scene *scene, struct Base *base, unsigned int *buffer, +int ED_do_pose_selectbuffer(struct Scene *scene, struct BaseLegacy *base, unsigned int *buffer, short hits, bool extend, bool deselect, bool toggle, bool do_nearest); bool ED_armature_select_pick(struct bContext *C, const int mval[2], bool extend, bool deselect, bool toggle); int join_armature_exec(struct bContext *C, struct wmOperator *op); diff --git a/source/blender/editors/include/ED_keyframes_draw.h b/source/blender/editors/include/ED_keyframes_draw.h index c478a8b17e5..8eef016a846 100644 --- a/source/blender/editors/include/ED_keyframes_draw.h +++ b/source/blender/editors/include/ED_keyframes_draw.h @@ -108,8 +108,10 @@ typedef enum eKeyframeShapeDrawOpts { KEYFRAME_SHAPE_BOTH } eKeyframeShapeDrawOpts; -/* draw simple diamond-shape keyframe (with OpenGL) */ -void draw_keyframe_shape(float x, float y, float xscale, float hsize, short sel, short key_type, short mode, float alpha); +/* draw simple diamond-shape keyframe */ +/* caller should set up vertex format, bind GPU_SHADER_KEYFRAME_DIAMOND, immBegin(PRIM_POINTS, n), then call this n times */ +void draw_keyframe_shape(float x, float y, float size, bool sel, short key_type, short mode, float alpha, + unsigned int pos_id, unsigned int size_id, unsigned int color_id, unsigned int outline_color_id); /* ******************************* Methods ****************************** */ diff --git a/source/blender/editors/include/ED_node.h b/source/blender/editors/include/ED_node.h index f7b9d6b4f9e..b4cf96f27bf 100644 --- a/source/blender/editors/include/ED_node.h +++ b/source/blender/editors/include/ED_node.h @@ -75,7 +75,7 @@ void ED_init_custom_node_socket_type(struct bNodeSocketType *stype); void ED_init_standard_node_socket_type(struct bNodeSocketType *stype); void ED_init_node_socket_type_virtual(struct bNodeSocketType *stype); void ED_node_sample_set(const float col[4]); -void ED_node_draw_snap(struct View2D *v2d, const float cent[2], float size, NodeBorder border); +void ED_node_draw_snap(struct View2D *v2d, const float cent[2], float size, NodeBorder border, unsigned pos); /* node_draw.c */ void ED_node_tree_update(const struct bContext *C); diff --git a/source/blender/editors/include/ED_object.h b/source/blender/editors/include/ED_object.h index 04ff5692717..f621ee7989d 100644 --- a/source/blender/editors/include/ED_object.h +++ b/source/blender/editors/include/ED_object.h @@ -35,14 +35,16 @@ extern "C" { #endif -struct Base; +struct BaseLegacy; struct EnumPropertyItem; struct ID; struct Main; struct ModifierData; struct Object; +struct Base; struct ReportList; struct Scene; +struct SceneLayer; struct bConstraint; struct bContext; struct bPoseChannel; @@ -89,7 +91,6 @@ bool ED_object_parent_set(struct ReportList *reports, struct Main *bmain, struct struct Object *par, int partype, const bool xmirror, const bool keep_transform, const int vert_par[3]); void ED_object_parent_clear(struct Object *ob, const int type); -struct Base *ED_object_scene_link(struct Scene *scene, struct Object *ob); void ED_keymap_proportional_cycle(struct wmKeyConfig *keyconf, struct wmKeyMap *keymap); void ED_keymap_proportional_obmode(struct wmKeyConfig *keyconf, struct wmKeyMap *keymap); @@ -98,14 +99,20 @@ void ED_keymap_proportional_editmode(struct wmKeyConfig *keyconf, struct wmKeyMa const bool do_connected); /* send your own notifier for select! */ -void ED_base_object_select(struct Base *base, short mode); +void ED_base_object_select(struct BaseLegacy *base, short mode); /* includes notifier */ -void ED_base_object_activate(struct bContext *C, struct Base *base); +void ED_base_object_activate(struct bContext *C, struct BaseLegacy *base); + +void ED_object_base_select(struct Base *base, short mode); +void ED_object_base_activate(struct bContext *C, struct Base *base); -void ED_base_object_free_and_unlink(struct Main *bmain, struct Scene *scene, struct Base *base); +void ED_base_object_free_and_unlink(struct Main *bmain, struct Scene *scene, struct Object *ob); + +void ED_base_object_sync_from_base(struct BaseLegacy *base, struct Object *ob); +void ED_base_object_sync_from_object(struct BaseLegacy *base, struct Object *ob); /* single object duplicate, if (dupflag == 0), fully linked, else it uses the flags given */ -struct Base *ED_object_add_duplicate(struct Main *bmain, struct Scene *scene, struct Base *base, int dupflag); +struct Base *ED_object_add_duplicate(struct Main *bmain, struct Scene *scene, struct SceneLayer *sl, struct Base *base, int dupflag); void ED_object_parent(struct Object *ob, struct Object *parent, const int type, const char *substr); @@ -191,7 +198,7 @@ void ED_object_modifier_clear(struct Main *bmain, struct Object *ob); int ED_object_modifier_move_down(struct ReportList *reports, struct Object *ob, struct ModifierData *md); int ED_object_modifier_move_up(struct ReportList *reports, struct Object *ob, struct ModifierData *md); int ED_object_modifier_convert(struct ReportList *reports, struct Main *bmain, struct Scene *scene, - struct Object *ob, struct ModifierData *md); + struct SceneLayer *sl, struct Object *ob, struct ModifierData *md); int ED_object_modifier_apply(struct ReportList *reports, struct Scene *scene, struct Object *ob, struct ModifierData *md, int mode); int ED_object_modifier_copy(struct ReportList *reports, struct Object *ob, struct ModifierData *md); diff --git a/source/blender/editors/include/ED_screen.h b/source/blender/editors/include/ED_screen.h index ec09add56b8..f5f66a07aea 100644 --- a/source/blender/editors/include/ED_screen.h +++ b/source/blender/editors/include/ED_screen.h @@ -36,6 +36,8 @@ #include "DNA_view2d_types.h" #include "DNA_view3d_types.h" +#include "BLI_compiler_attrs.h" + struct wmWindowManager; struct wmWindow; struct wmNotifier; @@ -47,6 +49,7 @@ struct bScreen; struct ARegion; struct uiBlock; struct rcti; +struct Main; /* regions */ void ED_region_do_listen(struct bScreen *sc, struct ScrArea *sa, struct ARegion *ar, struct wmNotifier *note); @@ -118,6 +121,7 @@ void ED_screen_full_restore(struct bContext *C, ScrArea *sa); struct ScrArea *ED_screen_state_toggle(struct bContext *C, struct wmWindow *win, struct ScrArea *sa, const short state); void ED_screens_header_tools_menu_create(struct bContext *C, struct uiLayout *layout, void *arg); bool ED_screen_stereo3d_required(struct bScreen *screen); +void ED_screen_preview_render(const struct bScreen *screen, int size_x, int size_y, unsigned int *r_rect) ATTR_NONNULL(); /* anim */ void ED_update_for_newframe(struct Main *bmain, struct Scene *scene, int mute); diff --git a/source/blender/editors/include/ED_transform.h b/source/blender/editors/include/ED_transform.h index ebd2a3dcb7a..898eecd3e42 100644 --- a/source/blender/editors/include/ED_transform.h +++ b/source/blender/editors/include/ED_transform.h @@ -109,7 +109,7 @@ enum TfmMode { bool calculateTransformCenter(struct bContext *C, int centerMode, float cent3d[3], float cent2d[2]); struct TransInfo; -struct Base; +struct BaseLegacy; struct Scene; struct Object; struct wmOperator; diff --git a/source/blender/editors/include/ED_uvedit.h b/source/blender/editors/include/ED_uvedit.h index 535683823bf..8d68fba84f5 100644 --- a/source/blender/editors/include/ED_uvedit.h +++ b/source/blender/editors/include/ED_uvedit.h @@ -41,6 +41,7 @@ struct MTexPoly; struct Main; struct Object; struct Scene; +struct SceneLayer; struct SpaceImage; struct bNode; struct wmKeyConfig; @@ -109,7 +110,7 @@ void ED_unwrap_lscm(struct Scene *scene, struct Object *obedit, const short sel) /* uvedit_draw.c */ void ED_image_draw_cursor(struct ARegion *ar, const float cursor[2]); -void ED_uvedit_draw_main(struct SpaceImage *sima, struct ARegion *ar, struct Scene *scene, struct Object *obedit, struct Object *obact); +void ED_uvedit_draw_main(struct SpaceImage *sima, struct ARegion *ar, struct Scene *scene, struct SceneLayer *sl, struct Object *obedit, struct Object *obact); /* uvedit_buttons.c */ void ED_uvedit_buttons_register(struct ARegionType *art); diff --git a/source/blender/editors/include/ED_view3d.h b/source/blender/editors/include/ED_view3d.h index 79176d9e9cf..cc83b97fc00 100644 --- a/source/blender/editors/include/ED_view3d.h +++ b/source/blender/editors/include/ED_view3d.h @@ -37,7 +37,7 @@ struct BMEdge; struct BMFace; struct BMVert; struct BPoint; -struct Base; +struct BaseLegacy; struct BezTriple; struct BoundBox; struct EditBone; @@ -49,6 +49,7 @@ struct Nurb; struct Object; struct RegionView3D; struct Scene; +struct SceneLayer; struct ScrArea; struct View3D; struct ViewContext; @@ -70,6 +71,7 @@ enum eGPUFXFlags; /* for derivedmesh drawing callbacks, for view3d_select, .... */ typedef struct ViewContext { struct Scene *scene; + struct SceneLayer *sl; struct Object *obact; struct Object *obedit; struct ARegion *ar; @@ -187,7 +189,7 @@ void pose_foreachScreenBone( void ED_view3d_project_float_v2_m4(const struct ARegion *ar, const float co[3], float r_co[2], float mat[4][4]); void ED_view3d_project_float_v3_m4(const struct ARegion *ar, const float co[3], float r_co[3], float mat[4][4]); -eV3DProjStatus ED_view3d_project_base(const struct ARegion *ar, struct Base *base); +eV3DProjStatus ED_view3d_project_base(const struct ARegion *ar, struct BaseLegacy *base); /* *** short *** */ eV3DProjStatus ED_view3d_project_short_ex(const struct ARegion *ar, float perspmat[4][4], const bool is_local, @@ -277,6 +279,7 @@ float ED_view3d_radius_to_dist( const float radius); void drawcircball(int mode, const float cent[3], float rad, const float tmat[4][4]); +void imm_drawcircball(const float cent[3], float rad, const float tmat[4][4], unsigned pos); /* backbuffer select and draw support */ void ED_view3d_backbuf_validate(struct ViewContext *vc); @@ -352,7 +355,7 @@ struct ImBuf *ED_view3d_draw_offscreen_imbuf_simple( int alpha_mode, int samples, bool full_samples, const char *viewname, struct GPUFX *fx, struct GPUOffScreen *ofs, char err_out[256]); -struct Base *ED_view3d_give_base_under_cursor(struct bContext *C, const int mval[2]); +struct BaseLegacy *ED_view3d_give_base_under_cursor(struct bContext *C, const int mval[2]); void ED_view3d_quadview_update(struct ScrArea *sa, struct ARegion *ar, bool do_clip); void ED_view3d_update_viewmat(struct Scene *scene, struct View3D *v3d, struct ARegion *ar, float viewmat[4][4], float winmat[4][4]); bool ED_view3d_quat_from_axis_view(const char view, float quat[4]); diff --git a/source/blender/editors/include/UI_interface.h b/source/blender/editors/include/UI_interface.h index 9fbce7dd203..69d15859407 100644 --- a/source/blender/editors/include/UI_interface.h +++ b/source/blender/editors/include/UI_interface.h @@ -308,18 +308,20 @@ typedef enum { * Functions to draw various shapes, taking theme settings into account. * Used for code that draws its own UI style elements. */ -void UI_draw_roundbox(float minx, float miny, float maxx, float maxy, float rad); +void UI_draw_roundbox(float minx, float miny, float maxx, float maxy, float rad, const float color[4]); void UI_draw_roundbox_corner_set(int type); int UI_draw_roundbox_corner_get(void); -void UI_draw_roundbox_unfilled(float minx, float miny, float maxx, float maxy, float rad); +void UI_draw_roundbox_unfilled(float minx, float miny, float maxx, float maxy, float rad, const float color[4]); void UI_draw_box_shadow(unsigned char alpha, float minx, float miny, float maxx, float maxy); -void UI_draw_roundbox_gl_mode(int mode, float minx, float miny, float maxx, float maxy, float rad); -void UI_draw_roundbox_shade_x(int mode, float minx, float miny, float maxx, float maxy, float rad, float shadetop, float shadedown); -void UI_draw_roundbox_shade_y(int mode, float minx, float miny, float maxx, float maxy, float rad, float shadeLeft, float shadeRight); -void UI_draw_text_underline(int pos_x, int pos_y, int len, int height); +void UI_draw_roundbox_gl_mode_3ubAlpha(int mode, float minx, float miny, float maxx, float maxy, float rad, unsigned char col[3], unsigned char alpha); +void UI_draw_roundbox_gl_mode_3fvAlpha(int mode, float minx, float miny, float maxx, float maxy, float rad, float col[3], float alpha); +void UI_draw_roundbox_gl_mode(int mode, float minx, float miny, float maxx, float maxy, float rad, float col[4]); +void UI_draw_roundbox_shade_x(int mode, float minx, float miny, float maxx, float maxy, float rad, float shadetop, float shadedown, const float col[4]); +void UI_draw_roundbox_shade_y(int mode, float minx, float miny, float maxx, float maxy, float rad, float shadeleft, float shaderight, const float col[4]); +void UI_draw_text_underline(int pos_x, int pos_y, int len, int height, const float color[4]); void UI_draw_safe_areas( - float x1, float x2, float y1, float y2, + unsigned pos, float x1, float x2, float y1, float y2, const float title_aspect[2], const float action_aspect[2]); /* state for scrolldrawing */ @@ -1042,20 +1044,22 @@ void UI_context_active_but_prop_get_templateID( /* Styled text draw */ void UI_fontstyle_set(const struct uiFontStyle *fs); -void UI_fontstyle_draw_ex( - const struct uiFontStyle *fs, const struct rcti *rect, const char *str, - size_t len, float *r_xofs, float *r_yofs); -void UI_fontstyle_draw(const struct uiFontStyle *fs, const struct rcti *rect, const char *str); -void UI_fontstyle_draw_rotated(const struct uiFontStyle *fs, const struct rcti *rect, const char *str); -void UI_fontstyle_draw_simple(const struct uiFontStyle *fs, float x, float y, const char *str); +void UI_fontstyle_draw_ex(const struct uiFontStyle *fs, const struct rcti *rect, const char *str, + const unsigned char col[4], size_t len, float *r_xofs, float *r_yofs); +void UI_fontstyle_draw(const struct uiFontStyle *fs, const struct rcti *rect, const char *str, + const unsigned char col[4]); +void UI_fontstyle_draw_rotated(const struct uiFontStyle *fs, const struct rcti *rect, const char *str, + const unsigned char col[4]); +void UI_fontstyle_draw_simple(const struct uiFontStyle *fs, float x, float y, const char *str, + const unsigned char col[4]); void UI_fontstyle_draw_simple_backdrop( const struct uiFontStyle *fs, float x, float y, const char *str, - const unsigned char fg[4], const unsigned char bg[4]); + const float col_fg[4], const float col_bg[4]); int UI_fontstyle_string_width(const struct uiFontStyle *fs, const char *str); int UI_fontstyle_height_max(const struct uiFontStyle *fs); -void UI_draw_icon_tri(float x, float y, char dir); +void UI_draw_icon_tri(float x, float y, char dir, const float[4]); struct uiStyle *UI_style_get(void); /* use for fonts etc */ struct uiStyle *UI_style_get_dpi(void); /* DPI scaled settings for drawing */ diff --git a/source/blender/editors/include/UI_interface_icons.h b/source/blender/editors/include/UI_interface_icons.h index 945ac1b6db9..cee68ed361c 100644 --- a/source/blender/editors/include/UI_interface_icons.h +++ b/source/blender/editors/include/UI_interface_icons.h @@ -66,6 +66,7 @@ void UI_id_icon_render( int UI_preview_render_size(enum eIconSizes size); void UI_icon_draw(float x, float y, int icon_id); +void UI_icon_draw_alpha(float x, float y, int icon_id, float alpha); void UI_icon_draw_preview(float x, float y, int icon_id); void UI_icon_draw_preview_aspect(float x, float y, int icon_id, float aspect); void UI_icon_draw_preview_aspect_size(float x, float y, int icon_id, float aspect, float alpha, int size); diff --git a/source/blender/editors/include/UI_resources.h b/source/blender/editors/include/UI_resources.h index f8a5f30a596..2fc76ae9563 100644 --- a/source/blender/editors/include/UI_resources.h +++ b/source/blender/editors/include/UI_resources.h @@ -320,13 +320,13 @@ struct bThemeState { void UI_ThemeColor(int colorid); // sets the color plus alpha -void UI_ThemeColor4(int colorid); +void UI_ThemeColor4(int colorid); // sets color plus offset for shade -void UI_ThemeColorShade(int colorid, int offset); +void UI_ThemeColorShade(int colorid, int offset); // sets color plus offset for alpha -void UI_ThemeColorShadeAlpha(int colorid, int coloffset, int alphaoffset); +void UI_ThemeColorShadeAlpha(int colorid, int coloffset, int alphaoffset); // sets color, which is blend between two theme colors void UI_ThemeColorBlend(int colorid1, int colorid2, float fac); @@ -347,11 +347,22 @@ void UI_GetThemeColorBlend3ubv(int colorid1, int colorid2, float fac, unsigne // get the color, range 0.0-1.0, complete with shading offset void UI_GetThemeColorShade3fv(int colorid, int offset, float col[3]); void UI_GetThemeColorShade3ubv(int colorid, int offset, unsigned char col[3]); +void UI_GetThemeColorShade4ubv(int colorid, int offset, unsigned char col[4]); + +// get three color values, range 0-255, complete with shading offset for the RGB components and blending +void UI_GetThemeColorBlendShade3ubv(int colorid1, int colorid2, float fac, int offset, unsigned char col[3]); // get four color values, scaled to 0.0-1.0 range void UI_GetThemeColor4fv(int colorid, float col[4]); // get four color values, range 0.0-1.0, complete with shading offset for the RGB components void UI_GetThemeColorShade4fv(int colorid, int offset, float col[4]); +void UI_GetThemeColorShadeAlpha4fv(int colorid, int coloffset, int alphaoffset, float col[4]); + +// get four colour values ranged between 0 and 255; includes the alpha channel +void UI_GetThemeColorShadeAlpha4ubv(int colorid, int coloffset, int alphaoffset, unsigned char col[4]); + +// get four color values, range 0.0-1.0, complete with shading offset for the RGB components and blending +void UI_GetThemeColorBlendShade4fv(int colorid1, int colorid2, float fac, int offset, float col[4]); // get the 3 or 4 byte values void UI_GetThemeColor3ubv(int colorid, unsigned char col[3]); @@ -369,6 +380,10 @@ void UI_GetColorPtrShade3ubv(const unsigned char cp1[3], unsigned char col[3] // get a 3 byte color, blended and shaded between two other char color pointers void UI_GetColorPtrBlendShade3ubv(const unsigned char cp1[3], const unsigned char cp2[3], unsigned char col[3], float fac, int offset); +// sets the font color +// (for anything fancy use UI_GetThemeColor[Fancy] then BLF_color) +void UI_FontThemeColor(int fontid, int colorid); + // clear the openGL ClearColor using the input colorid void UI_ThemeClearColor(int colorid); diff --git a/source/blender/editors/interface/interface.c b/source/blender/editors/interface/interface.c index 682db20af55..fe9b3054ea7 100644 --- a/source/blender/editors/interface/interface.c +++ b/source/blender/editors/interface/interface.c @@ -499,6 +499,7 @@ static int ui_but_calc_float_precision(uiBut *but, double value) static void ui_draw_linkline(uiLinkLine *line, int highlightActiveLines, int dashInactiveLines) { rcti rect; + float color[4] = {1.0f}; if (line->from == NULL || line->to == NULL) return; @@ -508,15 +509,15 @@ static void ui_draw_linkline(uiLinkLine *line, int highlightActiveLines, int das rect.ymax = BLI_rctf_cent_y(&line->to->rect); if (dashInactiveLines) - UI_ThemeColor(TH_GRID); + UI_GetThemeColor4fv(TH_GRID, color); else if (line->flag & UI_SELECT) - glColor3ub(100, 100, 100); + rgba_float_args_set_ch(color, 100, 100, 100, 255); else if (highlightActiveLines && ((line->from->flag & UI_ACTIVE) || (line->to->flag & UI_ACTIVE))) - UI_ThemeColor(TH_TEXT_HI); + UI_GetThemeColor4fv(TH_TEXT_HI, color); else - glColor3ub(0, 0, 0); + rgba_float_args_set_ch(color, 0, 0, 0, 255); - ui_draw_link_bezier(&rect); + ui_draw_link_bezier(&rect, color); } static void ui_draw_links(uiBlock *block) diff --git a/source/blender/editors/interface/interface_draw.c b/source/blender/editors/interface/interface_draw.c index 01ea1e953fa..c96e5c73166 100644 --- a/source/blender/editors/interface/interface_draw.c +++ b/source/blender/editors/interface/interface_draw.c @@ -57,6 +57,9 @@ #include "GPU_draw.h" #include "GPU_basic_shader.h" +#include "GPU_batch.h" +#include "GPU_immediate.h" +#include "GPU_matrix.h" #include "UI_interface.h" @@ -79,325 +82,387 @@ int UI_draw_roundbox_corner_get(void) return roundboxtype; } -void UI_draw_roundbox_gl_mode(int mode, float minx, float miny, float maxx, float maxy, float rad) +void UI_draw_roundbox_gl_mode_3ubAlpha(int mode, float minx, float miny, float maxx, float maxy, float rad, unsigned char col[3], unsigned char alpha) +{ + float colv[4]; + colv[0] = ((float)col[0]) / 255; + colv[1] = ((float)col[1]) / 255; + colv[2] = ((float)col[2]) / 255; + colv[3] = ((float)alpha) / 255; + UI_draw_roundbox_gl_mode(mode, minx, miny, maxx, maxy, rad, colv); +} + +void UI_draw_roundbox_gl_mode_3fvAlpha(int mode, float minx, float miny, float maxx, float maxy, float rad, float col[3], float alpha) +{ + float colv[4]; + colv[0] = col[0]; + colv[1] = col[1]; + colv[2] = col[2]; + colv[3] = alpha; + UI_draw_roundbox_gl_mode(mode, minx, miny, maxx, maxy, rad, colv); +} + +void UI_draw_roundbox_gl_mode(int mode, float minx, float miny, float maxx, float maxy, float rad, float col[4]) { float vec[7][2] = {{0.195, 0.02}, {0.383, 0.067}, {0.55, 0.169}, {0.707, 0.293}, {0.831, 0.45}, {0.924, 0.617}, {0.98, 0.805}}; int a; + VertexFormat *format = immVertexFormat(); + unsigned pos = add_attrib(format, "pos", GL_FLOAT, 2, KEEP_FLOAT); + /* mult */ for (a = 0; a < 7; a++) { mul_v2_fl(vec[a], rad); } - glBegin(mode); + BLI_assert(mode != GL_POLYGON); + + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + immUniformColor4fv(col); + immBeginAtMost(mode, 36); /* start with corner right-bottom */ if (roundboxtype & UI_CNR_BOTTOM_RIGHT) { - glVertex2f(maxx - rad, miny); + immVertex2f(pos, maxx - rad, miny); for (a = 0; a < 7; a++) { - glVertex2f(maxx - rad + vec[a][0], miny + vec[a][1]); + immVertex2f(pos, maxx - rad + vec[a][0], miny + vec[a][1]); } - glVertex2f(maxx, miny + rad); + immVertex2f(pos, maxx, miny + rad); } else { - glVertex2f(maxx, miny); + immVertex2f(pos, maxx, miny); } /* corner right-top */ if (roundboxtype & UI_CNR_TOP_RIGHT) { - glVertex2f(maxx, maxy - rad); + immVertex2f(pos, maxx, maxy - rad); for (a = 0; a < 7; a++) { - glVertex2f(maxx - vec[a][1], maxy - rad + vec[a][0]); + immVertex2f(pos, maxx - vec[a][1], maxy - rad + vec[a][0]); } - glVertex2f(maxx - rad, maxy); + immVertex2f(pos, maxx - rad, maxy); } else { - glVertex2f(maxx, maxy); + immVertex2f(pos, maxx, maxy); } /* corner left-top */ if (roundboxtype & UI_CNR_TOP_LEFT) { - glVertex2f(minx + rad, maxy); + immVertex2f(pos, minx + rad, maxy); for (a = 0; a < 7; a++) { - glVertex2f(minx + rad - vec[a][0], maxy - vec[a][1]); + immVertex2f(pos, minx + rad - vec[a][0], maxy - vec[a][1]); } - glVertex2f(minx, maxy - rad); + immVertex2f(pos, minx, maxy - rad); } else { - glVertex2f(minx, maxy); + immVertex2f(pos, minx, maxy); } /* corner left-bottom */ if (roundboxtype & UI_CNR_BOTTOM_LEFT) { - glVertex2f(minx, miny + rad); + immVertex2f(pos, minx, miny + rad); for (a = 0; a < 7; a++) { - glVertex2f(minx + vec[a][1], miny + rad - vec[a][0]); + immVertex2f(pos, minx + vec[a][1], miny + rad - vec[a][0]); } - glVertex2f(minx + rad, miny); + immVertex2f(pos, minx + rad, miny); } else { - glVertex2f(minx, miny); + immVertex2f(pos, minx, miny); } - glEnd(); + immEnd(); + immUnbindProgram(); } -static void round_box_shade_col(const float col1[3], float const col2[3], const float fac) +static void round_box_shade_col(unsigned attrib, const float col1[3], float const col2[3], const float fac) { - float col[3] = { + float col[4] = { fac * col1[0] + (1.0f - fac) * col2[0], fac * col1[1] + (1.0f - fac) * col2[1], - fac * col1[2] + (1.0f - fac) * col2[2] + fac * col1[2] + (1.0f - fac) * col2[2], + 1.0f }; - glColor3fv(col); + immAttrib4fv(attrib, col); } /* linear horizontal shade within button or in outline */ /* view2d scrollers use it */ void UI_draw_roundbox_shade_x( int mode, float minx, float miny, float maxx, float maxy, - float rad, float shadetop, float shadedown) + float rad, float shadetop, float shadedown, const float col[4]) { float vec[7][2] = {{0.195, 0.02}, {0.383, 0.067}, {0.55, 0.169}, {0.707, 0.293}, {0.831, 0.45}, {0.924, 0.617}, {0.98, 0.805}}; const float div = maxy - miny; const float idiv = 1.0f / div; - float coltop[3], coldown[3], color[4]; + float coltop[3], coldown[3]; + int vert_count = 0; int a; - + + VertexFormat *format = immVertexFormat(); + unsigned pos = add_attrib(format, "pos", GL_FLOAT, 2, KEEP_FLOAT); + unsigned color = add_attrib(format, "color", GL_FLOAT, 4, KEEP_FLOAT); + + immBindBuiltinProgram(GPU_SHADER_2D_SMOOTH_COLOR); + /* mult */ for (a = 0; a < 7; a++) { mul_v2_fl(vec[a], rad); } - /* get current color, needs to be outside of glBegin/End */ - glGetFloatv(GL_CURRENT_COLOR, color); + + BLI_assert(mode != GL_POLYGON); /* 'shade' defines strength of shading */ - coltop[0] = min_ff(1.0f, color[0] + shadetop); - coltop[1] = min_ff(1.0f, color[1] + shadetop); - coltop[2] = min_ff(1.0f, color[2] + shadetop); - coldown[0] = max_ff(0.0f, color[0] + shadedown); - coldown[1] = max_ff(0.0f, color[1] + shadedown); - coldown[2] = max_ff(0.0f, color[2] + shadedown); + coltop[0] = min_ff(1.0f, col[0] + shadetop); + coltop[1] = min_ff(1.0f, col[1] + shadetop); + coltop[2] = min_ff(1.0f, col[2] + shadetop); + coldown[0] = max_ff(0.0f, col[0] + shadedown); + coldown[1] = max_ff(0.0f, col[1] + shadedown); + coldown[2] = max_ff(0.0f, col[2] + shadedown); + + vert_count += (roundboxtype & UI_CNR_BOTTOM_RIGHT) ? 9 : 1; + vert_count += (roundboxtype & UI_CNR_TOP_RIGHT) ? 9 : 1; + vert_count += (roundboxtype & UI_CNR_TOP_LEFT) ? 9 : 1; + vert_count += (roundboxtype & UI_CNR_BOTTOM_LEFT) ? 9 : 1; - glBegin(mode); + immBegin(mode, vert_count); /* start with corner right-bottom */ if (roundboxtype & UI_CNR_BOTTOM_RIGHT) { - round_box_shade_col(coltop, coldown, 0.0); - glVertex2f(maxx - rad, miny); + round_box_shade_col(color, coltop, coldown, 0.0); + immVertex2f(pos, maxx - rad, miny); for (a = 0; a < 7; a++) { - round_box_shade_col(coltop, coldown, vec[a][1] * idiv); - glVertex2f(maxx - rad + vec[a][0], miny + vec[a][1]); + round_box_shade_col(color, coltop, coldown, vec[a][1] * idiv); + immVertex2f(pos, maxx - rad + vec[a][0], miny + vec[a][1]); } - round_box_shade_col(coltop, coldown, rad * idiv); - glVertex2f(maxx, miny + rad); + round_box_shade_col(color, coltop, coldown, rad * idiv); + immVertex2f(pos, maxx, miny + rad); } else { - round_box_shade_col(coltop, coldown, 0.0); - glVertex2f(maxx, miny); + round_box_shade_col(color, coltop, coldown, 0.0); + immVertex2f(pos, maxx, miny); } /* corner right-top */ if (roundboxtype & UI_CNR_TOP_RIGHT) { - round_box_shade_col(coltop, coldown, (div - rad) * idiv); - glVertex2f(maxx, maxy - rad); + round_box_shade_col(color, coltop, coldown, (div - rad) * idiv); + immVertex2f(pos, maxx, maxy - rad); for (a = 0; a < 7; a++) { - round_box_shade_col(coltop, coldown, (div - rad + vec[a][1]) * idiv); - glVertex2f(maxx - vec[a][1], maxy - rad + vec[a][0]); + round_box_shade_col(color, coltop, coldown, (div - rad + vec[a][1]) * idiv); + immVertex2f(pos, maxx - vec[a][1], maxy - rad + vec[a][0]); } - round_box_shade_col(coltop, coldown, 1.0); - glVertex2f(maxx - rad, maxy); + round_box_shade_col(color, coltop, coldown, 1.0); + immVertex2f(pos, maxx - rad, maxy); } else { - round_box_shade_col(coltop, coldown, 1.0); - glVertex2f(maxx, maxy); + round_box_shade_col(color, coltop, coldown, 1.0); + immVertex2f(pos, maxx, maxy); } /* corner left-top */ if (roundboxtype & UI_CNR_TOP_LEFT) { - round_box_shade_col(coltop, coldown, 1.0); - glVertex2f(minx + rad, maxy); + round_box_shade_col(color, coltop, coldown, 1.0); + immVertex2f(pos, minx + rad, maxy); for (a = 0; a < 7; a++) { - round_box_shade_col(coltop, coldown, (div - vec[a][1]) * idiv); - glVertex2f(minx + rad - vec[a][0], maxy - vec[a][1]); + round_box_shade_col(color, coltop, coldown, (div - vec[a][1]) * idiv); + immVertex2f(pos, minx + rad - vec[a][0], maxy - vec[a][1]); } - round_box_shade_col(coltop, coldown, (div - rad) * idiv); - glVertex2f(minx, maxy - rad); + round_box_shade_col(color, coltop, coldown, (div - rad) * idiv); + immVertex2f(pos, minx, maxy - rad); } else { - round_box_shade_col(coltop, coldown, 1.0); - glVertex2f(minx, maxy); + round_box_shade_col(color, coltop, coldown, 1.0); + immVertex2f(pos, minx, maxy); } /* corner left-bottom */ if (roundboxtype & UI_CNR_BOTTOM_LEFT) { - round_box_shade_col(coltop, coldown, rad * idiv); - glVertex2f(minx, miny + rad); + round_box_shade_col(color, coltop, coldown, rad * idiv); + immVertex2f(pos, minx, miny + rad); for (a = 0; a < 7; a++) { - round_box_shade_col(coltop, coldown, (rad - vec[a][1]) * idiv); - glVertex2f(minx + vec[a][1], miny + rad - vec[a][0]); + round_box_shade_col(color, coltop, coldown, (rad - vec[a][1]) * idiv); + immVertex2f(pos, minx + vec[a][1], miny + rad - vec[a][0]); } - round_box_shade_col(coltop, coldown, 0.0); - glVertex2f(minx + rad, miny); + round_box_shade_col(color, coltop, coldown, 0.0); + immVertex2f(pos, minx + rad, miny); } else { - round_box_shade_col(coltop, coldown, 0.0); - glVertex2f(minx, miny); + round_box_shade_col(color, coltop, coldown, 0.0); + immVertex2f(pos, minx, miny); } - - glEnd(); + + immEnd(); + immUnbindProgram(); } /* linear vertical shade within button or in outline */ /* view2d scrollers use it */ void UI_draw_roundbox_shade_y( int mode, float minx, float miny, float maxx, float maxy, - float rad, float shadeLeft, float shadeRight) + float rad, float shadeleft, float shaderight, const float col[4]) { float vec[7][2] = {{0.195, 0.02}, {0.383, 0.067}, {0.55, 0.169}, {0.707, 0.293}, {0.831, 0.45}, {0.924, 0.617}, {0.98, 0.805}}; const float div = maxx - minx; const float idiv = 1.0f / div; - float colLeft[3], colRight[3], color[4]; + float colLeft[3], colRight[3]; + int vert_count = 0; int a; /* mult */ for (a = 0; a < 7; a++) { mul_v2_fl(vec[a], rad); } - /* get current color, needs to be outside of glBegin/End */ - glGetFloatv(GL_CURRENT_COLOR, color); + + BLI_assert(mode != GL_POLYGON); + + VertexFormat *format = immVertexFormat(); + unsigned pos = add_attrib(format, "pos", GL_FLOAT, 2, KEEP_FLOAT); + unsigned color = add_attrib(format, "color", GL_FLOAT, 4, KEEP_FLOAT); + + immBindBuiltinProgram(GPU_SHADER_2D_SMOOTH_COLOR); /* 'shade' defines strength of shading */ - colLeft[0] = min_ff(1.0f, color[0] + shadeLeft); - colLeft[1] = min_ff(1.0f, color[1] + shadeLeft); - colLeft[2] = min_ff(1.0f, color[2] + shadeLeft); - colRight[0] = max_ff(0.0f, color[0] + shadeRight); - colRight[1] = max_ff(0.0f, color[1] + shadeRight); - colRight[2] = max_ff(0.0f, color[2] + shadeRight); + colLeft[0] = min_ff(1.0f, col[0] + shadeleft); + colLeft[1] = min_ff(1.0f, col[1] + shadeleft); + colLeft[2] = min_ff(1.0f, col[2] + shadeleft); + colRight[0] = max_ff(0.0f, col[0] + shaderight); + colRight[1] = max_ff(0.0f, col[1] + shaderight); + colRight[2] = max_ff(0.0f, col[2] + shaderight); + - glBegin(mode); + vert_count += (roundboxtype & UI_CNR_BOTTOM_RIGHT) ? 9 : 1; + vert_count += (roundboxtype & UI_CNR_TOP_RIGHT) ? 9 : 1; + vert_count += (roundboxtype & UI_CNR_TOP_LEFT) ? 9 : 1; + vert_count += (roundboxtype & UI_CNR_BOTTOM_LEFT) ? 9 : 1; + + immBegin(mode, vert_count); /* start with corner right-bottom */ if (roundboxtype & UI_CNR_BOTTOM_RIGHT) { - round_box_shade_col(colLeft, colRight, 0.0); - glVertex2f(maxx - rad, miny); + round_box_shade_col(color, colLeft, colRight, 0.0); + immVertex2f(pos, maxx - rad, miny); for (a = 0; a < 7; a++) { - round_box_shade_col(colLeft, colRight, vec[a][0] * idiv); - glVertex2f(maxx - rad + vec[a][0], miny + vec[a][1]); + round_box_shade_col(color, colLeft, colRight, vec[a][0] * idiv); + immVertex2f(pos, maxx - rad + vec[a][0], miny + vec[a][1]); } - round_box_shade_col(colLeft, colRight, rad * idiv); - glVertex2f(maxx, miny + rad); + round_box_shade_col(color, colLeft, colRight, rad * idiv); + immVertex2f(pos, maxx, miny + rad); } else { - round_box_shade_col(colLeft, colRight, 0.0); - glVertex2f(maxx, miny); + round_box_shade_col(color, colLeft, colRight, 0.0); + immVertex2f(pos, maxx, miny); } /* corner right-top */ if (roundboxtype & UI_CNR_TOP_RIGHT) { - round_box_shade_col(colLeft, colRight, 0.0); - glVertex2f(maxx, maxy - rad); + round_box_shade_col(color, colLeft, colRight, 0.0); + immVertex2f(pos, maxx, maxy - rad); for (a = 0; a < 7; a++) { - round_box_shade_col(colLeft, colRight, (div - rad - vec[a][0]) * idiv); - glVertex2f(maxx - vec[a][1], maxy - rad + vec[a][0]); + round_box_shade_col(color, colLeft, colRight, (div - rad - vec[a][0]) * idiv); + immVertex2f(pos, maxx - vec[a][1], maxy - rad + vec[a][0]); } - round_box_shade_col(colLeft, colRight, (div - rad) * idiv); - glVertex2f(maxx - rad, maxy); + round_box_shade_col(color, colLeft, colRight, (div - rad) * idiv); + immVertex2f(pos, maxx - rad, maxy); } else { - round_box_shade_col(colLeft, colRight, 0.0); - glVertex2f(maxx, maxy); + round_box_shade_col(color, colLeft, colRight, 0.0); + immVertex2f(pos, maxx, maxy); } /* corner left-top */ if (roundboxtype & UI_CNR_TOP_LEFT) { - round_box_shade_col(colLeft, colRight, (div - rad) * idiv); - glVertex2f(minx + rad, maxy); + round_box_shade_col(color, colLeft, colRight, (div - rad) * idiv); + immVertex2f(pos, minx + rad, maxy); for (a = 0; a < 7; a++) { - round_box_shade_col(colLeft, colRight, (div - rad + vec[a][0]) * idiv); - glVertex2f(minx + rad - vec[a][0], maxy - vec[a][1]); + round_box_shade_col(color, colLeft, colRight, (div - rad + vec[a][0]) * idiv); + immVertex2f(pos, minx + rad - vec[a][0], maxy - vec[a][1]); } - round_box_shade_col(colLeft, colRight, 1.0); - glVertex2f(minx, maxy - rad); + round_box_shade_col(color, colLeft, colRight, 1.0); + immVertex2f(pos, minx, maxy - rad); } else { - round_box_shade_col(colLeft, colRight, 1.0); - glVertex2f(minx, maxy); + round_box_shade_col(color, colLeft, colRight, 1.0); + immVertex2f(pos, minx, maxy); } /* corner left-bottom */ if (roundboxtype & UI_CNR_BOTTOM_LEFT) { - round_box_shade_col(colLeft, colRight, 1.0); - glVertex2f(minx, miny + rad); + round_box_shade_col(color, colLeft, colRight, 1.0); + immVertex2f(pos, minx, miny + rad); for (a = 0; a < 7; a++) { - round_box_shade_col(colLeft, colRight, (vec[a][0]) * idiv); - glVertex2f(minx + vec[a][1], miny + rad - vec[a][0]); + round_box_shade_col(color, colLeft, colRight, (vec[a][0]) * idiv); + immVertex2f(pos, minx + vec[a][1], miny + rad - vec[a][0]); } - round_box_shade_col(colLeft, colRight, 1.0); - glVertex2f(minx + rad, miny); + round_box_shade_col(color, colLeft, colRight, 1.0); + immVertex2f(pos, minx + rad, miny); } else { - round_box_shade_col(colLeft, colRight, 1.0); - glVertex2f(minx, miny); + round_box_shade_col(color, colLeft, colRight, 1.0); + immVertex2f(pos, minx, miny); } - - glEnd(); + + immEnd(); + immUnbindProgram(); } /* plain antialiased unfilled rectangle */ -void UI_draw_roundbox_unfilled(float minx, float miny, float maxx, float maxy, float rad) +void UI_draw_roundbox_unfilled(float minx, float miny, float maxx, float maxy, float rad, const float color[4]) { - float color[4]; - + float col[4]; + + copy_v4_v4(col, color); + if (roundboxtype & UI_RB_ALPHA) { - glGetFloatv(GL_CURRENT_COLOR, color); - color[3] = 0.5; - glColor4fv(color); - glEnable(GL_BLEND); + col[3] = 0.5; } /* set antialias line */ glEnable(GL_LINE_SMOOTH); glEnable(GL_BLEND); - - UI_draw_roundbox_gl_mode(GL_LINE_LOOP, minx, miny, maxx, maxy, rad); + UI_draw_roundbox_gl_mode(GL_LINE_LOOP, minx, miny, maxx, maxy, rad, col); glDisable(GL_BLEND); glDisable(GL_LINE_SMOOTH); } /* (old, used in outliner) plain antialiased filled box */ -void UI_draw_roundbox(float minx, float miny, float maxx, float maxy, float rad) +void UI_draw_roundbox(float minx, float miny, float maxx, float maxy, float rad, const float color[4]) { - ui_draw_anti_roundbox(GL_POLYGON, minx, miny, maxx, maxy, rad, roundboxtype & UI_RB_ALPHA); + ui_draw_anti_roundbox(GL_TRIANGLE_FAN, minx, miny, maxx, maxy, rad, roundboxtype & UI_RB_ALPHA, color); } -void UI_draw_text_underline(int pos_x, int pos_y, int len, int height) +void UI_draw_text_underline(int pos_x, int pos_y, int len, int height, const float color[4]) { int ofs_y = 4 * U.pixelsize; - glRecti(pos_x, pos_y - ofs_y, pos_x + len, pos_y - ofs_y + (height * U.pixelsize)); + + VertexFormat *format = immVertexFormat(); + unsigned pos = add_attrib(format, "pos", GL_INT, 2, CONVERT_INT_TO_FLOAT); + + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + immUniformColor4fv(color); + + immRecti(pos, pos_x, pos_y - ofs_y, pos_x + len, pos_y - ofs_y + (height * U.pixelsize)); + immUnbindProgram(); } /* ************** SPECIAL BUTTON DRAWING FUNCTIONS ************* */ @@ -427,7 +492,7 @@ void ui_draw_but_IMAGE(ARegion *UNUSED(ar), uiBut *but, uiWidgetColors *UNUSED(w #endif glEnable(GL_BLEND); - glColor4f(0.0, 0.0, 0.0, 0.0); + glColor4f(0.0f, 0.0f, 0.0f, 0.0f); if (w != ibuf->x || h != ibuf->y) { float facx = (float)w / (float)ibuf->x; @@ -451,43 +516,36 @@ void ui_draw_but_IMAGE(ARegion *UNUSED(ar), uiBut *but, uiWidgetColors *UNUSED(w /** * Draw title and text safe areas. * - * The first 4 parameters are the offsets for the view, not the zones. + * The first parameter is a GL_FLOAT, 2, KEEP_FLOAT vertex attrib + * The next 4 parameters are the offsets for the view, not the zones. */ void UI_draw_safe_areas( - float x1, float x2, float y1, float y2, + unsigned pos, float x1, float x2, float y1, float y2, const float title_aspect[2], const float action_aspect[2]) { const float size_x_half = (x2 - x1) * 0.5f; const float size_y_half = (y2 - y1) * 0.5f; const float *safe_areas[] = {title_aspect, action_aspect}; - int safe_len = ARRAY_SIZE(safe_areas); + const int safe_len = ARRAY_SIZE(safe_areas); bool is_first = true; for (int i = 0; i < safe_len; i++) { if (safe_areas[i][0] || safe_areas[i][1]) { - float margin_x, margin_y; - float minx, miny, maxx, maxy; - if (is_first) { - UI_ThemeColorBlendShade(TH_VIEW_OVERLAY, TH_BACK, 0.25f, 0); + immUniformThemeColorBlend(TH_VIEW_OVERLAY, TH_BACK, 0.25f); is_first = false; } - margin_x = safe_areas[i][0] * size_x_half; - margin_y = safe_areas[i][1] * size_y_half; + float margin_x = safe_areas[i][0] * size_x_half; + float margin_y = safe_areas[i][1] * size_y_half; - minx = x1 + margin_x; - miny = y1 + margin_y; - maxx = x2 - margin_x; - maxy = y2 - margin_y; + float minx = x1 + margin_x; + float miny = y1 + margin_y; + float maxx = x2 - margin_x; + float maxy = y2 - margin_y; - glBegin(GL_LINE_LOOP); - glVertex2f(maxx, miny); - glVertex2f(maxx, maxy); - glVertex2f(minx, maxy); - glVertex2f(minx, miny); - glEnd(); + imm_draw_line_box(pos, minx, miny, maxx, maxy); } } } @@ -501,52 +559,60 @@ static void draw_scope_end(const rctf *rect, GLint *scissor) glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); /* outline */ - glColor4f(0.f, 0.f, 0.f, 0.5f); UI_draw_roundbox_corner_set(UI_CNR_ALL); - UI_draw_roundbox_gl_mode(GL_LINE_LOOP, rect->xmin - 1, rect->ymin, rect->xmax + 1, rect->ymax + 1, 3.0f); + float color[4] = {0.0f, 0.0f, 0.0f, 0.5f}; + UI_draw_roundbox_gl_mode(GL_LINE_LOOP, rect->xmin - 1, rect->ymin, rect->xmax + 1, rect->ymax + 1, 3.0f, color); } static void histogram_draw_one( float r, float g, float b, float alpha, - float x, float y, float w, float h, const float *data, int res, const bool is_line) + float x, float y, float w, float h, const float *data, int res, const bool is_line, + unsigned int pos_attrib) { + float color[4] = {r, g, b, alpha}; + + /* that can happen */ + if (res == 0) + return; + glEnable(GL_LINE_SMOOTH); glBlendFunc(GL_SRC_ALPHA, GL_ONE); - glColor4f(r, g, b, alpha); + + immUniformColor4fv(color); if (is_line) { /* curve outline */ glLineWidth(1.5); - glBegin(GL_LINE_STRIP); + immBegin(GL_LINE_STRIP, res); for (int i = 0; i < res; i++) { float x2 = x + i * (w / (float)res); - glVertex2f(x2, y + (data[i] * h)); + immVertex2f(pos_attrib, x2, y + (data[i] * h)); } - glEnd(); + immEnd(); } else { /* under the curve */ - glBegin(GL_TRIANGLE_STRIP); - glVertex2f(x, y); - glVertex2f(x, y + (data[0] * h)); + immBegin(GL_TRIANGLE_STRIP, res * 2); + immVertex2f(pos_attrib, x, y); + immVertex2f(pos_attrib, x, y + (data[0] * h)); for (int i = 1; i < res; i++) { float x2 = x + i * (w / (float)res); - glVertex2f(x2, y + (data[i] * h)); - glVertex2f(x2, y); + immVertex2f(pos_attrib, x2, y + (data[i] * h)); + immVertex2f(pos_attrib, x2, y); } - glEnd(); + immEnd(); /* curve outline */ - glColor4f(0.f, 0.f, 0.f, 0.25f); + immUniformColor4f(0.0f, 0.0f, 0.0f, 0.25f); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - glBegin(GL_LINE_STRIP); + immBegin(GL_LINE_STRIP, res); for (int i = 0; i < res; i++) { float x2 = x + i * (w / (float)res); - glVertex2f(x2, y + (data[i] * h)); + immVertex2f(pos_attrib, x2, y + (data[i] * h)); } - glEnd(); + immEnd(); } glDisable(GL_LINE_SMOOTH); @@ -559,7 +625,7 @@ void ui_draw_but_HISTOGRAM(ARegion *ar, uiBut *but, uiWidgetColors *UNUSED(wcol) Histogram *hist = (Histogram *)but->poin; int res = hist->x_resolution; const bool is_line = (hist->flag & HISTO_FLAG_LINE) != 0; - + rctf rect = { .xmin = (float)recti->xmin + 1, .xmax = (float)recti->xmax - 1, @@ -573,9 +639,10 @@ void ui_draw_but_HISTOGRAM(ARegion *ar, uiBut *but, uiWidgetColors *UNUSED(wcol) glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - UI_ThemeColor4(TH_PREVIEW_BACK); + float color[4]; + UI_GetThemeColor4fv(TH_PREVIEW_BACK, color); UI_draw_roundbox_corner_set(UI_CNR_ALL); - UI_draw_roundbox_gl_mode(GL_POLYGON, rect.xmin - 1, rect.ymin - 1, rect.xmax + 1, rect.ymax + 1, 3.0f); + UI_draw_roundbox_gl_mode(GL_TRIANGLE_FAN, rect.xmin - 1, rect.ymin - 1, rect.xmax + 1, rect.ymax + 1, 3.0f, color); /* need scissor test, histogram can draw outside of boundary */ GLint scissor[4]; @@ -585,34 +652,48 @@ void ui_draw_but_HISTOGRAM(ARegion *ar, uiBut *but, uiWidgetColors *UNUSED(wcol) (rect.xmax + 1) - (rect.xmin - 1), (rect.ymax + 1) - (rect.ymin - 1)); - glColor4f(1.f, 1.f, 1.f, 0.08f); + VertexFormat *format = immVertexFormat(); + unsigned pos = add_attrib(format, "pos", GL_FLOAT, 2, KEEP_FLOAT); + + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + + immUniformColor4f(1.0f, 1.0f, 1.0f, 0.08f); /* draw grid lines here */ for (int i = 1; i <= HISTOGRAM_TOT_GRID_LINES; i++) { const float fac = (float)i / (float)HISTOGRAM_TOT_GRID_LINES; /* so we can tell the 1.0 color point */ if (i == HISTOGRAM_TOT_GRID_LINES) { - glColor4f(1.0f, 1.0f, 1.0f, 0.5f); + immUniformColor4f(1.0f, 1.0f, 1.0f, 0.5f); } - fdrawline(rect.xmin, rect.ymin + fac * h, rect.xmax, rect.ymin + fac * h); - fdrawline(rect.xmin + fac * w, rect.ymin, rect.xmin + fac * w, rect.ymax); + immBegin(GL_LINES, 4); + + immVertex2f(pos, rect.xmin, rect.ymin + fac * h); + immVertex2f(pos, rect.xmax, rect.ymin + fac * h); + + immVertex2f(pos, rect.xmin + fac * w, rect.ymin); + immVertex2f(pos, rect.xmin + fac * w, rect.ymax); + + immEnd(); } - + if (hist->mode == HISTO_MODE_LUMA) { - histogram_draw_one(1.0, 1.0, 1.0, 0.75, rect.xmin, rect.ymin, w, h, hist->data_luma, res, is_line); + histogram_draw_one(1.0, 1.0, 1.0, 0.75, rect.xmin, rect.ymin, w, h, hist->data_luma, res, is_line, pos); } else if (hist->mode == HISTO_MODE_ALPHA) { - histogram_draw_one(1.0, 1.0, 1.0, 0.75, rect.xmin, rect.ymin, w, h, hist->data_a, res, is_line); + histogram_draw_one(1.0, 1.0, 1.0, 0.75, rect.xmin, rect.ymin, w, h, hist->data_a, res, is_line, pos); } else { if (hist->mode == HISTO_MODE_RGB || hist->mode == HISTO_MODE_R) - histogram_draw_one(1.0, 0.0, 0.0, 0.75, rect.xmin, rect.ymin, w, h, hist->data_r, res, is_line); + histogram_draw_one(1.0, 0.0, 0.0, 0.75, rect.xmin, rect.ymin, w, h, hist->data_r, res, is_line, pos); if (hist->mode == HISTO_MODE_RGB || hist->mode == HISTO_MODE_G) - histogram_draw_one(0.0, 1.0, 0.0, 0.75, rect.xmin, rect.ymin, w, h, hist->data_g, res, is_line); + histogram_draw_one(0.0, 1.0, 0.0, 0.75, rect.xmin, rect.ymin, w, h, hist->data_g, res, is_line, pos); if (hist->mode == HISTO_MODE_RGB || hist->mode == HISTO_MODE_B) - histogram_draw_one(0.0, 0.0, 1.0, 0.75, rect.xmin, rect.ymin, w, h, hist->data_b, res, is_line); + histogram_draw_one(0.0, 0.0, 1.0, 0.75, rect.xmin, rect.ymin, w, h, hist->data_b, res, is_line, pos); } + + immUnbindProgram(); /* outline */ draw_scope_end(&rect, scissor); @@ -620,6 +701,25 @@ void ui_draw_but_HISTOGRAM(ARegion *ar, uiBut *but, uiWidgetColors *UNUSED(wcol) #undef HISTOGRAM_TOT_GRID_LINES +static void waveform_draw_one(float *waveform, int nbr, const float col[3]) +{ + VertexFormat format = {0}; + unsigned int pos_id = add_attrib(&format, "pos", GL_FLOAT, 2, KEEP_FLOAT); + + VertexBuffer *vbo = VertexBuffer_create_with_format(&format); + VertexBuffer_allocate_data(vbo, nbr); + + fillAttrib(vbo, pos_id, waveform); + + /* TODO store the Batch inside the scope */ + Batch *batch = Batch_create(GL_POINTS, vbo, NULL); + Batch_set_builtin_program(batch, GPU_SHADER_2D_UNIFORM_COLOR); + Batch_Uniform4f(batch, "color", col[0], col[1], col[2], 1.0f); + Batch_draw(batch); + + Batch_discard_all(batch); +} + void ui_draw_but_WAVEFORM(ARegion *ar, uiBut *but, uiWidgetColors *UNUSED(wcol), const rcti *recti) { Scopes *scopes = (Scopes *)but->poin; @@ -642,7 +742,7 @@ void ui_draw_but_WAVEFORM(ARegion *ar, uiBut *but, uiWidgetColors *UNUSED(wcol), scopes->wavefrm_yfac = 0.98f; float w = BLI_rctf_size_x(&rect) - 7; float h = BLI_rctf_size_y(&rect) * scopes->wavefrm_yfac; - float yofs = rect.ymin + (BLI_rctf_size_y(&rect) - h) / 2.0f; + float yofs = rect.ymin + (BLI_rctf_size_y(&rect) - h) * 0.5f; float w3 = w / 3.0f; /* log scale for alpha */ @@ -660,9 +760,10 @@ void ui_draw_but_WAVEFORM(ARegion *ar, uiBut *but, uiWidgetColors *UNUSED(wcol), glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - UI_ThemeColor4(TH_PREVIEW_BACK); + float color[4]; + UI_GetThemeColor4fv(TH_PREVIEW_BACK, color); UI_draw_roundbox_corner_set(UI_CNR_ALL); - UI_draw_roundbox_gl_mode(GL_POLYGON, rect.xmin - 1, rect.ymin - 1, rect.xmax + 1, rect.ymax + 1, 3.0f); + UI_draw_roundbox_gl_mode(GL_TRIANGLE_FAN, rect.xmin - 1, rect.ymin - 1, rect.xmax + 1, rect.ymax + 1, 3.0f, color); /* need scissor test, waveform can draw outside of boundary */ glGetIntegerv(GL_VIEWPORT, scissor); @@ -671,94 +772,120 @@ void ui_draw_but_WAVEFORM(ARegion *ar, uiBut *but, uiWidgetColors *UNUSED(wcol), (rect.xmax + 1) - (rect.xmin - 1), (rect.ymax + 1) - (rect.ymin - 1)); - glColor4f(1.f, 1.f, 1.f, 0.08f); - /* draw grid lines here */ + /* draw scale numbers first before binding any shader */ for (int i = 0; i < 6; i++) { char str[4]; BLI_snprintf(str, sizeof(str), "%-3d", i * 20); str[3] = '\0'; - fdrawline(rect.xmin + 22, yofs + (i / 5.f) * h, rect.xmax + 1, yofs + (i / 5.f) * h); - BLF_draw_default(rect.xmin + 1, yofs - 5 + (i / 5.f) * h, 0, str, sizeof(str) - 1); - /* in the loop because blf_draw reset it */ - glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + BLF_color4f(BLF_default(), 1.0f, 1.0f, 1.0f, 0.08f); + BLF_draw_default(rect.xmin + 1, yofs - 5 + (i * 0.2f) * h, 0, str, sizeof(str) - 1); } + + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + + VertexFormat *format = immVertexFormat(); + unsigned pos = add_attrib(format, "pos", GL_FLOAT, 2, KEEP_FLOAT); + + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + + immUniformColor4f(1.0f, 1.0f, 1.0f, 0.08f); + + /* draw grid lines here */ + immBegin(GL_LINES, 12); + + for (int i = 0; i < 6; i++) { + immVertex2f(pos, rect.xmin + 22, yofs + (i * 0.2f) * h); + immVertex2f(pos, rect.xmax + 1, yofs + (i * 0.2f) * h); + } + + immEnd(); + /* 3 vertical separation */ if (scopes->wavefrm_mode != SCOPES_WAVEFRM_LUMA) { + immBegin(GL_LINES, 4); + for (int i = 1; i < 3; i++) { - fdrawline(rect.xmin + i * w3, rect.ymin, rect.xmin + i * w3, rect.ymax); + immVertex2f(pos, rect.xmin + i * w3, rect.ymin); + immVertex2f(pos, rect.xmin + i * w3, rect.ymax); } + + immEnd(); } /* separate min max zone on the right */ - fdrawline(rect.xmin + w, rect.ymin, rect.xmin + w, rect.ymax); + immBegin(GL_LINES, 2); + immVertex2f(pos, rect.xmin + w, rect.ymin); + immVertex2f(pos, rect.xmin + w, rect.ymax); + immEnd(); + /* 16-235-240 level in case of ITU-R BT601/709 */ - glColor4f(1.f, 0.4f, 0.f, 0.2f); + immUniformColor4f(1.0f, 0.4f, 0.0f, 0.2f); if (ELEM(scopes->wavefrm_mode, SCOPES_WAVEFRM_YCC_601, SCOPES_WAVEFRM_YCC_709)) { - fdrawline(rect.xmin + 22, yofs + h * 16.0f / 255.0f, rect.xmax + 1, yofs + h * 16.0f / 255.0f); - fdrawline(rect.xmin + 22, yofs + h * 235.0f / 255.0f, rect.xmin + w3, yofs + h * 235.0f / 255.0f); - fdrawline(rect.xmin + 3 * w3, yofs + h * 235.0f / 255.0f, rect.xmax + 1, yofs + h * 235.0f / 255.0f); - fdrawline(rect.xmin + w3, yofs + h * 240.0f / 255.0f, rect.xmax + 1, yofs + h * 240.0f / 255.0f); + immBegin(GL_LINES, 8); + + immVertex2f(pos, rect.xmin + 22, yofs + h * 16.0f / 255.0f); + immVertex2f(pos, rect.xmax + 1, yofs + h * 16.0f / 255.0f); + + immVertex2f(pos, rect.xmin + 22, yofs + h * 235.0f / 255.0f); + immVertex2f(pos, rect.xmin + w3, yofs + h * 235.0f / 255.0f); + + immVertex2f(pos, rect.xmin + 3 * w3, yofs + h * 235.0f / 255.0f); + immVertex2f(pos, rect.xmax + 1, yofs + h * 235.0f / 255.0f); + + immVertex2f(pos, rect.xmin + w3, yofs + h * 240.0f / 255.0f); + immVertex2f(pos, rect.xmax + 1, yofs + h * 240.0f / 255.0f); + + immEnd(); } /* 7.5 IRE black point level for NTSC */ - if (scopes->wavefrm_mode == SCOPES_WAVEFRM_LUMA) - fdrawline(rect.xmin, yofs + h * 0.075f, rect.xmax + 1, yofs + h * 0.075f); + if (scopes->wavefrm_mode == SCOPES_WAVEFRM_LUMA) { + immBegin(GL_LINES, 2); + immVertex2f(pos, rect.xmin, yofs + h * 0.075f); + immVertex2f(pos, rect.xmax + 1, yofs + h * 0.075f); + immEnd(); + } if (scopes->ok && scopes->waveform_1 != NULL) { - - /* LUMA (1 channel) */ + gpuMatrixBegin3D_legacy(); glBlendFunc(GL_ONE, GL_ONE); - glColor3f(alpha, alpha, alpha); glPointSize(1.0); + /* LUMA (1 channel) */ if (scopes->wavefrm_mode == SCOPES_WAVEFRM_LUMA) { + float col[3] = {alpha, alpha, alpha}; - glBlendFunc(GL_ONE, GL_ONE); - - glPushMatrix(); - glEnableClientState(GL_VERTEX_ARRAY); - - glTranslatef(rect.xmin, yofs, 0.f); - glScalef(w, h, 0.f); - glVertexPointer(2, GL_FLOAT, 0, scopes->waveform_1); - glDrawArrays(GL_POINTS, 0, scopes->waveform_tot); + gpuPushMatrix(); + gpuTranslate3f(rect.xmin, yofs, 0.0f); + gpuScale3f(w, h, 0.0f); - glDisableClientState(GL_VERTEX_ARRAY); - glPopMatrix(); + waveform_draw_one(scopes->waveform_1, scopes->waveform_tot, col); + + gpuPopMatrix(); /* min max */ - glColor3f(0.5f, 0.5f, 0.5f); + immUniformColor3f(0.5f, 0.5f, 0.5f); min = yofs + scopes->minmax[0][0] * h; max = yofs + scopes->minmax[0][1] * h; CLAMP(min, rect.ymin, rect.ymax); CLAMP(max, rect.ymin, rect.ymax); - fdrawline(rect.xmax - 3, min, rect.xmax - 3, max); + + immBegin(GL_LINES, 2); + immVertex2f(pos, rect.xmax - 3, min); + immVertex2f(pos, rect.xmax - 3, max); + immEnd(); } /* RGB (3 channel) */ else if (scopes->wavefrm_mode == SCOPES_WAVEFRM_RGB) { - glBlendFunc(GL_ONE, GL_ONE); + gpuPushMatrix(); + gpuTranslate3f(rect.xmin, yofs, 0.0f); + gpuScale3f(w, h, 0.0f); - glEnableClientState(GL_VERTEX_ARRAY); + waveform_draw_one(scopes->waveform_1, scopes->waveform_tot, colors_alpha[0]); + waveform_draw_one(scopes->waveform_2, scopes->waveform_tot, colors_alpha[1]); + waveform_draw_one(scopes->waveform_3, scopes->waveform_tot, colors_alpha[2]); - glPushMatrix(); - - glTranslatef(rect.xmin, yofs, 0.f); - glScalef(w, h, 0.f); - - glColor3fv( colors_alpha[0] ); - glVertexPointer(2, GL_FLOAT, 0, scopes->waveform_1); - glDrawArrays(GL_POINTS, 0, scopes->waveform_tot); - - glColor3fv( colors_alpha[1] ); - glVertexPointer(2, GL_FLOAT, 0, scopes->waveform_2); - glDrawArrays(GL_POINTS, 0, scopes->waveform_tot); - - glColor3fv( colors_alpha[2] ); - glVertexPointer(2, GL_FLOAT, 0, scopes->waveform_3); - glDrawArrays(GL_POINTS, 0, scopes->waveform_tot); - - glDisableClientState(GL_VERTEX_ARRAY); - glPopMatrix(); + gpuPopMatrix(); } /* PARADE / YCC (3 channels) */ else if (ELEM(scopes->wavefrm_mode, @@ -770,49 +897,48 @@ void ui_draw_but_WAVEFORM(ARegion *ar, uiBut *but, uiWidgetColors *UNUSED(wcol), { int rgb = (scopes->wavefrm_mode == SCOPES_WAVEFRM_RGB_PARADE); - glBlendFunc(GL_ONE, GL_ONE); - - glPushMatrix(); - glEnableClientState(GL_VERTEX_ARRAY); + gpuPushMatrix(); + gpuTranslate3f(rect.xmin, yofs, 0.0f); + gpuScale3f(w3, h, 0.0f); - glTranslatef(rect.xmin, yofs, 0.f); - glScalef(w3, h, 0.f); + waveform_draw_one(scopes->waveform_1, scopes->waveform_tot, (rgb) ? colors_alpha[0] : colorsycc_alpha[0]); - glColor3fv((rgb) ? colors_alpha[0] : colorsycc_alpha[0]); - glVertexPointer(2, GL_FLOAT, 0, scopes->waveform_1); - glDrawArrays(GL_POINTS, 0, scopes->waveform_tot); + gpuTranslate3f(1.0f, 0.0f, 0.0f); + waveform_draw_one(scopes->waveform_2, scopes->waveform_tot, (rgb) ? colors_alpha[1] : colorsycc_alpha[1]); - glTranslatef(1.f, 0.f, 0.f); - glColor3fv((rgb) ? colors_alpha[1] : colorsycc_alpha[1]); - glVertexPointer(2, GL_FLOAT, 0, scopes->waveform_2); - glDrawArrays(GL_POINTS, 0, scopes->waveform_tot); + gpuTranslate3f(1.0f, 0.0f, 0.0f); + waveform_draw_one(scopes->waveform_3, scopes->waveform_tot, (rgb) ? colors_alpha[2] : colorsycc_alpha[2]); - glTranslatef(1.f, 0.f, 0.f); - glColor3fv((rgb) ? colors_alpha[2] : colorsycc_alpha[2]); - glVertexPointer(2, GL_FLOAT, 0, scopes->waveform_3); - glDrawArrays(GL_POINTS, 0, scopes->waveform_tot); - - glDisableClientState(GL_VERTEX_ARRAY); - glPopMatrix(); + gpuPopMatrix(); } + /* min max */ if (scopes->wavefrm_mode != SCOPES_WAVEFRM_LUMA ) { for (int c = 0; c < 3; c++) { if (ELEM(scopes->wavefrm_mode, SCOPES_WAVEFRM_RGB_PARADE, SCOPES_WAVEFRM_RGB)) - glColor3f(colors[c][0] * 0.75f, colors[c][1] * 0.75f, colors[c][2] * 0.75f); + immUniformColor3f(colors[c][0] * 0.75f, colors[c][1] * 0.75f, colors[c][2] * 0.75f); else - glColor3f(colorsycc[c][0] * 0.75f, colorsycc[c][1] * 0.75f, colorsycc[c][2] * 0.75f); + immUniformColor3f(colorsycc[c][0] * 0.75f, colorsycc[c][1] * 0.75f, colorsycc[c][2] * 0.75f); min = yofs + scopes->minmax[c][0] * h; max = yofs + scopes->minmax[c][1] * h; CLAMP(min, rect.ymin, rect.ymax); CLAMP(max, rect.ymin, rect.ymax); - fdrawline(rect.xmin + w + 2 + c * 2, min, rect.xmin + w + 2 + c * 2, max); + + immBegin(GL_LINES, 2); + immVertex2f(pos, rect.xmin + w + 2 + c * 2, min); + immVertex2f(pos, rect.xmin + w + 2 + c * 2, max); + immEnd(); } } + gpuMatrixEnd(); } - + + immUnbindProgram(); + /* outline */ draw_scope_end(&rect, scissor); + + glDisable(GL_BLEND); } static float polar_to_x(float center, float diam, float ampli, float angle) @@ -825,10 +951,10 @@ static float polar_to_y(float center, float diam, float ampli, float angle) return center + diam * ampli * sinf(angle); } -static void vectorscope_draw_target(float centerx, float centery, float diam, const float colf[3]) +static void vectorscope_draw_target(unsigned int pos, float centerx, float centery, float diam, const float colf[3]) { float y, u, v; - float tangle = 0.f, tampli; + float tangle = 0.0f, tampli; float dangle, dampli, dangle2, dampli2; rgb_to_yuv(colf[0], colf[1], colf[2], &y, &u, &v); @@ -840,41 +966,41 @@ static void vectorscope_draw_target(float centerx, float centery, float diam, co tampli = sqrtf(u * u + v * v); /* small target vary by 2.5 degree and 2.5 IRE unit */ - glColor4f(1.0f, 1.0f, 1.0, 0.12f); + immUniformColor4f(1.0f, 1.0f, 1.0f, 0.12f); dangle = DEG2RADF(2.5f); dampli = 2.5f / 200.0f; - glBegin(GL_LINE_LOOP); - glVertex2f(polar_to_x(centerx, diam, tampli + dampli, tangle + dangle), polar_to_y(centery, diam, tampli + dampli, tangle + dangle)); - glVertex2f(polar_to_x(centerx, diam, tampli - dampli, tangle + dangle), polar_to_y(centery, diam, tampli - dampli, tangle + dangle)); - glVertex2f(polar_to_x(centerx, diam, tampli - dampli, tangle - dangle), polar_to_y(centery, diam, tampli - dampli, tangle - dangle)); - glVertex2f(polar_to_x(centerx, diam, tampli + dampli, tangle - dangle), polar_to_y(centery, diam, tampli + dampli, tangle - dangle)); - glEnd(); + immBegin(GL_LINE_LOOP, 4); + immVertex2f(pos, polar_to_x(centerx, diam, tampli + dampli, tangle + dangle), polar_to_y(centery, diam, tampli + dampli, tangle + dangle)); + immVertex2f(pos, polar_to_x(centerx, diam, tampli - dampli, tangle + dangle), polar_to_y(centery, diam, tampli - dampli, tangle + dangle)); + immVertex2f(pos, polar_to_x(centerx, diam, tampli - dampli, tangle - dangle), polar_to_y(centery, diam, tampli - dampli, tangle - dangle)); + immVertex2f(pos, polar_to_x(centerx, diam, tampli + dampli, tangle - dangle), polar_to_y(centery, diam, tampli + dampli, tangle - dangle)); + immEnd(); /* big target vary by 10 degree and 20% amplitude */ - glColor4f(1.0f, 1.0f, 1.0, 0.12f); + immUniformColor4f(1.0f, 1.0f, 1.0f, 0.12f); dangle = DEG2RADF(10.0f); dampli = 0.2f * tampli; dangle2 = DEG2RADF(5.0f); dampli2 = 0.5f * dampli; - glBegin(GL_LINE_STRIP); - glVertex2f(polar_to_x(centerx, diam, tampli + dampli - dampli2, tangle + dangle), polar_to_y(centery, diam, tampli + dampli - dampli2, tangle + dangle)); - glVertex2f(polar_to_x(centerx, diam, tampli + dampli, tangle + dangle), polar_to_y(centery, diam, tampli + dampli, tangle + dangle)); - glVertex2f(polar_to_x(centerx, diam, tampli + dampli, tangle + dangle - dangle2), polar_to_y(centery, diam, tampli + dampli, tangle + dangle - dangle2)); - glEnd(); - glBegin(GL_LINE_STRIP); - glVertex2f(polar_to_x(centerx, diam, tampli - dampli + dampli2, tangle + dangle), polar_to_y(centery, diam, tampli - dampli + dampli2, tangle + dangle)); - glVertex2f(polar_to_x(centerx, diam, tampli - dampli, tangle + dangle), polar_to_y(centery, diam, tampli - dampli, tangle + dangle)); - glVertex2f(polar_to_x(centerx, diam, tampli - dampli, tangle + dangle - dangle2), polar_to_y(centery, diam, tampli - dampli, tangle + dangle - dangle2)); - glEnd(); - glBegin(GL_LINE_STRIP); - glVertex2f(polar_to_x(centerx, diam, tampli - dampli + dampli2, tangle - dangle), polar_to_y(centery, diam, tampli - dampli + dampli2, tangle - dangle)); - glVertex2f(polar_to_x(centerx, diam, tampli - dampli, tangle - dangle), polar_to_y(centery, diam, tampli - dampli, tangle - dangle)); - glVertex2f(polar_to_x(centerx, diam, tampli - dampli, tangle - dangle + dangle2), polar_to_y(centery, diam, tampli - dampli, tangle - dangle + dangle2)); - glEnd(); - glBegin(GL_LINE_STRIP); - glVertex2f(polar_to_x(centerx, diam, tampli + dampli - dampli2, tangle - dangle), polar_to_y(centery, diam, tampli + dampli - dampli2, tangle - dangle)); - glVertex2f(polar_to_x(centerx, diam, tampli + dampli, tangle - dangle), polar_to_y(centery, diam, tampli + dampli, tangle - dangle)); - glVertex2f(polar_to_x(centerx, diam, tampli + dampli, tangle - dangle + dangle2), polar_to_y(centery, diam, tampli + dampli, tangle - dangle + dangle2)); - glEnd(); + immBegin(GL_LINE_STRIP, 3); + immVertex2f(pos, polar_to_x(centerx, diam, tampli + dampli - dampli2, tangle + dangle), polar_to_y(centery, diam, tampli + dampli - dampli2, tangle + dangle)); + immVertex2f(pos, polar_to_x(centerx, diam, tampli + dampli, tangle + dangle), polar_to_y(centery, diam, tampli + dampli, tangle + dangle)); + immVertex2f(pos, polar_to_x(centerx, diam, tampli + dampli, tangle + dangle - dangle2), polar_to_y(centery, diam, tampli + dampli, tangle + dangle - dangle2)); + immEnd(); + immBegin(GL_LINE_STRIP, 3); + immVertex2f(pos, polar_to_x(centerx, diam, tampli - dampli + dampli2, tangle + dangle), polar_to_y(centery, diam, tampli - dampli + dampli2, tangle + dangle)); + immVertex2f(pos, polar_to_x(centerx, diam, tampli - dampli, tangle + dangle), polar_to_y(centery, diam, tampli - dampli, tangle + dangle)); + immVertex2f(pos, polar_to_x(centerx, diam, tampli - dampli, tangle + dangle - dangle2), polar_to_y(centery, diam, tampli - dampli, tangle + dangle - dangle2)); + immEnd(); + immBegin(GL_LINE_STRIP, 3); + immVertex2f(pos, polar_to_x(centerx, diam, tampli - dampli + dampli2, tangle - dangle), polar_to_y(centery, diam, tampli - dampli + dampli2, tangle - dangle)); + immVertex2f(pos, polar_to_x(centerx, diam, tampli - dampli, tangle - dangle), polar_to_y(centery, diam, tampli - dampli, tangle - dangle)); + immVertex2f(pos, polar_to_x(centerx, diam, tampli - dampli, tangle - dangle + dangle2), polar_to_y(centery, diam, tampli - dampli, tangle - dangle + dangle2)); + immEnd(); + immBegin(GL_LINE_STRIP, 3); + immVertex2f(pos, polar_to_x(centerx, diam, tampli + dampli - dampli2, tangle - dangle), polar_to_y(centery, diam, tampli + dampli - dampli2, tangle - dangle)); + immVertex2f(pos, polar_to_x(centerx, diam, tampli + dampli, tangle - dangle), polar_to_y(centery, diam, tampli + dampli, tangle - dangle)); + immVertex2f(pos, polar_to_x(centerx, diam, tampli + dampli, tangle - dangle + dangle2), polar_to_y(centery, diam, tampli + dampli, tangle - dangle + dangle2)); + immEnd(); } void ui_draw_but_VECTORSCOPE(ARegion *ar, uiBut *but, uiWidgetColors *UNUSED(wcol), const rcti *recti) @@ -895,8 +1021,8 @@ void ui_draw_but_VECTORSCOPE(ARegion *ar, uiBut *but, uiWidgetColors *UNUSED(wco float w = BLI_rctf_size_x(&rect); float h = BLI_rctf_size_y(&rect); - float centerx = rect.xmin + w / 2; - float centery = rect.ymin + h / 2; + float centerx = rect.xmin + w * 0.5f; + float centery = rect.ymin + h * 0.5f; float diam = (w < h) ? w : h; float alpha = scopes->vecscope_alpha * scopes->vecscope_alpha * scopes->vecscope_alpha; @@ -904,9 +1030,10 @@ void ui_draw_but_VECTORSCOPE(ARegion *ar, uiBut *but, uiWidgetColors *UNUSED(wco glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - UI_ThemeColor4(TH_PREVIEW_BACK); + float color[4]; + UI_GetThemeColor4fv(TH_PREVIEW_BACK, color); UI_draw_roundbox_corner_set(UI_CNR_ALL); - UI_draw_roundbox_gl_mode(GL_POLYGON, rect.xmin - 1, rect.ymin - 1, rect.xmax + 1, rect.ymax + 1, 3.0f); + UI_draw_roundbox_gl_mode(GL_TRIANGLE_FAN, rect.xmin - 1, rect.ymin - 1, rect.xmax + 1, rect.ymax + 1, 3.0f, color); /* need scissor test, hvectorscope can draw outside of boundary */ GLint scissor[4]; @@ -916,93 +1043,111 @@ void ui_draw_but_VECTORSCOPE(ARegion *ar, uiBut *but, uiWidgetColors *UNUSED(wco (rect.xmax + 1) - (rect.xmin - 1), (rect.ymax + 1) - (rect.ymin - 1)); - glColor4f(1.f, 1.f, 1.f, 0.08f); + VertexFormat *format = immVertexFormat(); + unsigned pos = add_attrib(format, "pos", GL_FLOAT, 2, KEEP_FLOAT); + + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + + immUniformColor4f(1.0f, 1.0f, 1.0f, 0.08f); /* draw grid elements */ /* cross */ - fdrawline(centerx - (diam / 2) - 5, centery, centerx + (diam / 2) + 5, centery); - fdrawline(centerx, centery - (diam / 2) - 5, centerx, centery + (diam / 2) + 5); + immBegin(GL_LINES, 4); + + immVertex2f(pos, centerx - (diam * 0.5f) - 5, centery); + immVertex2f(pos, centerx + (diam * 0.5f) + 5, centery); + + immVertex2f(pos, centerx, centery - (diam * 0.5f) - 5); + immVertex2f(pos, centerx, centery + (diam * 0.5f) + 5); + + immEnd(); + /* circles */ for (int j = 0; j < 5; j++) { - glBegin(GL_LINE_LOOP); const int increment = 15; + immBegin(GL_LINE_LOOP, (int)(360 / increment)); for (int i = 0; i <= 360 - increment; i += increment) { const float a = DEG2RADF((float)i); - const float r = (j + 1) / 10.0f; - glVertex2f(polar_to_x(centerx, diam, r, a), polar_to_y(centery, diam, r, a)); + const float r = (j + 1) * 0.1f; + immVertex2f(pos, polar_to_x(centerx, diam, r, a), polar_to_y(centery, diam, r, a)); } - glEnd(); + immEnd(); } /* skin tone line */ - glColor4f(1.f, 0.4f, 0.f, 0.2f); - fdrawline(polar_to_x(centerx, diam, 0.5f, skin_rad), polar_to_y(centery, diam, 0.5, skin_rad), - polar_to_x(centerx, diam, 0.1f, skin_rad), polar_to_y(centery, diam, 0.1, skin_rad)); + immUniformColor4f(1.0f, 0.4f, 0.0f, 0.2f); + + immBegin(GL_LINES, 2); + immVertex2f(pos, polar_to_x(centerx, diam, 0.5f, skin_rad), polar_to_y(centery, diam, 0.5f, skin_rad)); + immVertex2f(pos, polar_to_x(centerx, diam, 0.1f, skin_rad), polar_to_y(centery, diam, 0.1f, skin_rad)); + immEnd(); + /* saturation points */ for (int i = 0; i < 6; i++) - vectorscope_draw_target(centerx, centery, diam, colors[i]); + vectorscope_draw_target(pos, centerx, centery, diam, colors[i]); if (scopes->ok && scopes->vecscope != NULL) { /* pixel point cloud */ + float col[3] = {alpha, alpha, alpha}; + glBlendFunc(GL_ONE, GL_ONE); - glColor3f(alpha, alpha, alpha); + glPointSize(1.0); - glPushMatrix(); - glEnableClientState(GL_VERTEX_ARRAY); + gpuMatrixBegin3D_legacy(); + gpuPushMatrix(); + gpuTranslate3f(centerx, centery, 0.0f); + gpuScale3f(diam, diam, 0.0f); - glTranslatef(centerx, centery, 0.f); - glScalef(diam, diam, 0.f); + waveform_draw_one(scopes->vecscope, scopes->waveform_tot, col); - glVertexPointer(2, GL_FLOAT, 0, scopes->vecscope); - glPointSize(1.0); - glDrawArrays(GL_POINTS, 0, scopes->waveform_tot); - - glDisableClientState(GL_VERTEX_ARRAY); - glPopMatrix(); + gpuPopMatrix(); + gpuMatrixEnd(); } + immUnbindProgram(); + /* outline */ draw_scope_end(&rect, scissor); glDisable(GL_BLEND); } -static void ui_draw_colorband_handle_tri_hlight(float x1, float y1, float halfwidth, float height) +static void ui_draw_colorband_handle_tri_hlight(unsigned int pos, float x1, float y1, float halfwidth, float height) { glEnable(GL_LINE_SMOOTH); - glBegin(GL_LINE_STRIP); - glVertex2f(x1 + halfwidth, y1); - glVertex2f(x1, y1 + height); - glVertex2f(x1 - halfwidth, y1); - glEnd(); + immBegin(GL_LINE_STRIP, 3); + immVertex2f(pos, x1 + halfwidth, y1); + immVertex2f(pos, x1, y1 + height); + immVertex2f(pos, x1 - halfwidth, y1); + immEnd(); glDisable(GL_LINE_SMOOTH); } -static void ui_draw_colorband_handle_tri(float x1, float y1, float halfwidth, float height, bool fill) +static void ui_draw_colorband_handle_tri(unsigned int pos, float x1, float y1, float halfwidth, float height, bool fill) { glEnable(fill ? GL_POLYGON_SMOOTH : GL_LINE_SMOOTH); - glBegin(fill ? GL_TRIANGLES : GL_LINE_LOOP); - glVertex2f(x1 + halfwidth, y1); - glVertex2f(x1, y1 + height); - glVertex2f(x1 - halfwidth, y1); - glEnd(); + immBegin(fill ? GL_TRIANGLES : GL_LINE_LOOP, 3); + immVertex2f(pos, x1 + halfwidth, y1); + immVertex2f(pos, x1, y1 + height); + immVertex2f(pos, x1 - halfwidth, y1); + immEnd(); glDisable(fill ? GL_POLYGON_SMOOTH : GL_LINE_SMOOTH); } -static void ui_draw_colorband_handle_box(float x1, float y1, float x2, float y2, bool fill) +static void ui_draw_colorband_handle_box(unsigned int pos, float x1, float y1, float x2, float y2, bool fill) { - glBegin(fill ? GL_QUADS : GL_LINE_LOOP); - glVertex2f(x1, y1); - glVertex2f(x1, y2); - glVertex2f(x2, y2); - glVertex2f(x2, y1); - glEnd(); + immBegin(fill ? GL_QUADS : GL_LINE_LOOP, 4); + immVertex2f(pos, x1, y1); + immVertex2f(pos, x1, y2); + immVertex2f(pos, x2, y2); + immVertex2f(pos, x2, y1); + immEnd(); } static void ui_draw_colorband_handle( - const rcti *rect, float x, + unsigned int pos, const rcti *rect, float x, const float rgb[3], struct ColorManagedDisplay *display, bool active) { @@ -1021,17 +1166,18 @@ static void ui_draw_colorband_handle( y1 = floorf(y1 + 0.5f); if (active || half_width < min_width) { - glBegin(GL_LINES); - glColor3ub(0, 0, 0); - glVertex2f(x, y1); - glVertex2f(x, y2); - glEnd(); + immUniformColor3ub(0, 0, 0); + immBegin(GL_LINES, 2); + immVertex2f(pos, x, y1); + immVertex2f(pos, x, y2); + immEnd(); + setlinestyle(active ? 2 : 1); - glBegin(GL_LINES); - glColor3ub(200, 200, 200); - glVertex2f(x, y1); - glVertex2f(x, y2); - glEnd(); + immUniformColor3ub(200, 200, 200); + immBegin(GL_LINES, 2); + immVertex2f(pos, x, y1); + immVertex2f(pos, x, y2); + immEnd(); setlinestyle(0); /* hide handles when zoomed out too far */ @@ -1043,45 +1189,46 @@ static void ui_draw_colorband_handle( /* shift handle down */ y1 -= half_width; - glColor3ub(0, 0, 0); - ui_draw_colorband_handle_box(x - half_width, y1 - 1, x + half_width, y1 + height, false); + immUniformColor3ub(0, 0, 0); + ui_draw_colorband_handle_box(pos, x - half_width, y1 - 1, x + half_width, y1 + height, false); /* draw all triangles blended */ glEnable(GL_BLEND); - ui_draw_colorband_handle_tri(x, y1 + height, half_width, half_width, true); + ui_draw_colorband_handle_tri(pos, x, y1 + height, half_width, half_width, true); if (active) - glColor3ub(196, 196, 196); + immUniformColor3ub(196, 196, 196); else - glColor3ub(96, 96, 96); - ui_draw_colorband_handle_tri(x, y1 + height, half_width, half_width, true); + immUniformColor3ub(96, 96, 96); + ui_draw_colorband_handle_tri(pos, x, y1 + height, half_width, half_width, true); if (active) - glColor3ub(255, 255, 255); + immUniformColor3ub(255, 255, 255); else - glColor3ub(128, 128, 128); - ui_draw_colorband_handle_tri_hlight(x, y1 + height - 1, (half_width - 1), (half_width - 1)); + immUniformColor3ub(128, 128, 128); + ui_draw_colorband_handle_tri_hlight(pos, x, y1 + height - 1, (half_width - 1), (half_width - 1)); - glColor3ub(0, 0, 0); - ui_draw_colorband_handle_tri_hlight(x, y1 + height, half_width, half_width); + immUniformColor3ub(0, 0, 0); + ui_draw_colorband_handle_tri_hlight(pos, x, y1 + height, half_width, half_width); glDisable(GL_BLEND); - glColor3ub(128, 128, 128); - ui_draw_colorband_handle_box(x - (half_width - 1), y1, x + (half_width - 1), y1 + height, true); + immUniformColor3ub(128, 128, 128); + ui_draw_colorband_handle_box(pos, x - (half_width - 1), y1, x + (half_width - 1), y1 + height, true); if (display) { IMB_colormanagement_scene_linear_to_display_v3(colf, display); } - glColor3fv(colf); - ui_draw_colorband_handle_box(x - (half_width - 2), y1 + 1, x + (half_width - 2), y1 + height - 2, true); + immUniformColor3fv(colf); + ui_draw_colorband_handle_box(pos, x - (half_width - 2), y1 + 1, x + (half_width - 2), y1 + height - 2, true); } void ui_draw_but_COLORBAND(uiBut *but, uiWidgetColors *UNUSED(wcol), const rcti *rect) { struct ColorManagedDisplay *display = NULL; + unsigned int position, color; ColorBand *coba = (ColorBand *)(but->editcoba ? but->editcoba : but->poin); if (coba == NULL) return; @@ -1092,20 +1239,25 @@ void ui_draw_but_COLORBAND(uiBut *but, uiWidgetColors *UNUSED(wcol), const rcti float x1 = rect->xmin; float sizex = rect->xmax - x1; float sizey = BLI_rcti_size_y(rect); - float sizey_solid = sizey / 4; + float sizey_solid = sizey * 0.25f; float y1 = rect->ymin; - /* Drawing the checkerboard. - * This could be optimized with a single checkerboard shader, - * instead of drawing twice and using stippling the second time. */ - /* layer: background, to show tranparency */ - glColor4ub(UI_ALPHA_CHECKER_DARK, UI_ALPHA_CHECKER_DARK, UI_ALPHA_CHECKER_DARK, 255); - glRectf(x1, y1, x1 + sizex, rect->ymax); - GPU_basic_shader_bind(GPU_SHADER_STIPPLE | GPU_SHADER_USE_COLOR); - glColor4ub(UI_ALPHA_CHECKER_LIGHT, UI_ALPHA_CHECKER_LIGHT, UI_ALPHA_CHECKER_LIGHT, 255); - GPU_basic_shader_stipple(GPU_SHADER_STIPPLE_CHECKER_8PX); - glRectf(x1, y1, x1 + sizex, rect->ymax); - GPU_basic_shader_bind(GPU_SHADER_USE_COLOR); + VertexFormat *format = immVertexFormat(); + position = add_attrib(format, "pos", GL_FLOAT, 2, KEEP_FLOAT); + immBindBuiltinProgram(GPU_SHADER_2D_CHECKER); + + /* Drawing the checkerboard. */ + immUniform4f("color1", UI_ALPHA_CHECKER_DARK / 255.0f, UI_ALPHA_CHECKER_DARK / 255.0f, UI_ALPHA_CHECKER_DARK / 255.0f, 1.0f); + immUniform4f("color2", UI_ALPHA_CHECKER_LIGHT / 255.0f, UI_ALPHA_CHECKER_LIGHT / 255.0f, UI_ALPHA_CHECKER_LIGHT / 255.0f, 1.0f); + immUniform1i("size", 8); + immRectf(position, x1, y1, x1 + sizex, rect->ymax); + immUnbindProgram(); + + /* New format */ + format = immVertexFormat(); + position = add_attrib(format, "pos", GL_FLOAT, 2, KEEP_FLOAT); + color = add_attrib(format, "color", GL_FLOAT, 4, KEEP_FLOAT); + immBindBuiltinProgram(GPU_SHADER_2D_SMOOTH_COLOR); /* layer: color ramp */ glEnable(GL_BLEND); @@ -1118,7 +1270,7 @@ void ui_draw_but_COLORBAND(uiBut *but, uiWidgetColors *UNUSED(wcol), const rcti v1[1] = y1 + sizey_solid; v2[1] = rect->ymax; - glBegin(GL_TRIANGLE_STRIP); + immBegin(GL_TRIANGLE_STRIP, (sizex + 1) * 2); for (int a = 0; a <= sizex; a++) { float pos = ((float)a) / sizex; do_colorband(coba, pos, colf); @@ -1127,17 +1279,17 @@ void ui_draw_but_COLORBAND(uiBut *but, uiWidgetColors *UNUSED(wcol), const rcti v1[0] = v2[0] = x1 + a; - glColor4fv(colf); - glVertex2fv(v1); - glVertex2fv(v2); + immAttrib4fv(color, colf); + immVertex2fv(position, v1); + immVertex2fv(position, v2); } - glEnd(); + immEnd(); /* layer: color ramp without alpha for reference when manipulating ramp properties */ v1[1] = y1; v2[1] = y1 + sizey_solid; - glBegin(GL_TRIANGLE_STRIP); + immBegin(GL_TRIANGLE_STRIP, (sizex + 1) * 2); for (int a = 0; a <= sizex; a++) { float pos = ((float)a) / sizex; do_colorband(coba, pos, colf); @@ -1146,31 +1298,48 @@ void ui_draw_but_COLORBAND(uiBut *but, uiWidgetColors *UNUSED(wcol), const rcti v1[0] = v2[0] = x1 + a; - glColor4f(colf[0], colf[1], colf[2], 1.0f); - glVertex2fv(v1); - glVertex2fv(v2); + immAttrib4f(color, colf[0], colf[1], colf[2], 1.0f); + immVertex2fv(position, v1); + immVertex2fv(position, v2); } - glEnd(); + immEnd(); + + immUnbindProgram(); glDisable(GL_BLEND); + /* New format */ + format = immVertexFormat(); + position = add_attrib(format, "pos", GL_FLOAT, 2, KEEP_FLOAT); + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + /* layer: box outline */ - glColor4f(0.0, 0.0, 0.0, 1.0); - fdrawbox(x1, y1, x1 + sizex, rect->ymax); - + immUniformColor4f(0.0f, 0.0f, 0.0f, 1.0f); + imm_draw_line_box(position, x1, y1, x1 + sizex, rect->ymax); + /* layer: box outline */ glEnable(GL_BLEND); - glColor4f(0.0f, 0.0f, 0.0f, 0.5f); - fdrawline(x1, y1, x1 + sizex, y1); - glColor4f(1.0f, 1.0f, 1.0f, 0.25f); - fdrawline(x1, y1 - 1, x1 + sizex, y1 - 1); + immUniformColor4f(0.0f, 0.0f, 0.0f, 0.5f); + + immBegin(GL_LINES, 2); + immVertex2f(position, x1, y1); + immVertex2f(position, x1 + sizex, y1); + immEnd(); + + immUniformColor4f(1.0f, 1.0f, 1.0f, 0.25f); + + immBegin(GL_LINES, 2); + immVertex2f(position, x1, y1 - 1); + immVertex2f(position, x1 + sizex, y1 - 1); + immEnd(); + glDisable(GL_BLEND); /* layer: draw handles */ for (int a = 0; a < coba->tot; a++, cbd++) { if (a != coba->cur) { float pos = x1 + cbd->pos * (sizex - 1) + 1; - ui_draw_colorband_handle(rect, pos, &cbd->r, display, false); + ui_draw_colorband_handle(position, rect, pos, &cbd->r, display, false); } } @@ -1178,117 +1347,102 @@ void ui_draw_but_COLORBAND(uiBut *but, uiWidgetColors *UNUSED(wcol), const rcti if (coba->tot != 0) { cbd = &coba->data[coba->cur]; float pos = x1 + cbd->pos * (sizex - 1) + 1; - ui_draw_colorband_handle(rect, pos, &cbd->r, display, true); + ui_draw_colorband_handle(position, rect, pos, &cbd->r, display, true); } + + immUnbindProgram(); } void ui_draw_but_UNITVEC(uiBut *but, uiWidgetColors *wcol, const rcti *rect) { - static GLuint displist = 0; + /* sphere color */ float diffuse[3] = {1.0f, 1.0f, 1.0f}; + float light[3]; float size; /* backdrop */ - glColor3ubv((unsigned char *)wcol->inner); UI_draw_roundbox_corner_set(UI_CNR_ALL); - UI_draw_roundbox_gl_mode(GL_POLYGON, rect->xmin, rect->ymin, rect->xmax, rect->ymax, 5.0f); + UI_draw_roundbox_gl_mode_3ubAlpha(GL_TRIANGLE_FAN, rect->xmin, rect->ymin, rect->xmax, rect->ymax, 5.0f, (unsigned char *)wcol->inner, 255); - /* sphere color */ glCullFace(GL_BACK); glEnable(GL_CULL_FACE); /* setup lights */ - GPULightData light = {0}; - light.type = GPU_LIGHT_SUN; - copy_v3_v3(light.diffuse, diffuse); - zero_v3(light.specular); - ui_but_v3_get(but, light.direction); - - GPU_basic_shader_light_set(0, &light); - for (int a = 1; a < 8; a++) - GPU_basic_shader_light_set(a, NULL); - - /* setup shader */ - GPU_basic_shader_colors(diffuse, NULL, 0, 1.0f); - GPU_basic_shader_bind(GPU_SHADER_LIGHTING); + ui_but_v3_get(but, light); /* transform to button */ - glPushMatrix(); - glTranslatef(rect->xmin + 0.5f * BLI_rcti_size_x(rect), rect->ymin + 0.5f * BLI_rcti_size_y(rect), 0.0f); + gpuMatrixBegin3D_legacy(); + gpuPushMatrix(); if (BLI_rcti_size_x(rect) < BLI_rcti_size_y(rect)) - size = BLI_rcti_size_x(rect) / 200.f; + size = 0.5f * BLI_rcti_size_x(rect); else - size = BLI_rcti_size_y(rect) / 200.f; - - glScalef(size, size, MIN2(size, 1.0f)); - - if (displist == 0) { - GLUquadricObj *qobj; + size = 0.5f * BLI_rcti_size_y(rect); - displist = glGenLists(1); - glNewList(displist, GL_COMPILE); - - qobj = gluNewQuadric(); - gluQuadricDrawStyle(qobj, GLU_FILL); - GPU_basic_shader_bind(GPU_basic_shader_bound_options()); - gluSphere(qobj, 100.0, 32, 24); - gluDeleteQuadric(qobj); - - glEndList(); - } + gpuTranslate3f(rect->xmin + 0.5f * BLI_rcti_size_x(rect), rect->ymin + 0.5f * BLI_rcti_size_y(rect), 0.0f); + gpuScale3f(size, size, size); - glCallList(displist); + Batch *sphere = Batch_get_sphere(2); + Batch_set_builtin_program(sphere, GPU_SHADER_SIMPLE_LIGHTING); + Batch_Uniform4f(sphere, "color", diffuse[0], diffuse[1], diffuse[2], 1.0f); + Batch_Uniform3fv(sphere, "light", light); + Batch_draw(sphere); /* restore */ - GPU_basic_shader_bind(GPU_SHADER_USE_COLOR); - GPU_default_lights(); glDisable(GL_CULL_FACE); /* AA circle */ + VertexFormat *format = immVertexFormat(); + unsigned int pos = add_attrib(format, "pos", GL_FLOAT, 2, KEEP_FLOAT); + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + immUniformColor3ubv((unsigned char *)wcol->inner); + glEnable(GL_BLEND); glEnable(GL_LINE_SMOOTH); - glColor3ubv((unsigned char *)wcol->inner); - glutil_draw_lined_arc(0.0f, M_PI * 2.0, 100.0f, 32); + imm_draw_lined_circle(pos, 0.0f, 0.0f, 1.0f, 32); glDisable(GL_BLEND); glDisable(GL_LINE_SMOOTH); /* matrix after circle */ - glPopMatrix(); + gpuPopMatrix(); + gpuMatrixEnd(); - /* We disabled all blender lights above, so restore them here. */ - GPU_default_lights(); + immUnbindProgram(); } -static void ui_draw_but_curve_grid(const rcti *rect, float zoomx, float zoomy, float offsx, float offsy, float step) +static void ui_draw_but_curve_grid(unsigned int pos, const rcti *rect, float zoomx, float zoomy, float offsx, float offsy, float step) { - glBegin(GL_LINES); float dx = step * zoomx; float fx = rect->xmin + zoomx * (-offsx); if (fx > rect->xmin) fx -= dx * (floorf(fx - rect->xmin)); - while (fx < rect->xmax) { - glVertex2f(fx, rect->ymin); - glVertex2f(fx, rect->ymax); - fx += dx; - } float dy = step * zoomy; float fy = rect->ymin + zoomy * (-offsy); if (fy > rect->ymin) fy -= dy * (floorf(fy - rect->ymin)); + + float line_count = floorf((rect->xmax - fx) / dx) + 1.0f + + floorf((rect->ymax - fy) / dy) + 1.0f; + + immBegin(GL_LINES, (int)line_count * 2); + while (fx < rect->xmax) { + immVertex2f(pos, fx, rect->ymin); + immVertex2f(pos, fx, rect->ymax); + fx += dx; + } while (fy < rect->ymax) { - glVertex2f(rect->xmin, fy); - glVertex2f(rect->xmax, fy); + immVertex2f(pos, rect->xmin, fy); + immVertex2f(pos, rect->xmax, fy); fy += dy; } - glEnd(); + immEnd(); } static void gl_shaded_color(unsigned char *col, int shade) { - glColor3ub(col[0] - shade > 0 ? col[0] - shade : 0, - col[1] - shade > 0 ? col[1] - shade : 0, - col[2] - shade > 0 ? col[2] - shade : 0); + immUniformColor3ub(col[0] - shade > 0 ? col[0] - shade : 0, + col[1] - shade > 0 ? col[1] - shade : 0, + col[2] - shade > 0 ? col[2] - shade : 0); } void ui_draw_but_CURVE(ARegion *ar, uiBut *but, uiWidgetColors *wcol, const rcti *rect) @@ -1324,10 +1478,8 @@ void ui_draw_but_CURVE(ARegion *ar, uiBut *but, uiWidgetColors *wcol, const rcti float zoomy = (BLI_rcti_size_y(rect) - 2.0f) / BLI_rctf_size_y(&cumap->curr); float offsx = cumap->curr.xmin - (1.0f / zoomx); float offsy = cumap->curr.ymin - (1.0f / zoomy); - - glLineWidth(1.0f); - /* backdrop */ + /* Do this first to not mess imm context */ if (but->a1 == UI_GRAD_H) { /* magic trigger for curve backgrounds */ float col[3] = {0.0f, 0.0f, 0.0f}; /* dummy arg */ @@ -1340,96 +1492,105 @@ void ui_draw_but_CURVE(ARegion *ar, uiBut *but, uiWidgetColors *wcol, const rcti }; ui_draw_gradient(&grid, col, UI_GRAD_H, 1.0f); + } + + glLineWidth(1.0f); + + VertexFormat *format = immVertexFormat(); + unsigned int pos = add_attrib(format, "pos", GL_FLOAT, 2, KEEP_FLOAT); + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + /* backdrop */ + if (but->a1 == UI_GRAD_H) { /* grid, hsv uses different grid */ glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - glColor4ub(0, 0, 0, 48); - ui_draw_but_curve_grid(rect, zoomx, zoomy, offsx, offsy, 0.1666666f); + immUniformColor4ub(0, 0, 0, 48); + ui_draw_but_curve_grid(pos, rect, zoomx, zoomy, offsx, offsy, 0.1666666f); glDisable(GL_BLEND); } else { if (cumap->flag & CUMA_DO_CLIP) { gl_shaded_color((unsigned char *)wcol->inner, -20); - glRectf(rect->xmin, rect->ymin, rect->xmax, rect->ymax); - glColor3ubv((unsigned char *)wcol->inner); - glRectf(rect->xmin + zoomx * (cumap->clipr.xmin - offsx), - rect->ymin + zoomy * (cumap->clipr.ymin - offsy), - rect->xmin + zoomx * (cumap->clipr.xmax - offsx), - rect->ymin + zoomy * (cumap->clipr.ymax - offsy)); + immRectf(pos, rect->xmin, rect->ymin, rect->xmax, rect->ymax); + immUniformColor3ubv((unsigned char *)wcol->inner); + immRectf(pos, rect->xmin + zoomx * (cumap->clipr.xmin - offsx), + rect->ymin + zoomy * (cumap->clipr.ymin - offsy), + rect->xmin + zoomx * (cumap->clipr.xmax - offsx), + rect->ymin + zoomy * (cumap->clipr.ymax - offsy)); } else { - glColor3ubv((unsigned char *)wcol->inner); - glRectf(rect->xmin, rect->ymin, rect->xmax, rect->ymax); + immUniformColor3ubv((unsigned char *)wcol->inner); + immRectf(pos, rect->xmin, rect->ymin, rect->xmax, rect->ymax); } /* grid, every 0.25 step */ gl_shaded_color((unsigned char *)wcol->inner, -16); - ui_draw_but_curve_grid(rect, zoomx, zoomy, offsx, offsy, 0.25f); + ui_draw_but_curve_grid(pos, rect, zoomx, zoomy, offsx, offsy, 0.25f); /* grid, every 1.0 step */ gl_shaded_color((unsigned char *)wcol->inner, -24); - ui_draw_but_curve_grid(rect, zoomx, zoomy, offsx, offsy, 1.0f); + ui_draw_but_curve_grid(pos, rect, zoomx, zoomy, offsx, offsy, 1.0f); /* axes */ gl_shaded_color((unsigned char *)wcol->inner, -50); - glBegin(GL_LINES); - glVertex2f(rect->xmin, rect->ymin + zoomy * (-offsy)); - glVertex2f(rect->xmax, rect->ymin + zoomy * (-offsy)); - glVertex2f(rect->xmin + zoomx * (-offsx), rect->ymin); - glVertex2f(rect->xmin + zoomx * (-offsx), rect->ymax); - glEnd(); + immBegin(GL_LINES, 4); + immVertex2f(pos, rect->xmin, rect->ymin + zoomy * (-offsy)); + immVertex2f(pos, rect->xmax, rect->ymin + zoomy * (-offsy)); + immVertex2f(pos, rect->xmin + zoomx * (-offsx), rect->ymin); + immVertex2f(pos, rect->xmin + zoomx * (-offsx), rect->ymax); + immEnd(); } /* cfra option */ /* XXX 2.48 */ #if 0 if (cumap->flag & CUMA_DRAW_CFRA) { - glColor3ub(0x60, 0xc0, 0x40); - glBegin(GL_LINES); - glVertex2f(rect->xmin + zoomx * (cumap->sample[0] - offsx), rect->ymin); - glVertex2f(rect->xmin + zoomx * (cumap->sample[0] - offsx), rect->ymax); - glEnd(); + immUniformColor3ub(0x60, 0xc0, 0x40); + immBegin(GL_LINES, 2); + immVertex2f(pos, rect->xmin + zoomx * (cumap->sample[0] - offsx), rect->ymin); + immVertex2f(pos, rect->xmin + zoomx * (cumap->sample[0] - offsx), rect->ymax); + immEnd(); } #endif /* sample option */ if (cumap->flag & CUMA_DRAW_SAMPLE) { - glBegin(GL_LINES); /* will draw one of the following 3 lines */ + immBegin(GL_LINES, 2); /* will draw one of the following 3 lines */ if (but->a1 == UI_GRAD_H) { float tsample[3]; float hsv[3]; linearrgb_to_srgb_v3_v3(tsample, cumap->sample); rgb_to_hsv_v(tsample, hsv); - glColor3ub(240, 240, 240); + immUniformColor3ub(240, 240, 240); - glVertex2f(rect->xmin + zoomx * (hsv[0] - offsx), rect->ymin); - glVertex2f(rect->xmin + zoomx * (hsv[0] - offsx), rect->ymax); + immVertex2f(pos, rect->xmin + zoomx * (hsv[0] - offsx), rect->ymin); + immVertex2f(pos, rect->xmin + zoomx * (hsv[0] - offsx), rect->ymax); } else if (cumap->cur == 3) { float lum = IMB_colormanagement_get_luminance(cumap->sample); - glColor3ub(240, 240, 240); + immUniformColor3ub(240, 240, 240); - glVertex2f(rect->xmin + zoomx * (lum - offsx), rect->ymin); - glVertex2f(rect->xmin + zoomx * (lum - offsx), rect->ymax); + immVertex2f(pos, rect->xmin + zoomx * (lum - offsx), rect->ymin); + immVertex2f(pos, rect->xmin + zoomx * (lum - offsx), rect->ymax); } else { if (cumap->cur == 0) - glColor3ub(240, 100, 100); + immUniformColor3ub(240, 100, 100); else if (cumap->cur == 1) - glColor3ub(100, 240, 100); + immUniformColor3ub(100, 240, 100); else - glColor3ub(100, 100, 240); + immUniformColor3ub(100, 100, 240); - glVertex2f(rect->xmin + zoomx * (cumap->sample[cumap->cur] - offsx), rect->ymin); - glVertex2f(rect->xmin + zoomx * (cumap->sample[cumap->cur] - offsx), rect->ymax); + immVertex2f(pos, rect->xmin + zoomx * (cumap->sample[cumap->cur] - offsx), rect->ymin); + immVertex2f(pos, rect->xmin + zoomx * (cumap->sample[cumap->cur] - offsx), rect->ymax); } - glEnd(); + immEnd(); } /* the curve */ - glColor3ubv((unsigned char *)wcol->item); + immUniformColor3ubv((unsigned char *)wcol->item); glEnable(GL_LINE_SMOOTH); glEnable(GL_BLEND); - glBegin(GL_LINE_STRIP); + immBegin(GL_LINE_STRIP, (CM_TABLE+1) + 2); if (cuma->table == NULL) curvemapping_changed(cumap, false); @@ -1438,52 +1599,67 @@ void ui_draw_but_CURVE(ARegion *ar, uiBut *but, uiWidgetColors *wcol, const rcti /* first point */ if ((cuma->flag & CUMA_EXTEND_EXTRAPOLATE) == 0) { - glVertex2f(rect->xmin, rect->ymin + zoomy * (cmp[0].y - offsy)); + immVertex2f(pos, rect->xmin, rect->ymin + zoomy * (cmp[0].y - offsy)); } else { float fx = rect->xmin + zoomx * (cmp[0].x - offsx + cuma->ext_in[0]); float fy = rect->ymin + zoomy * (cmp[0].y - offsy + cuma->ext_in[1]); - glVertex2f(fx, fy); + immVertex2f(pos, fx, fy); } for (int a = 0; a <= CM_TABLE; a++) { float fx = rect->xmin + zoomx * (cmp[a].x - offsx); float fy = rect->ymin + zoomy * (cmp[a].y - offsy); - glVertex2f(fx, fy); + immVertex2f(pos, fx, fy); } /* last point */ if ((cuma->flag & CUMA_EXTEND_EXTRAPOLATE) == 0) { - glVertex2f(rect->xmax, rect->ymin + zoomy * (cmp[CM_TABLE].y - offsy)); + immVertex2f(pos, rect->xmax, rect->ymin + zoomy * (cmp[CM_TABLE].y - offsy)); } else { float fx = rect->xmin + zoomx * (cmp[CM_TABLE].x - offsx - cuma->ext_out[0]); float fy = rect->ymin + zoomy * (cmp[CM_TABLE].y - offsy - cuma->ext_out[1]); - glVertex2f(fx, fy); + immVertex2f(pos, fx, fy); } - glEnd(); + immEnd(); glDisable(GL_LINE_SMOOTH); glDisable(GL_BLEND); + immUnbindProgram(); /* the points, use aspect to make them visible on edges */ + format = immVertexFormat(); + pos = add_attrib(format, "pos", GL_FLOAT, 2, KEEP_FLOAT); + unsigned int col = add_attrib(format, "color", GL_FLOAT, 4, KEEP_FLOAT); + immBindBuiltinProgram(GPU_SHADER_2D_FLAT_COLOR); + cmp = cuma->curve; glPointSize(3.0f); - glBegin(GL_POINTS); + immBegin(GL_POINTS, cuma->totpoint); for (int a = 0; a < cuma->totpoint; a++) { + float color[4]; if (cmp[a].flag & CUMA_SELECT) - UI_ThemeColor(TH_TEXT_HI); + UI_GetThemeColor4fv(TH_TEXT_HI, color); else - UI_ThemeColor(TH_TEXT); + UI_GetThemeColor4fv(TH_TEXT, color); float fx = rect->xmin + zoomx * (cmp[a].x - offsx); float fy = rect->ymin + zoomy * (cmp[a].y - offsy); - glVertex2f(fx, fy); + immAttrib4fv(col, color); + immVertex2f(pos, fx, fy); } - glEnd(); + immEnd(); + immUnbindProgram(); /* restore scissortest */ glScissor(scissor[0], scissor[1], scissor[2], scissor[3]); /* outline */ - glColor3ubv((unsigned char *)wcol->outline); - fdrawbox(rect->xmin, rect->ymin, rect->xmax, rect->ymax); + format = immVertexFormat(); + pos = add_attrib(format, "pos", GL_FLOAT, 2, KEEP_FLOAT); + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + + immUniformColor3ubv((unsigned char *)wcol->outline); + imm_draw_line_box(pos, rect->xmin, rect->ymin, rect->xmax, rect->ymax); + + immUnbindProgram(); } void ui_draw_but_TRACKPREVIEW(ARegion *ar, uiBut *but, uiWidgetColors *UNUSED(wcol), const rcti *recti) @@ -1513,9 +1689,9 @@ void ui_draw_but_TRACKPREVIEW(ARegion *ar, uiBut *but, uiWidgetColors *UNUSED(wc (rect.ymax + 1) - (rect.ymin - 1)); if (scopes->track_disabled) { - glColor4f(0.7f, 0.3f, 0.3f, 0.3f); + float color[4] = {0.7f, 0.3f, 0.3f, 0.3f}; UI_draw_roundbox_corner_set(UI_CNR_ALL); - UI_draw_roundbox_gl_mode(GL_POLYGON, rect.xmin - 1, rect.ymin, rect.xmax + 1, rect.ymax + 1, 3.0f); + UI_draw_roundbox_gl_mode(GL_TRIANGLE_FAN, rect.xmin - 1, rect.ymin, rect.xmax + 1, rect.ymax + 1, 3.0f, color); ok = true; } @@ -1542,62 +1718,74 @@ void ui_draw_but_TRACKPREVIEW(ARegion *ar, uiBut *but, uiWidgetColors *UNUSED(wc } if (!ok && scopes->track_preview) { - glPushMatrix(); + gpuMatrixBegin3D_legacy(); + gpuPushMatrix(); /* draw content of pattern area */ glScissor(ar->winrct.xmin + rect.xmin, ar->winrct.ymin + rect.ymin, scissor[2], scissor[3]); if (width > 0 && height > 0) { ImBuf *drawibuf = scopes->track_preview; + float img_col[4] = {1.0f, 1.0f, 1.0f, 1.0f}; + float col_sel[4], col_outline[4]; if (scopes->use_track_mask) { - glColor4f(0.0f, 0.0f, 0.0f, 0.3f); + float color[4] = {0.0f, 0.0f, 0.0f, 0.3f}; UI_draw_roundbox_corner_set(UI_CNR_ALL); - UI_draw_roundbox_gl_mode(GL_POLYGON, rect.xmin - 1, rect.ymin, rect.xmax + 1, rect.ymax + 1, 3.0f); + UI_draw_roundbox_gl_mode(GL_TRIANGLE_FAN, rect.xmin - 1, rect.ymin, rect.xmax + 1, rect.ymax + 1, 3.0f, color); } - glaDrawPixelsSafe(rect.xmin, rect.ymin + 1, drawibuf->x, drawibuf->y, - drawibuf->x, GL_RGBA, GL_UNSIGNED_BYTE, drawibuf->rect); + immDrawPixelsTex(rect.xmin, rect.ymin + 1, drawibuf->x, drawibuf->y, GL_RGBA, GL_UNSIGNED_BYTE, GL_LINEAR, drawibuf->rect, 1.0f, 1.0f, img_col); /* draw cross for pixel position */ - glTranslatef(rect.xmin + scopes->track_pos[0], rect.ymin + scopes->track_pos[1], 0.f); + gpuTranslate3f(rect.xmin + scopes->track_pos[0], rect.ymin + scopes->track_pos[1], 0.0f); glScissor(ar->winrct.xmin + rect.xmin, ar->winrct.ymin + rect.ymin, BLI_rctf_size_x(&rect), BLI_rctf_size_y(&rect)); - GPU_basic_shader_bind_enable(GPU_SHADER_LINE); - - for (int a = 0; a < 2; a++) { - if (a == 1) { - GPU_basic_shader_bind_enable(GPU_SHADER_STIPPLE); - GPU_basic_shader_line_stipple(3, 0xAAAA); - UI_ThemeColor(TH_SEL_MARKER); + VertexFormat *format = immVertexFormat(); + unsigned int pos = add_attrib(format, "pos", GL_FLOAT, 2, KEEP_FLOAT); + unsigned int col = add_attrib(format, "color", GL_FLOAT, 4, KEEP_FLOAT); + immBindBuiltinProgram(GPU_SHADER_2D_FLAT_COLOR); + + UI_GetThemeColor4fv(TH_SEL_MARKER, col_sel); + UI_GetThemeColor4fv(TH_MARKER_OUTLINE, col_outline); + + /* Do stipple cross with geometry */ + immBegin(GL_LINES, 7*2*2); + float pos_sel[8] = {-10.0f, -7.0f, -4.0f, -1.0f, 2.0f, 5.0f, 8.0f, 11.0f}; + for (int axe = 0; axe < 2; ++axe) { + for (int i = 0; i < 7; ++i) { + float x1 = pos_sel[i] * (1 - axe); + float y1 = pos_sel[i] * axe; + float x2 = pos_sel[i+1] * (1 - axe); + float y2 = pos_sel[i+1] * axe; + + if (i % 2 == 1) + immAttrib4fv(col, col_sel); + else + immAttrib4fv(col, col_outline); + + immVertex2f(pos, x1, y1); + immVertex2f(pos, x2, y2); } - else { - UI_ThemeColor(TH_MARKER_OUTLINE); - } - - glBegin(GL_LINES); - glVertex2f(-10.0f, 0.0f); - glVertex2f(10.0f, 0.0f); - glVertex2f(0.0f, -10.0f); - glVertex2f(0.0f, 10.0f); - glEnd(); } + immEnd(); - GPU_basic_shader_bind_disable(GPU_SHADER_LINE | GPU_SHADER_STIPPLE); + immUnbindProgram(); } - glPopMatrix(); + gpuPopMatrix(); + gpuMatrixEnd(); ok = true; } if (!ok) { - glColor4f(0.f, 0.f, 0.f, 0.3f); + float color[4] = {0.0f, 0.0f, 0.0f, 0.3f}; UI_draw_roundbox_corner_set(UI_CNR_ALL); - UI_draw_roundbox_gl_mode(GL_POLYGON, rect.xmin - 1, rect.ymin, rect.xmax + 1, rect.ymax + 1, 3.0f); + UI_draw_roundbox_gl_mode(GL_TRIANGLE_FAN, rect.xmin - 1, rect.ymin, rect.xmax + 1, rect.ymax + 1, 3.0f, color); } /* outline */ @@ -1643,26 +1831,31 @@ void ui_draw_but_NODESOCKET(ARegion *ar, uiBut *but, uiWidgetColors *UNUSED(wcol BLI_rcti_size_x(&scissor_new), BLI_rcti_size_y(&scissor_new)); - glColor4ubv(but->col); - float x = 0.5f * (recti->xmin + recti->xmax); float y = 0.5f * (recti->ymin + recti->ymax); - + + VertexFormat *format = immVertexFormat(); + unsigned int pos = add_attrib(format, "pos", GL_FLOAT, 2, KEEP_FLOAT); + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + immUniformColor4ubv(but->col); + glEnable(GL_BLEND); - glBegin(GL_POLYGON); + immBegin(GL_TRIANGLE_FAN, 16); for (int a = 0; a < 16; a++) - glVertex2f(x + size * si[a], y + size * co[a]); - glEnd(); + immVertex2f(pos, x + size * si[a], y + size * co[a]); + immEnd(); - glColor4ub(0, 0, 0, 150); + immUniformColor4ub(0, 0, 0, 150); glLineWidth(1); glEnable(GL_LINE_SMOOTH); - glBegin(GL_LINE_LOOP); + immBegin(GL_LINE_LOOP, 16); for (int a = 0; a < 16; a++) - glVertex2f(x + size * si[a], y + size * co[a]); - glEnd(); + immVertex2f(pos, x + size * si[a], y + size * co[a]); + immEnd(); glDisable(GL_LINE_SMOOTH); glDisable(GL_BLEND); + + immUnbindProgram(); /* restore scissortest */ glScissor(scissor[0], scissor[1], scissor[2], scissor[3]); @@ -1671,46 +1864,54 @@ void ui_draw_but_NODESOCKET(ARegion *ar, uiBut *but, uiWidgetColors *UNUSED(wcol /* ****************************************************** */ -static void ui_shadowbox(float minx, float miny, float maxx, float maxy, float shadsize, unsigned char alpha) +static void ui_shadowbox(unsigned pos, unsigned color, float minx, float miny, float maxx, float maxy, float shadsize, unsigned char alpha) { /* right quad */ - glColor4ub(0, 0, 0, alpha); - glVertex2f(maxx, miny); - glVertex2f(maxx, maxy - 0.3f * shadsize); - glColor4ub(0, 0, 0, 0); - glVertex2f(maxx + shadsize, maxy - 0.75f * shadsize); - glVertex2f(maxx + shadsize, miny); + immAttrib4ub(color, 0, 0, 0, alpha); + immVertex2f(pos, maxx, miny); + immVertex2f(pos, maxx, maxy - 0.3f * shadsize); + immAttrib4ub(color, 0, 0, 0, 0); + immVertex2f(pos, maxx + shadsize, maxy - 0.75f * shadsize); + immVertex2f(pos, maxx + shadsize, miny); /* corner shape */ - glColor4ub(0, 0, 0, alpha); - glVertex2f(maxx, miny); - glColor4ub(0, 0, 0, 0); - glVertex2f(maxx + shadsize, miny); - glVertex2f(maxx + 0.7f * shadsize, miny - 0.7f * shadsize); - glVertex2f(maxx, miny - shadsize); + immAttrib4ub(color, 0, 0, 0, alpha); + immVertex2f(pos, maxx, miny); + immAttrib4ub(color, 0, 0, 0, 0); + immVertex2f(pos, maxx + shadsize, miny); + immVertex2f(pos, maxx + 0.7f * shadsize, miny - 0.7f * shadsize); + immVertex2f(pos, maxx, miny - shadsize); /* bottom quad */ - glColor4ub(0, 0, 0, alpha); - glVertex2f(minx + 0.3f * shadsize, miny); - glVertex2f(maxx, miny); - glColor4ub(0, 0, 0, 0); - glVertex2f(maxx, miny - shadsize); - glVertex2f(minx + 0.5f * shadsize, miny - shadsize); + immAttrib4ub(color, 0, 0, 0, alpha); + immVertex2f(pos, minx + 0.3f * shadsize, miny); + immVertex2f(pos, maxx, miny); + immAttrib4ub(color, 0, 0, 0, 0); + immVertex2f(pos, maxx, miny - shadsize); + immVertex2f(pos, minx + 0.5f * shadsize, miny - shadsize); } void UI_draw_box_shadow(unsigned char alpha, float minx, float miny, float maxx, float maxy) { glEnable(GL_BLEND); - - glBegin(GL_QUADS); + + VertexFormat *format = immVertexFormat(); + unsigned pos = add_attrib(format, "pos", GL_FLOAT, 2, KEEP_FLOAT); + unsigned color = add_attrib(format, "color", GL_UNSIGNED_BYTE, 4, NORMALIZE_INT_TO_FLOAT); + + immBindBuiltinProgram(GPU_SHADER_2D_SMOOTH_COLOR); + + immBegin(GL_QUADS, 36); /* accumulated outline boxes to make shade not linear, is more pleasant */ - ui_shadowbox(minx, miny, maxx, maxy, 11.0, (20 * alpha) >> 8); - ui_shadowbox(minx, miny, maxx, maxy, 7.0, (40 * alpha) >> 8); - ui_shadowbox(minx, miny, maxx, maxy, 5.0, (80 * alpha) >> 8); - - glEnd(); + ui_shadowbox(pos, color, minx, miny, maxx, maxy, 11.0, (20 * alpha) >> 8); + ui_shadowbox(pos, color, minx, miny, maxx, maxy, 7.0, (40 * alpha) >> 8); + ui_shadowbox(pos, color, minx, miny, maxx, maxy, 5.0, (80 * alpha) >> 8); + immEnd(); + + immUnbindProgram(); + glDisable(GL_BLEND); } @@ -1719,8 +1920,8 @@ void ui_draw_dropshadow(const rctf *rct, float radius, float aspect, float alpha { float rad; - if (radius > (BLI_rctf_size_y(rct) - 10.0f) / 2.0f) - rad = (BLI_rctf_size_y(rct) - 10.0f) / 2.0f; + if (radius > (BLI_rctf_size_y(rct) - 10.0f) * 0.5f) + rad = (BLI_rctf_size_y(rct) - 10.0f) * 0.5f; else rad = radius; @@ -1741,16 +1942,15 @@ void ui_draw_dropshadow(const rctf *rct, float radius, float aspect, float alpha float calpha = dalpha; for (; i--; a -= aspect) { /* alpha ranges from 2 to 20 or so */ - glColor4f(0.0f, 0.0f, 0.0f, calpha); + float color[4] = {0.0f, 0.0f, 0.0f, calpha}; + UI_draw_roundbox_gl_mode(GL_TRIANGLE_FAN, rct->xmin - a, rct->ymin - a, rct->xmax + a, rct->ymax - 10.0f + a, rad + a, color); calpha += dalpha; - - UI_draw_roundbox_gl_mode(GL_POLYGON, rct->xmin - a, rct->ymin - a, rct->xmax + a, rct->ymax - 10.0f + a, rad + a); } /* outline emphasis */ glEnable(GL_LINE_SMOOTH); - glColor4ub(0, 0, 0, 100); - UI_draw_roundbox_gl_mode(GL_LINE_LOOP, rct->xmin - 0.5f, rct->ymin - 0.5f, rct->xmax + 0.5f, rct->ymax + 0.5f, radius + 0.5f); + float color[4] = {0.0f, 0.0f, 0.0f, 0.4f}; + UI_draw_roundbox_gl_mode(GL_LINE_LOOP, rct->xmin - 0.5f, rct->ymin - 0.5f, rct->xmax + 0.5f, rct->ymax + 0.5f, radius + 0.5f, color); glDisable(GL_LINE_SMOOTH); glDisable(GL_BLEND); diff --git a/source/blender/editors/interface/interface_eyedropper.c b/source/blender/editors/interface/interface_eyedropper.c index 5154a77ad21..a50c0f5a4f4 100644 --- a/source/blender/editors/interface/interface_eyedropper.c +++ b/source/blender/editors/interface/interface_eyedropper.c @@ -139,8 +139,8 @@ static void eyedropper_draw_cursor_text(const struct bContext *C, ARegion *ar, c wmWindow *win = CTX_wm_window(C); int x = win->eventstate->x; int y = win->eventstate->y; - const unsigned char fg[4] = {255, 255, 255, 255}; - const unsigned char bg[4] = {0, 0, 0, 50}; + const float col_fg[4] = {1.0f, 1.0f, 1.0f, 1.0f}; + const float col_bg[4] = {0.0f, 0.0f, 0.0f, 0.2f}; if ((name[0] == '\0') || @@ -154,7 +154,7 @@ static void eyedropper_draw_cursor_text(const struct bContext *C, ARegion *ar, c y += U.widget_unit; - UI_fontstyle_draw_simple_backdrop(fstyle, x, y, name, fg, bg); + UI_fontstyle_draw_simple_backdrop(fstyle, x, y, name, col_fg, col_bg); } @@ -597,7 +597,7 @@ static void datadropper_id_sample_pt(bContext *C, DataDropper *ddr, int mx, int const int mval[2] = { mx - ar->winrct.xmin, my - ar->winrct.ymin}; - Base *base; + BaseLegacy *base; CTX_wm_area_set(C, sa); CTX_wm_region_set(C, ar); diff --git a/source/blender/editors/interface/interface_handlers.c b/source/blender/editors/interface/interface_handlers.c index 734cd02a056..9bdc4d29807 100644 --- a/source/blender/editors/interface/interface_handlers.c +++ b/source/blender/editors/interface/interface_handlers.c @@ -185,7 +185,6 @@ typedef struct uiSelectContextStore { uiSelectContextElem *elems; int elems_len; bool do_free; - bool is_enabled; /* When set, simply copy values (don't apply difference). * Rules are: * - dragging numbers uses delta. @@ -1160,14 +1159,11 @@ static void ui_multibut_states_apply(bContext *C, uiHandleButtonData *data, uiBl ui_but_execute_begin(C, ar, but, &active_back); #ifdef USE_ALLSELECT - if (data->select_others.is_enabled) { - /* init once! */ - if (mbut_state->select_others.elems_len == 0) { - ui_selectcontext_begin(C, but, &mbut_state->select_others); - } - if (mbut_state->select_others.elems_len == 0) { - mbut_state->select_others.elems_len = -1; - } + if (mbut_state->select_others.elems_len == 0) { + ui_selectcontext_begin(C, but, &mbut_state->select_others); + } + if (mbut_state->select_others.elems_len == 0) { + mbut_state->select_others.elems_len = -1; } /* needed so we apply the right deltas */ @@ -2055,12 +2051,7 @@ static void ui_apply_but(bContext *C, uiBlock *block, uiBut *but, uiHandleButton else # endif if (data->select_others.elems_len == 0) { - wmWindow *win = CTX_wm_window(C); - /* may have been enabled before activating */ - if (data->select_others.is_enabled || IS_ALLSELECT_EVENT(win->eventstate)) { - ui_selectcontext_begin(C, but, &data->select_others); - data->select_others.is_enabled = true; - } + ui_selectcontext_begin(C, but, &data->select_others); } if (data->select_others.elems_len == 0) { /* dont check again */ @@ -3061,11 +3052,7 @@ static void ui_textedit_begin(bContext *C, uiBut *but, uiHandleButtonData *data) #ifdef USE_ALLSELECT if (is_num_but) { - if (IS_ALLSELECT_EVENT(win->eventstate)) { - data->select_others.is_enabled = true; - data->select_others.is_copy = true; - - } + data->select_others.is_copy = true; } #endif @@ -3665,15 +3652,6 @@ static void ui_block_open_begin(bContext *C, uiBut *but, uiHandleButtonData *dat data->menu->popup = but->block->handle->popup; } -#ifdef USE_ALLSELECT - { - wmWindow *win = CTX_wm_window(C); - if (IS_ALLSELECT_EVENT(win->eventstate)) { - data->select_others.is_enabled = true; - } - } -#endif - /* this makes adjacent blocks auto open from now on */ //if (but->block->auto_open == 0) but->block->auto_open = 1; } diff --git a/source/blender/editors/interface/interface_icons.c b/source/blender/editors/interface/interface_icons.c index 65b12fcd64e..d6dcd0208f4 100644 --- a/source/blender/editors/interface/interface_icons.c +++ b/source/blender/editors/interface/interface_icons.c @@ -35,6 +35,8 @@ #include "GPU_extensions.h" #include "GPU_basic_shader.h" +#include "GPU_draw.h" +#include "GPU_immediate.h" #include "BLI_blenlib.h" #include "BLI_utildefines.h" @@ -59,7 +61,6 @@ #include "IMB_imbuf_types.h" #include "IMB_thumbs.h" -#include "BIF_gl.h" #include "BIF_glutil.h" #include "ED_datafiles.h" @@ -224,13 +225,17 @@ static void vicon_small_tri_right_draw(int x, int y, int w, int UNUSED(h), float viconutil_set_point(pts[1], cx - d2, cy - d); viconutil_set_point(pts[2], cx + d2, cy); - glColor4f(0.2f, 0.2f, 0.2f, alpha); + unsigned int pos = add_attrib(immVertexFormat(), "pos", COMP_I32, 2, CONVERT_INT_TO_FLOAT); + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + immUniformColor4f(0.2f, 0.2f, 0.2f, alpha); - glBegin(GL_TRIANGLES); - glVertex2iv(pts[0]); - glVertex2iv(pts[1]); - glVertex2iv(pts[2]); - glEnd(); + immBegin(PRIM_TRIANGLES, 3); + immVertex2iv(pos, pts[0]); + immVertex2iv(pos, pts[1]); + immVertex2iv(pos, pts[2]); + immEnd(); + + immUnbindProgram(); } static void vicon_keytype_draw_wrapper(int x, int y, int w, int h, float alpha, short key_type) @@ -239,7 +244,6 @@ static void vicon_keytype_draw_wrapper(int x, int y, int w, int h, float alpha, * (since we're doing this offscreen, free from any particular space_id) */ struct bThemeState theme_state; - int xco, yco; UI_Theme_Store(&theme_state); UI_SetTheme(SPACE_ACTION, RGN_TYPE_WINDOW); @@ -248,16 +252,30 @@ static void vicon_keytype_draw_wrapper(int x, int y, int w, int h, float alpha, * while the draw_keyframe_shape() function needs the midpoint for * the keyframe */ - xco = x + w / 2; - yco = y + h / 2; + int xco = x + w / 2; + int yco = y + h / 2; + + VertexFormat *format = immVertexFormat(); + unsigned int pos_id = add_attrib(format, "pos", COMP_F32, 2, KEEP_FLOAT); + unsigned int size_id = add_attrib(format, "size", COMP_F32, 1, KEEP_FLOAT); + unsigned int color_id = add_attrib(format, "color", COMP_U8, 4, NORMALIZE_INT_TO_FLOAT); + unsigned int outline_color_id = add_attrib(format, "outlineColor", COMP_U8, 4, NORMALIZE_INT_TO_FLOAT); + + immBindBuiltinProgram(GPU_SHADER_KEYFRAME_DIAMOND); + GPU_enable_program_point_size(); + immBegin(PRIM_POINTS, 1); /* draw keyframe - * - xscale: 1.0 (since there's no timeline scaling to compensate for) - * - yscale: 0.3 * h (found out experimentally... dunno why!) + * - size: 0.3 * h (found out experimentally... dunno why!) * - sel: true (so that "keyframe" state shows the iconic yellow icon) */ - draw_keyframe_shape(xco, yco, 1.0f, 0.3f * h, true, key_type, KEYFRAME_SHAPE_BOTH, alpha); - + draw_keyframe_shape(xco, yco, 0.3f * h, true, key_type, KEYFRAME_SHAPE_BOTH, alpha, + pos_id, size_id, color_id, outline_color_id); + + immEnd(); + GPU_disable_program_point_size(); + immUnbindProgram(); + UI_Theme_Restore(&theme_state); } @@ -290,7 +308,7 @@ static void vicon_colorset_draw(int index, int x, int y, int w, int h, float UNU { bTheme *btheme = UI_GetTheme(); ThemeWireColor *cs = &btheme->tarm[index]; - + /* Draw three bands of color: One per color * x-----a-----b-----c * | N | S | A | @@ -299,19 +317,24 @@ static void vicon_colorset_draw(int index, int x, int y, int w, int h, float UNU const int a = x + w / 3; const int b = x + w / 3 * 2; const int c = x + w; - + + unsigned int pos = add_attrib(immVertexFormat(), "pos", COMP_I32, 2, CONVERT_INT_TO_FLOAT); + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + /* XXX: Include alpha into this... */ /* normal */ - glColor3ubv((unsigned char *)cs->solid); - glRecti(x, y, a, y + h); - + immUniformColor3ubv((unsigned char *)cs->solid); + immRecti(pos, x, y, a, y + h); + /* selected */ - glColor3ubv((unsigned char *)cs->select); - glRecti(a, y, b, y + h); - + immUniformColor3ubv((unsigned char *)cs->select); + immRecti(pos, a, y, b, y + h); + /* active */ - glColor3ubv((unsigned char *)cs->active); - glRecti(b, y, c, y + h); + immUniformColor3ubv((unsigned char *)cs->active); + immRecti(pos, b, y, c, y + h); + + immUnbindProgram(); } #define DEF_VICON_COLORSET_DRAW_NTH(prefix, index) \ @@ -504,8 +527,12 @@ static void init_internal_icons(void) icongltex.id = 0; } +#if 0 /* should be a compile-time check (if needed at all) */ /* we only use a texture for cards with non-power of two */ if (GPU_full_non_power_of_two_support()) { +#else + { +#endif glGenTextures(1, &icongltex.id); if (icongltex.id) { @@ -533,11 +560,6 @@ static void init_internal_icons(void) glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glBindTexture(GL_TEXTURE_2D, 0); - - if (glGetError() == GL_OUT_OF_MEMORY) { - glDeleteTextures(1, &icongltex.id); - icongltex.id = 0; - } } } } @@ -851,12 +873,15 @@ void ui_icon_ensure_deferred(const bContext *C, const int icon_id, const bool bi { ID *id = (icon->type != 0) ? icon->obj : NULL; PreviewImage *prv = id ? BKE_previewimg_id_ensure(id) : icon->obj; + /* Using jobs for screen previews crashes due to offscreen rendering. + * XXX would be nicer if PreviewImage could store if it supports jobs */ + const bool use_jobs = !id || (GS(id->name) != ID_SCR); if (prv) { const int size = big ? ICON_SIZE_PREVIEW : ICON_SIZE_ICON; if (id || (prv->tag & PRV_TAG_DEFFERED) != 0) { - ui_id_preview_image_render_size(C, NULL, id, prv, size, true); + ui_id_preview_image_render_size(C, NULL, id, prv, size, use_jobs); } } break; @@ -1017,33 +1042,40 @@ static void icon_draw_texture( { float x1, x2, y1, y2; - if (rgb) glColor4f(rgb[0], rgb[1], rgb[2], alpha); - else glColor4f(alpha, alpha, alpha, alpha); - x1 = ix * icongltex.invw; x2 = (ix + ih) * icongltex.invw; y1 = iy * icongltex.invh; y2 = (iy + ih) * icongltex.invh; - GPU_basic_shader_bind(GPU_SHADER_TEXTURE_2D | GPU_SHADER_USE_COLOR); - glBindTexture(GL_TEXTURE_2D, icongltex.id); - /* sharper downscaling, has no effect when scale matches with a mip level */ glTexEnvf(GL_TEXTURE_FILTER_CONTROL, GL_TEXTURE_LOD_BIAS, -0.5f); - glBegin(GL_QUADS); - glTexCoord2f(x1, y1); - glVertex2f(x, y); + glBindTexture(GL_TEXTURE_2D, icongltex.id); + VertexFormat *format = immVertexFormat(); + unsigned int pos = add_attrib(format, "pos", GL_FLOAT, 2, KEEP_FLOAT); + unsigned int texCoord = add_attrib(format, "texCoord", GL_FLOAT, 2, KEEP_FLOAT); + + immBindBuiltinProgram(GPU_SHADER_2D_IMAGE_COLOR); + if (rgb) immUniformColor3fvAlpha(rgb, alpha); + else immUniformColor4f(alpha, alpha, alpha, alpha); - glTexCoord2f(x2, y1); - glVertex2f(x + w, y); + immUniform1i("image", 0); - glTexCoord2f(x2, y2); - glVertex2f(x + w, y + h); + immBegin(GL_TRIANGLE_STRIP, 4); + immAttrib2f(texCoord, x1, y2); + immVertex2f(pos, x, y + h); - glTexCoord2f(x1, y2); - glVertex2f(x, y + h); - glEnd(); + immAttrib2f(texCoord, x1, y1); + immVertex2f(pos, x, y); + + immAttrib2f(texCoord, x2, y2); + immVertex2f(pos, x + w, y + h); + + immAttrib2f(texCoord, x2, y1); + immVertex2f(pos, x + w, y); + immEnd(); + + immUnbindProgram(); glTexEnvf(GL_TEXTURE_FILTER_CONTROL, GL_TEXTURE_LOD_BIAS, 0.0f); @@ -1162,7 +1194,7 @@ void UI_id_icon_render(const bContext *C, Scene *scene, ID *id, const bool big, } } -static void ui_id_brush_render(const bContext *C, ID *id) +static void ui_id_icon_render(const bContext *C, ID *id, bool use_jobs) { PreviewImage *pi = BKE_previewimg_id_ensure(id); enum eIconSizes i; @@ -1174,7 +1206,7 @@ static void ui_id_brush_render(const bContext *C, ID *id) /* check if rect needs to be created; changed * only set by dynamic icons */ if (((pi->flag[i] & PRV_CHANGED) || !pi->rect[i])) { - icon_set_image(C, NULL, id, pi, i, true); + icon_set_image(C, NULL, id, pi, i, use_jobs); pi->flag[i] &= ~PRV_CHANGED; } } @@ -1187,7 +1219,7 @@ static int ui_id_brush_get_icon(const bContext *C, ID *id) if (br->flag & BRUSH_CUSTOM_ICON) { BKE_icon_id_ensure(id); - ui_id_brush_render(C, id); + ui_id_icon_render(C, id, true); } else { Object *ob = CTX_data_active_object(C); @@ -1234,6 +1266,15 @@ static int ui_id_brush_get_icon(const bContext *C, ID *id) return id->icon_id; } +static int ui_id_screen_get_icon(const bContext *C, ID *id) +{ + BKE_icon_id_ensure(id); + /* Don't use jobs here, offscreen rendering doesn't like this and crashes. */ + ui_id_icon_render(C, id, false); + + return id->icon_id; +} + int ui_id_icon_get(const bContext *C, ID *id, const bool big) { int iconid = 0; @@ -1252,6 +1293,9 @@ int ui_id_icon_get(const bContext *C, ID *id, const bool big) /* checks if not exists, or changed */ UI_id_icon_render(C, NULL, id, big, true); break; + case ID_SCR: + iconid = ui_id_screen_get_icon(C, id); + break; default: break; } @@ -1388,6 +1432,11 @@ void UI_icon_draw(float x, float y, int icon_id) UI_icon_draw_aspect(x, y, icon_id, 1.0f / UI_DPI_FAC, 1.0f); } +void UI_icon_draw_alpha(float x, float y, int icon_id, float alpha) +{ + UI_icon_draw_aspect(x, y, icon_id, 1.0f / UI_DPI_FAC, alpha); +} + void UI_icon_draw_size(float x, float y, int size, int icon_id, float alpha) { icon_draw_size(x, y, icon_id, 1.0f, alpha, NULL, ICON_SIZE_ICON, size, true, false); diff --git a/source/blender/editors/interface/interface_intern.h b/source/blender/editors/interface/interface_intern.h index d8f9fdcbaae..9179f8039cd 100644 --- a/source/blender/editors/interface/interface_intern.h +++ b/source/blender/editors/interface/interface_intern.h @@ -681,15 +681,16 @@ struct wmIMEData *ui_but_ime_data_get(uiBut *but); #endif /* interface_widgets.c */ -void ui_draw_anti_tria(float x1, float y1, float x2, float y2, float x3, float y3); -void ui_draw_anti_roundbox(int mode, float minx, float miny, float maxx, float maxy, float rad, bool use_alpha); +void ui_draw_anti_tria(float x1, float y1, float x2, float y2, float x3, float y3, const float color[4]); +void ui_draw_anti_roundbox(int mode, float minx, float miny, float maxx, float maxy, + float rad, bool use_alpha, const float color[4]); void ui_draw_menu_back(struct uiStyle *style, uiBlock *block, rcti *rect); void ui_draw_pie_center(uiBlock *block); uiWidgetColors *ui_tooltip_get_theme(void); void ui_draw_tooltip_background(uiStyle *UNUSED(style), uiBlock *block, rcti *rect); void ui_draw_search_back(struct uiStyle *style, uiBlock *block, rcti *rect); bool ui_link_bezier_points(const rcti *rect, float coord_array[][2], int resol); -void ui_draw_link_bezier(const rcti *rect); +void ui_draw_link_bezier(const rcti *rect, const float color[4]); extern void ui_draw_but(const struct bContext *C, ARegion *ar, struct uiStyle *style, uiBut *but, rcti *rect); /* theme color init */ diff --git a/source/blender/editors/interface/interface_panel.c b/source/blender/editors/interface/interface_panel.c index c131bcb8e14..bd8fa682c49 100644 --- a/source/blender/editors/interface/interface_panel.c +++ b/source/blender/editors/interface/interface_panel.c @@ -65,6 +65,8 @@ #include "UI_interface_icons.h" #include "UI_resources.h" +#include "GPU_immediate.h" + #include "interface_intern.h" /*********************** defines and structs ************************/ @@ -410,37 +412,40 @@ static void uiPanelPop(uiBlock *UNUSED(block)) #endif /* triangle 'icon' for panel header */ -void UI_draw_icon_tri(float x, float y, char dir) +void UI_draw_icon_tri(float x, float y, char dir, const float color[4]) { float f3 = 0.15 * U.widget_unit; float f5 = 0.25 * U.widget_unit; float f7 = 0.35 * U.widget_unit; if (dir == 'h') { - ui_draw_anti_tria(x - f3, y - f5, x - f3, y + f5, x + f7, y); + ui_draw_anti_tria(x - f3, y - f5, x - f3, y + f5, x + f7, y, color); } else if (dir == 't') { - ui_draw_anti_tria(x - f5, y - f7, x + f5, y - f7, x, y + f3); + ui_draw_anti_tria(x - f5, y - f7, x + f5, y - f7, x, y + f3, color); } else { /* 'v' = vertical, down */ - ui_draw_anti_tria(x - f5, y + f3, x + f5, y + f3, x, y - f7); + ui_draw_anti_tria(x - f5, y + f3, x + f5, y + f3, x, y - f7, color); } } /* triangle 'icon' inside rect */ static void ui_draw_tria_rect(const rctf *rect, char dir) { + float color[4]; + UI_GetThemeColor4fv(TH_TITLE, color); + if (dir == 'h') { float half = 0.5f * BLI_rctf_size_y(rect); - ui_draw_anti_tria(rect->xmin, rect->ymin, rect->xmin, rect->ymax, rect->xmax, rect->ymin + half); + ui_draw_anti_tria(rect->xmin, rect->ymin, rect->xmin, rect->ymax, rect->xmax, rect->ymin + half, color); } else { float half = 0.5f * BLI_rctf_size_x(rect); - ui_draw_anti_tria(rect->xmin, rect->ymax, rect->xmax, rect->ymax, rect->xmin + half, rect->ymin); + ui_draw_anti_tria(rect->xmin, rect->ymax, rect->xmax, rect->ymax, rect->xmin + half, rect->ymin, color); } } -static void ui_draw_anti_x(float x1, float y1, float x2, float y2) +static void ui_draw_anti_x(unsigned int pos, float x1, float y1, float x2, float y2) { /* set antialias line */ @@ -448,9 +453,16 @@ static void ui_draw_anti_x(float x1, float y1, float x2, float y2) glEnable(GL_BLEND); glLineWidth(2.0); - - fdrawline(x1, y1, x2, y2); - fdrawline(x1, y2, x2, y1); + + immBegin(GL_LINES, 4); + + immVertex2f(pos, x1, y1); + immVertex2f(pos, x2, y2); + + immVertex2f(pos, x1, y2); + immVertex2f(pos, x2, y1); + + immEnd(); glDisable(GL_LINE_SMOOTH); glDisable(GL_BLEND); @@ -458,16 +470,16 @@ static void ui_draw_anti_x(float x1, float y1, float x2, float y2) } /* x 'icon' for panel header */ -static void ui_draw_x_icon(float x, float y) +static void ui_draw_x_icon(unsigned int pos, float x, float y) { - ui_draw_anti_x(x, y, x + 9.375f, y + 9.375f); + ui_draw_anti_x(pos, x, y, x + 9.375f, y + 9.375f); } #define PNL_ICON UI_UNIT_X /* could be UI_UNIT_Y too */ -static void ui_draw_panel_scalewidget(const rcti *rect) +static void ui_draw_panel_scalewidget(unsigned int pos, const rcti *rect) { float xmin, xmax, dx; float ymin, ymax, dy; @@ -481,16 +493,33 @@ static void ui_draw_panel_scalewidget(const rcti *rect) dy = 0.5f * (ymax - ymin); glEnable(GL_BLEND); - glColor4ub(255, 255, 255, 50); - fdrawline(xmin, ymin, xmax, ymax); - fdrawline(xmin + dx, ymin, xmax, ymax - dy); + immUniformColor4ub(255, 255, 255, 50); + + immBegin(GL_LINES, 4); + + immVertex2f(pos, xmin, ymin); + immVertex2f(pos, xmax, ymax); + + immVertex2f(pos, xmin + dx, ymin); + immVertex2f(pos, xmax, ymax - dy); + + immEnd(); - glColor4ub(0, 0, 0, 50); - fdrawline(xmin, ymin + 1, xmax, ymax + 1); - fdrawline(xmin + dx, ymin + 1, xmax, ymax - dy + 1); + immUniformColor4ub(0, 0, 0, 50); + + immBegin(GL_LINES, 4); + + immVertex2f(pos, xmin, ymin + 1); + immVertex2f(pos, xmax, ymax + 1); + + immVertex2f(pos, xmin + dx, ymin + 1); + immVertex2f(pos, xmax, ymax - dy + 1); + + immEnd(); + glDisable(GL_BLEND); } -static void ui_draw_panel_dragwidget(const rctf *rect) +static void ui_draw_panel_dragwidget(unsigned int pos, const rctf *rect) { unsigned char col_back[3], col_high[3], col_dark[3]; const int col_tint = 84; @@ -519,10 +548,10 @@ static void ui_draw_panel_dragwidget(const rctf *rect) const int x_co = (x_min + x_ofs) + (i_x * (box_size + box_margin)); const int y_co = (y_min + y_ofs) + (i_y * (box_size + box_margin)); - glColor3ubv(col_dark); - glRectf(x_co - box_size, y_co - px_zoom, x_co, (y_co + box_size) - px_zoom); - glColor3ubv(col_high); - glRectf(x_co - box_size, y_co, x_co, y_co + box_size); + immUniformColor3ubv(col_dark); + immRectf(pos, x_co - box_size, y_co - px_zoom, x_co, (y_co + box_size) - px_zoom); + immUniformColor3ubv(col_high); + immRectf(pos, x_co - box_size, y_co, x_co, y_co + box_size); } } } @@ -534,29 +563,29 @@ static void ui_draw_aligned_panel_header(uiStyle *style, uiBlock *block, const r rcti hrect; int pnl_icons; const char *activename = panel->drawname[0] ? panel->drawname : panel->panelname; + unsigned char col_title[4]; /* + 0.001f to avoid flirting with float inaccuracy */ if (panel->control & UI_PNL_CLOSE) pnl_icons = (panel->labelofs + 2 * PNL_ICON + 5) / block->aspect + 0.001f; else pnl_icons = (panel->labelofs + PNL_ICON + 5) / block->aspect + 0.001f; - - /* active tab */ + /* draw text label */ - UI_ThemeColor(TH_TITLE); - + UI_GetThemeColor4ubv(TH_TITLE, col_title); + hrect = *rect; if (dir == 'h') { hrect.xmin = rect->xmin + pnl_icons; hrect.ymin += 2.0f / block->aspect; - UI_fontstyle_draw(&style->paneltitle, &hrect, activename); + UI_fontstyle_draw(&style->paneltitle, &hrect, activename, col_title); } else { /* ignore 'pnl_icons', otherwise the text gets offset horizontally * + 0.001f to avoid flirting with float inaccuracy */ hrect.xmin = rect->xmin + (PNL_ICON + 5) / block->aspect + 0.001f; - UI_fontstyle_draw_rotated(&style->paneltitle, &hrect, activename); + UI_fontstyle_draw_rotated(&style->paneltitle, &hrect, activename, col_title); } } @@ -567,6 +596,7 @@ void ui_draw_aligned_panel(uiStyle *style, uiBlock *block, const rcti *rect, con rcti headrect; rctf itemrect; int ofsx; + float color[4]; const bool is_closed_x = (panel->flag & PNL_CLOSEDX) ? true : false; const bool is_closed_y = (panel->flag & PNL_CLOSEDY) ? true : false; @@ -579,6 +609,9 @@ void ui_draw_aligned_panel(uiStyle *style, uiBlock *block, const rcti *rect, con headrect.ymin = headrect.ymax; headrect.ymax = headrect.ymin + floor(PNL_HEADER / block->aspect + 0.001f); + unsigned int pos = add_attrib(immVertexFormat(), "pos", GL_FLOAT, 2, KEEP_FLOAT); + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + { float minx = rect->xmin; float maxx = is_closed_x ? (minx + PNL_HEADER / block->aspect) : rect->xmax; @@ -588,11 +621,18 @@ void ui_draw_aligned_panel(uiStyle *style, uiBlock *block, const rcti *rect, con if (UI_GetThemeValue(TH_PANEL_SHOW_HEADER)) { /* draw with background color */ - UI_ThemeColor4(TH_PANEL_HEADER); - glRectf(minx, headrect.ymin + 1, maxx, y); + immUniformThemeColor(TH_PANEL_HEADER); + immRectf(pos, minx, headrect.ymin + 1, maxx, y); + + immBegin(GL_LINES, 4); + + immVertex2f(pos, minx, y); + immVertex2f(pos, maxx, y); - fdrawline(minx, y, maxx, y); - fdrawline(minx, y, maxx, y); + immVertex2f(pos, minx, y); + immVertex2f(pos, maxx, y); + + immEnd(); } else if (!(panel->runtime_flag & PNL_FIRST)) { /* draw embossed separator */ @@ -602,15 +642,26 @@ void ui_draw_aligned_panel(uiStyle *style, uiBlock *block, const rcti *rect, con maxx -= 5.0f / block->aspect; } - glColor4f(0.0f, 0.0f, 0.0f, 0.5f); - fdrawline(minx, y, maxx, y); - glColor4f(1.0f, 1.0f, 1.0f, 0.25f); - fdrawline(minx, y - 1, maxx, y - 1); + immUniformColor4f(0.0f, 0.0f, 0.0f, 0.5f); + + immBegin(GL_LINES, 2); + immVertex2f(pos, minx, y); + immVertex2f(pos, maxx, y); + immEnd(); + + immUniformColor4f(1.0f, 1.0f, 1.0f, 0.25f); + + immBegin(GL_LINES, 2); + immVertex2f(pos, minx, y - 1); + immVertex2f(pos, maxx, y - 1); + immEnd(); } glDisable(GL_BLEND); } + immUnbindProgram(); + /* draw optional pin icon */ #ifdef USE_PIN_HIDDEN @@ -626,9 +677,11 @@ void ui_draw_aligned_panel(uiStyle *style, uiBlock *block, const rcti *rect, con glDisable(GL_BLEND); } + /* horizontal title */ if (is_closed_x == false) { ui_draw_aligned_panel_header(style, block, &headrect, 'h'); + pos = add_attrib(immVertexFormat(), "pos", GL_FLOAT, 2, KEEP_FLOAT); /* itemrect smaller */ itemrect.xmax = headrect.xmax - 5.0f / block->aspect; @@ -637,7 +690,9 @@ void ui_draw_aligned_panel(uiStyle *style, uiBlock *block, const rcti *rect, con itemrect.ymax = headrect.ymax; BLI_rctf_scale(&itemrect, 0.7f); - ui_draw_panel_dragwidget(&itemrect); + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + ui_draw_panel_dragwidget(pos, &itemrect); + immUnbindProgram(); } /* if the panel is minimized vertically: @@ -649,6 +704,7 @@ void ui_draw_aligned_panel(uiStyle *style, uiBlock *block, const rcti *rect, con else if (is_closed_x) { /* draw vertical title */ ui_draw_aligned_panel_header(style, block, &headrect, 'v'); + pos = add_attrib(immVertexFormat(), "pos", GL_FLOAT, 2, KEEP_FLOAT); } /* an open panel */ else { @@ -657,33 +713,38 @@ void ui_draw_aligned_panel(uiStyle *style, uiBlock *block, const rcti *rect, con if (panel->control & UI_PNL_SOLID) UI_draw_roundbox_corner_set(UI_CNR_ALL); else UI_draw_roundbox_corner_set(UI_CNR_NONE); - UI_ThemeColorShade(TH_BACK, -120); - UI_draw_roundbox_unfilled(0.5f + rect->xmin, 0.5f + rect->ymin, 0.5f + rect->xmax, 0.5f + headrect.ymax + 1, 8); + UI_GetThemeColorShade4fv(TH_BACK, -120, color); + UI_draw_roundbox_unfilled(0.5f + rect->xmin, 0.5f + rect->ymin, 0.5f + rect->xmax, 0.5f + headrect.ymax + 1, 8, color); } + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + /* panel backdrop */ if (UI_GetThemeValue(TH_PANEL_SHOW_BACK)) { /* draw with background color */ glEnable(GL_BLEND); - UI_ThemeColor4(TH_PANEL_BACK); - glRecti(rect->xmin, rect->ymin, rect->xmax, rect->ymax); + immUniformThemeColor(TH_PANEL_BACK); + immRecti(pos, rect->xmin, rect->ymin, rect->xmax, rect->ymax); } if (panel->control & UI_PNL_SCALE) - ui_draw_panel_scalewidget(rect); + ui_draw_panel_scalewidget(pos, rect); + + immUnbindProgram(); } /* draw optional close icon */ ofsx = 6; if (panel->control & UI_PNL_CLOSE) { - UI_ThemeColor(TH_TITLE); - ui_draw_x_icon(rect->xmin + 2 + ofsx, rect->ymax + 2); + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + immUniformThemeColor(TH_TITLE); + ui_draw_x_icon(pos, rect->xmin + 2 + ofsx, rect->ymax + 2); ofsx = 22; + immUnbindProgram(); } /* draw collapse icon */ - UI_ThemeColor(TH_TITLE); /* itemrect smaller */ itemrect.xmin = headrect.xmin + 5.0f / block->aspect; @@ -700,6 +761,7 @@ void ui_draw_aligned_panel(uiStyle *style, uiBlock *block, const rcti *rect, con else ui_draw_tria_rect(&itemrect, 'v'); + (void)ofsx; } @@ -1518,7 +1580,8 @@ static void ui_panel_category_draw_tab( int mode, float minx, float miny, float maxx, float maxy, float rad, int roundboxtype, const bool use_highlight, const bool use_shadow, - const unsigned char highlight_fade[3]) + const unsigned char highlight_fade[3], + const unsigned char col[3]) { float vec[4][2] = { {0.195, 0.02}, @@ -1527,74 +1590,84 @@ static void ui_panel_category_draw_tab( {0.98, 0.805}}; int a; + VertexFormat *format = immVertexFormat(); + unsigned pos = add_attrib(format, "pos", GL_FLOAT, 2, KEEP_FLOAT); + unsigned color = add_attrib(format, "color", GL_UNSIGNED_BYTE, 3, NORMALIZE_INT_TO_FLOAT); + /* mult */ for (a = 0; a < 4; a++) { mul_v2_fl(vec[a], rad); } - glBegin(mode); + immBindBuiltinProgram(GPU_SHADER_2D_SMOOTH_COLOR); + + immBeginAtMost(mode, 24); + + immAttrib3ubv(color, col); /* start with corner right-top */ if (use_highlight) { if (roundboxtype & UI_CNR_TOP_RIGHT) { - glVertex2f(maxx, maxy - rad); + immVertex2f(pos, maxx, maxy - rad); for (a = 0; a < 4; a++) { - glVertex2f(maxx - vec[a][1], maxy - rad + vec[a][0]); + immVertex2f(pos, maxx - vec[a][1], maxy - rad + vec[a][0]); } - glVertex2f(maxx - rad, maxy); + immVertex2f(pos, maxx - rad, maxy); } else { - glVertex2f(maxx, maxy); + immVertex2f(pos, maxx, maxy); } /* corner left-top */ if (roundboxtype & UI_CNR_TOP_LEFT) { - glVertex2f(minx + rad, maxy); + immVertex2f(pos, minx + rad, maxy); for (a = 0; a < 4; a++) { - glVertex2f(minx + rad - vec[a][0], maxy - vec[a][1]); + immVertex2f(pos, minx + rad - vec[a][0], maxy - vec[a][1]); } - glVertex2f(minx, maxy - rad); + immVertex2f(pos, minx, maxy - rad); } else { - glVertex2f(minx, maxy); + immVertex2f(pos, minx, maxy); } } if (use_highlight && !use_shadow) { if (highlight_fade) { - glColor3ubv(highlight_fade); + immAttrib3ubv(color, highlight_fade); } - glVertex2f(minx, miny + rad); - glEnd(); + immVertex2f(pos, minx, miny + rad); + immEnd(); + immUnbindProgram(); return; } /* corner left-bottom */ if (roundboxtype & UI_CNR_BOTTOM_LEFT) { - glVertex2f(minx, miny + rad); + immVertex2f(pos, minx, miny + rad); for (a = 0; a < 4; a++) { - glVertex2f(minx + vec[a][1], miny + rad - vec[a][0]); + immVertex2f(pos, minx + vec[a][1], miny + rad - vec[a][0]); } - glVertex2f(minx + rad, miny); + immVertex2f(pos, minx + rad, miny); } else { - glVertex2f(minx, miny); + immVertex2f(pos, minx, miny); } /* corner right-bottom */ if (roundboxtype & UI_CNR_BOTTOM_RIGHT) { - glVertex2f(maxx - rad, miny); + immVertex2f(pos, maxx - rad, miny); for (a = 0; a < 4; a++) { - glVertex2f(maxx - rad + vec[a][0], miny + vec[a][1]); + immVertex2f(pos, maxx - rad + vec[a][0], miny + vec[a][1]); } - glVertex2f(maxx, miny + rad); + immVertex2f(pos, maxx, miny + rad); } else { - glVertex2f(maxx, miny); + immVertex2f(pos, maxx, miny); } - glEnd(); + immEnd(); + immUnbindProgram(); } @@ -1717,21 +1790,26 @@ void UI_panel_category_draw_all(ARegion *ar, const char *category_id_active) /* begin drawing */ glEnable(GL_LINE_SMOOTH); + unsigned int pos = add_attrib(immVertexFormat(), "pos", GL_INT, 2, CONVERT_INT_TO_FLOAT); + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + /* draw the background */ if (is_alpha) { glEnable(GL_BLEND); - glColor4ubv(theme_col_tab_bg); + immUniformColor4ubv(theme_col_tab_bg); } else { - glColor3ubv(theme_col_tab_bg); + immUniformColor3ubv(theme_col_tab_bg); } - glRecti(v2d->mask.xmin, v2d->mask.ymin, v2d->mask.xmin + category_tabs_width, v2d->mask.ymax); + immRecti(pos, v2d->mask.xmin, v2d->mask.ymin, v2d->mask.xmin + category_tabs_width, v2d->mask.ymax); if (is_alpha) { glDisable(GL_BLEND); } + immUnbindProgram(); + for (pc_dyn = ar->panels_category.first; pc_dyn; pc_dyn = pc_dyn->next) { const rcti *rct = &pc_dyn->rect; const char *category_id = pc_dyn->idname; @@ -1754,28 +1832,33 @@ void UI_panel_category_draw_all(ARegion *ar, const char *category_id_active) if (is_active) #endif { - glColor3ubv(is_active ? theme_col_tab_active : theme_col_tab_inactive); - ui_panel_category_draw_tab(GL_POLYGON, rct->xmin, rct->ymin, rct->xmax, rct->ymax, - tab_curve_radius - px, roundboxtype, true, true, NULL); + ui_panel_category_draw_tab(GL_TRIANGLE_FAN, rct->xmin, rct->ymin, rct->xmax, rct->ymax, + tab_curve_radius - px, roundboxtype, true, true, NULL, + is_active ? theme_col_tab_active : theme_col_tab_inactive); /* tab outline */ - glColor3ubv(theme_col_tab_outline); ui_panel_category_draw_tab(GL_LINE_STRIP, rct->xmin - px, rct->ymin - px, rct->xmax - px, rct->ymax + px, - tab_curve_radius, roundboxtype, true, true, NULL); + tab_curve_radius, roundboxtype, true, true, NULL, theme_col_tab_outline); + /* tab highlight (3d look) */ - glColor3ubv(is_active ? theme_col_tab_highlight : theme_col_tab_highlight_inactive); ui_panel_category_draw_tab(GL_LINE_STRIP, rct->xmin, rct->ymin, rct->xmax, rct->ymax, tab_curve_radius, roundboxtype, true, false, - is_active ? theme_col_back : theme_col_tab_inactive); + is_active ? theme_col_back : theme_col_tab_inactive, + is_active ? theme_col_tab_highlight : theme_col_tab_highlight_inactive); } /* tab blackline */ if (!is_active) { - glColor3ubv(theme_col_tab_divider); - glRecti(v2d->mask.xmin + category_tabs_width - px, - rct->ymin - tab_v_pad, - v2d->mask.xmin + category_tabs_width, - rct->ymax + tab_v_pad); + pos = add_attrib(immVertexFormat(), "pos", GL_INT, 2, CONVERT_INT_TO_FLOAT); + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + + immUniformColor3ubv(theme_col_tab_divider); + immRecti(pos, v2d->mask.xmin + category_tabs_width - px, + rct->ymin - tab_v_pad, + v2d->mask.xmin + category_tabs_width, + rct->ymax + tab_v_pad); + + immUnbindProgram(); } if (do_scaletabs) { @@ -1788,7 +1871,7 @@ void UI_panel_category_draw_all(ARegion *ar, const char *category_id_active) /* tab titles */ /* draw white shadow to give text more depth */ - glColor3ubv(theme_col_text); + BLF_color3ubv(fontid, theme_col_text); /* main tab title */ BLF_draw(fontid, category_id_draw, category_draw_len); @@ -1796,33 +1879,36 @@ void UI_panel_category_draw_all(ARegion *ar, const char *category_id_active) glDisable(GL_BLEND); /* tab blackline remaining (last tab) */ + pos = add_attrib(immVertexFormat(), "pos", GL_INT, 2, CONVERT_INT_TO_FLOAT); + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); if (pc_dyn->prev == NULL) { - glColor3ubv(theme_col_tab_divider); - glRecti(v2d->mask.xmin + category_tabs_width - px, - rct->ymax + px, - v2d->mask.xmin + category_tabs_width, - v2d->mask.ymax); + immUniformColor3ubv(theme_col_tab_divider); + immRecti(pos, v2d->mask.xmin + category_tabs_width - px, + rct->ymax + px, + v2d->mask.xmin + category_tabs_width, + v2d->mask.ymax); } if (pc_dyn->next == NULL) { - glColor3ubv(theme_col_tab_divider); - glRecti(v2d->mask.xmin + category_tabs_width - px, - 0, - v2d->mask.xmin + category_tabs_width, - rct->ymin); + immUniformColor3ubv(theme_col_tab_divider); + immRecti(pos, v2d->mask.xmin + category_tabs_width - px, + 0, + v2d->mask.xmin + category_tabs_width, + rct->ymin); } #ifdef USE_FLAT_INACTIVE /* draw line between inactive tabs */ if (is_active == false && is_active_prev == false && pc_dyn->prev) { - glColor3ubv(theme_col_tab_divider); - glRecti(v2d->mask.xmin + (category_tabs_width / 5), - rct->ymax + px, - (v2d->mask.xmin + category_tabs_width) - (category_tabs_width / 5), - rct->ymax + (px * 3)); + immUniformColor3ubv(theme_col_tab_divider); + immRecti(pos, v2d->mask.xmin + (category_tabs_width / 5), + rct->ymax + px, + (v2d->mask.xmin + category_tabs_width) - (category_tabs_width / 5), + rct->ymax + (px * 3)); } is_active_prev = is_active; #endif + immUnbindProgram(); /* not essential, but allows events to be handled right up until the region edge [#38171] */ pc_dyn->rect.xmin = v2d->mask.xmin; diff --git a/source/blender/editors/interface/interface_regions.c b/source/blender/editors/interface/interface_regions.c index 466978272bc..b78fa0706c0 100644 --- a/source/blender/editors/interface/interface_regions.c +++ b/source/blender/editors/interface/interface_regions.c @@ -194,6 +194,7 @@ static void ui_tooltip_region_draw_cb(const bContext *UNUSED(C), ARegion *ar) uiWidgetColors *theme = ui_tooltip_get_theme(); rcti bbox = data->bbox; float tip_colors[UI_TIP_LC_MAX][3]; + unsigned char drawcol[4] = {0, 0, 0, 255}; /* to store color in while drawing (alpha is always 255) */ float *main_color = tip_colors[UI_TIP_LC_MAIN]; /* the color from the theme */ float *value_color = tip_colors[UI_TIP_LC_VALUE]; @@ -260,9 +261,9 @@ static void ui_tooltip_region_draw_cb(const bContext *UNUSED(C), ARegion *ar) fstyle_header.shadowalpha = 1.0f; fstyle_header.word_wrap = true; + rgb_float_to_uchar(drawcol, tip_colors[UI_TIP_LC_MAIN]); UI_fontstyle_set(&fstyle_header); - glColor3fv(tip_colors[UI_TIP_LC_MAIN]); - UI_fontstyle_draw(&fstyle_header, &bbox, data->header); + UI_fontstyle_draw(&fstyle_header, &bbox, data->header, drawcol); /* offset to the end of the last line */ xofs = data->line_geom[i].x_pos; @@ -270,9 +271,9 @@ static void ui_tooltip_region_draw_cb(const bContext *UNUSED(C), ARegion *ar) bbox.xmin += xofs; bbox.ymax -= yofs; - glColor3fv(tip_colors[UI_TIP_LC_ACTIVE]); + rgb_float_to_uchar(drawcol, tip_colors[UI_TIP_LC_ACTIVE]); fstyle_header.shadow = 0; - UI_fontstyle_draw(&fstyle_header, &bbox, data->active_info); + UI_fontstyle_draw(&fstyle_header, &bbox, data->active_info, drawcol); /* undo offset */ bbox.xmin -= xofs; @@ -280,14 +281,15 @@ static void ui_tooltip_region_draw_cb(const bContext *UNUSED(C), ARegion *ar) } else if (data->format[i].style == UI_TIP_STYLE_MONO) { uiFontStyle fstyle_mono = data->fstyle; + fstyle_mono.uifont_id = blf_mono_font; fstyle_mono.word_wrap = true; UI_fontstyle_set(&fstyle_mono); /* XXX, needed because we dont have mono in 'U.uifonts' */ BLF_size(fstyle_mono.uifont_id, fstyle_mono.points * U.pixelsize, U.dpi); - glColor3fv(tip_colors[data->format[i].color_id]); - UI_fontstyle_draw(&fstyle_mono, &bbox, data->lines[i]); + rgb_float_to_uchar(drawcol, tip_colors[data->format[i].color_id]); + UI_fontstyle_draw(&fstyle_mono, &bbox, data->lines[i], drawcol); } else { uiFontStyle fstyle_normal = data->fstyle; @@ -296,8 +298,8 @@ static void ui_tooltip_region_draw_cb(const bContext *UNUSED(C), ARegion *ar) /* draw remaining data */ UI_fontstyle_set(&fstyle_normal); - glColor3fv(tip_colors[data->format[i].color_id]); - UI_fontstyle_draw(&fstyle_normal, &bbox, data->lines[i]); + rgb_float_to_uchar(drawcol, tip_colors[data->format[i].color_id]); + UI_fontstyle_draw(&fstyle_normal, &bbox, data->lines[i], drawcol); } bbox.ymax -= data->lineh * data->line_geom[i].lines; @@ -1059,7 +1061,7 @@ int ui_searchbox_autocomplete(bContext *C, ARegion *ar, uiBut *but, char *str) return match; } -static void ui_searchbox_region_draw_cb(const bContext *UNUSED(C), ARegion *ar) +static void ui_searchbox_region_draw_cb(const bContext *C, ARegion *ar) { uiSearchboxData *data = ar->regiondata; @@ -1077,6 +1079,9 @@ static void ui_searchbox_region_draw_cb(const bContext *UNUSED(C), ARegion *ar) if (data->preview) { /* draw items */ for (a = 0; a < data->items.totitem; a++) { + /* ensure icon is up-to-date */ + ui_icon_ensure_deferred(C, data->items.icons[a], data->preview); + ui_searchbox_butrect(&rect, data, a); /* widget itself */ diff --git a/source/blender/editors/interface/interface_style.c b/source/blender/editors/interface/interface_style.c index 8b41302b5bb..01bce9d7bdc 100644 --- a/source/blender/editors/interface/interface_style.c +++ b/source/blender/editors/interface/interface_style.c @@ -149,7 +149,7 @@ static uiFont *uifont_to_blfont(int id) void UI_fontstyle_draw_ex( - const uiFontStyle *fs, const rcti *rect, const char *str, + const uiFontStyle *fs, const rcti *rect, const char *str, const unsigned char col[4], size_t len, float *r_xofs, float *r_yofs) { int xofs = 0, yofs; @@ -196,6 +196,7 @@ void UI_fontstyle_draw_ex( /* clip is very strict, so we give it some space */ BLF_clipping(fs->uifont_id, rect->xmin - 2, rect->ymin - 4, rect->xmax + 1, rect->ymax + 4); BLF_position(fs->uifont_id, rect->xmin + xofs, rect->ymin + yofs, 0.0f); + BLF_color4ubv(fs->uifont_id, col); BLF_draw(fs->uifont_id, str, len); @@ -205,17 +206,17 @@ void UI_fontstyle_draw_ex( *r_yofs = yofs; } -void UI_fontstyle_draw(const uiFontStyle *fs, const rcti *rect, const char *str) +void UI_fontstyle_draw(const uiFontStyle *fs, const rcti *rect, const char *str, const unsigned char col[4]) { float xofs, yofs; UI_fontstyle_draw_ex( - fs, rect, str, + fs, rect, str, col, BLF_DRAW_STR_DUMMY_MAX, &xofs, &yofs); } /* drawn same as above, but at 90 degree angle */ -void UI_fontstyle_draw_rotated(const uiFontStyle *fs, const rcti *rect, const char *str) +void UI_fontstyle_draw_rotated(const uiFontStyle *fs, const rcti *rect, const char *str, const unsigned char col[4]) { float height; int xofs, yofs; @@ -249,6 +250,7 @@ void UI_fontstyle_draw_rotated(const uiFontStyle *fs, const rcti *rect, const ch BLF_enable(fs->uifont_id, BLF_ROTATION); BLF_rotation(fs->uifont_id, angle); + BLF_color4ubv(fs->uifont_id, col); if (fs->shadow) { BLF_enable(fs->uifont_id, BLF_SHADOW); @@ -275,13 +277,14 @@ void UI_fontstyle_draw_rotated(const uiFontStyle *fs, const rcti *rect, const ch * * For drawing on-screen labels. */ -void UI_fontstyle_draw_simple(const uiFontStyle *fs, float x, float y, const char *str) +void UI_fontstyle_draw_simple(const uiFontStyle *fs, float x, float y, const char *str, const unsigned char col[4]) { if (fs->kerning == 1) BLF_enable(fs->uifont_id, BLF_KERNING_DEFAULT); UI_fontstyle_set(fs); BLF_position(fs->uifont_id, x, y, 0.0f); + BLF_color4ubv(fs->uifont_id, col); BLF_draw(fs->uifont_id, str, BLF_DRAW_STR_DUMMY_MAX); if (fs->kerning == 1) @@ -293,7 +296,7 @@ void UI_fontstyle_draw_simple(const uiFontStyle *fs, float x, float y, const cha */ void UI_fontstyle_draw_simple_backdrop( const uiFontStyle *fs, float x, float y, const char *str, - const unsigned char fg[4], const unsigned char bg[4]) + const float col_fg[4], const float col_bg[4]) { if (fs->kerning == 1) BLF_enable(fs->uifont_id, BLF_KERNING_DEFAULT); @@ -307,7 +310,6 @@ void UI_fontstyle_draw_simple_backdrop( const float margin = height / 4.0f; /* backdrop */ - glColor4ubv(bg); UI_draw_roundbox_corner_set(UI_CNR_ALL | UI_RB_ALPHA); UI_draw_roundbox( @@ -315,13 +317,12 @@ void UI_fontstyle_draw_simple_backdrop( (y + decent) - margin, x + width + margin, (y + decent) + height + margin, - margin); - - glColor4ubv(fg); + margin, col_bg); } BLF_position(fs->uifont_id, x, y, 0.0f); + BLF_color4fv(fs->uifont_id, col_fg); BLF_draw(fs->uifont_id, str, BLF_DRAW_STR_DUMMY_MAX); if (fs->kerning == 1) diff --git a/source/blender/editors/interface/interface_templates.c b/source/blender/editors/interface/interface_templates.c index 4db1c845c23..2cdcf7a604d 100644 --- a/source/blender/editors/interface/interface_templates.c +++ b/source/blender/editors/interface/interface_templates.c @@ -417,17 +417,30 @@ static void template_ID( type = idptr.type; if (flag & UI_ID_PREVIEWS) { + ARegion *region = CTX_wm_region(C); + const bool use_big_size = (region->regiontype != RGN_TYPE_HEADER); /* silly check, could be more generic */ + /* Ugly exception for screens here, drawing their preview in icon size looks ugly/useless */ + const bool use_preview_icon = use_big_size || (id && (GS(id->name) != ID_SCR)); + const short width = UI_UNIT_X * (use_big_size ? 6 : 1.6f); + const short height = UI_UNIT_Y * (use_big_size ? 6: 1); + template->preview = true; - but = uiDefBlockButN(block, id_search_menu, MEM_dupallocN(template), "", 0, 0, UI_UNIT_X * 6, UI_UNIT_Y * 6, + but = uiDefBlockButN(block, id_search_menu, MEM_dupallocN(template), "", 0, 0, width, height, TIP_(template_id_browse_tip(type))); - ui_def_but_icon(but, id ? ui_id_icon_get(C, id, true) : RNA_struct_ui_icon(type), - UI_HAS_ICON | UI_BUT_ICON_PREVIEW); + if (use_preview_icon) { + ui_def_but_icon(but, ui_id_icon_get(C, id, use_big_size), UI_HAS_ICON | UI_BUT_ICON_PREVIEW); + } + else { + ui_def_but_icon(but, RNA_struct_ui_icon(type), UI_HAS_ICON); + UI_but_drawflag_enable(but, UI_BUT_ICON_LEFT); + } if ((idfrom && idfrom->lib) || !editable) UI_but_flag_enable(but, UI_BUT_DISABLED); - - uiLayoutRow(layout, true); + if (use_big_size) { + uiLayoutRow(layout, true); + } } else if (flag & UI_ID_BROWSE) { but = uiDefBlockButN(block, id_search_menu, MEM_dupallocN(template), "", 0, 0, UI_UNIT_X * 1.6, UI_UNIT_Y, diff --git a/source/blender/editors/interface/interface_widgets.c b/source/blender/editors/interface/interface_widgets.c index b3736a71e74..0521e7d8c7d 100644 --- a/source/blender/editors/interface/interface_widgets.c +++ b/source/blender/editors/interface/interface_widgets.c @@ -58,6 +58,8 @@ #include "interface_intern.h" #include "GPU_basic_shader.h" +#include "GPU_immediate.h" +#include "GPU_matrix.h" #ifdef WITH_INPUT_IME # include "WM_types.h" @@ -186,47 +188,54 @@ static const unsigned int check_tria_face[4][3] = { /* ************************************************* */ -void ui_draw_anti_tria(float x1, float y1, float x2, float y2, float x3, float y3) +void ui_draw_anti_tria(float x1, float y1, float x2, float y2, float x3, float y3, + const float color[4]) { float tri_arr[3][2] = {{x1, y1}, {x2, y2}, {x3, y3}}; - float color[4]; - int j; - + float draw_color[4]; + + copy_v4_v4(draw_color, color); + draw_color[3] *= 0.125f; + glEnable(GL_BLEND); - glGetFloatv(GL_CURRENT_COLOR, color); - color[3] *= 0.125f; - glColor4fv(color); - glEnableClientState(GL_VERTEX_ARRAY); - glVertexPointer(2, GL_FLOAT, 0, tri_arr); + unsigned int pos = add_attrib(immVertexFormat(), "pos", GL_FLOAT, 2, KEEP_FLOAT); + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + + immUniformColor4fv(draw_color); + immBegin(GL_TRIANGLES, 3 * WIDGET_AA_JITTER); /* for each AA step */ - for (j = 0; j < WIDGET_AA_JITTER; j++) { - glTranslate2fv(jit[j]); - glDrawArrays(GL_TRIANGLES, 0, 3); - glTranslatef(-jit[j][0], -jit[j][1], 0.0f); + for (int j = 0; j < WIDGET_AA_JITTER; j++) { + immVertex2f(pos, tri_arr[0][0] + jit[j][0], tri_arr[0][1] + jit[j][1]); + immVertex2f(pos, tri_arr[1][0] + jit[j][0], tri_arr[1][1] + jit[j][1]); + immVertex2f(pos, tri_arr[2][0] + jit[j][0], tri_arr[2][1] + jit[j][1]); } - glDisableClientState(GL_VERTEX_ARRAY); + immEnd(); + + immUnbindProgram(); + glDisable(GL_BLEND); } -void ui_draw_anti_roundbox(int mode, float minx, float miny, float maxx, float maxy, float rad, bool use_alpha) +void ui_draw_anti_roundbox(int mode, float minx, float miny, float maxx, float maxy, + float rad, bool use_alpha, const float color[4]) { - float color[4]; + float draw_color[4]; int j; - + + copy_v4_v4(draw_color, color); + glEnable(GL_BLEND); - glGetFloatv(GL_CURRENT_COLOR, color); if (use_alpha) { - color[3] = 0.5f; + draw_color[3] = 0.5f; } - color[3] *= 0.125f; - glColor4fv(color); + draw_color[3] *= 0.125f; for (j = 0; j < WIDGET_AA_JITTER; j++) { glTranslate2fv(jit[j]); - UI_draw_roundbox_gl_mode(mode, minx, miny, maxx, maxy, rad); + UI_draw_roundbox_gl_mode(mode, minx, miny, maxx, maxy, rad, draw_color); glTranslatef(-jit[j][0], -jit[j][1], 0.0f); } @@ -537,12 +546,27 @@ static void widget_scroll_circle(uiWidgetTrias *tria, const rcti *rect, float tr scroll_circle_face, ARRAY_SIZE(scroll_circle_face)); } -static void widget_trias_draw(uiWidgetTrias *tria) +static void widget_trias_draw(uiWidgetTrias *tria, unsigned int pos) { - glEnableClientState(GL_VERTEX_ARRAY); - glVertexPointer(2, GL_FLOAT, 0, tria->vec); - glDrawElements(GL_TRIANGLES, tria->tot * 3, GL_UNSIGNED_INT, tria->index); - glDisableClientState(GL_VERTEX_ARRAY); + immBegin(GL_TRIANGLES, tria->tot * 3); + for (int i = 0; i < tria->tot; ++i) + for (int j = 0; j < 3; ++j) + immVertex2fv(pos, tria->vec[tria->index[i][j]]); + immEnd(); +} + +static void widget_draw_vertex_buffer(unsigned int pos, unsigned int col, int mode, + const float quads_pos[WIDGET_SIZE_MAX][2], + const unsigned char quads_col[WIDGET_SIZE_MAX][4], + unsigned int totvert) +{ + immBegin(mode, totvert); + for (int i = 0; i < totvert; ++i) { + if (quads_col) + immAttrib4ubv(col, quads_col[i]); + immVertex2fv(pos, quads_pos[i]); + } + immEnd(); } static void widget_menu_trias(uiWidgetTrias *tria, const rcti *rect) @@ -631,21 +655,18 @@ static void widget_verts_to_triangle_strip_open(uiWidgetBase *wtb, const int tot } } -static void widgetbase_outline(uiWidgetBase *wtb) +static void widgetbase_outline(uiWidgetBase *wtb, unsigned int pos) { float triangle_strip[WIDGET_SIZE_MAX * 2 + 2][2]; /* + 2 because the last pair is wrapped */ widget_verts_to_triangle_strip(wtb, wtb->totvert, triangle_strip); - glEnableClientState(GL_VERTEX_ARRAY); - glVertexPointer(2, GL_FLOAT, 0, triangle_strip); - glDrawArrays(GL_TRIANGLE_STRIP, 0, wtb->totvert * 2 + 2); - glDisableClientState(GL_VERTEX_ARRAY); + widget_draw_vertex_buffer(pos, 0, GL_TRIANGLE_STRIP, triangle_strip, NULL, wtb->totvert * 2 + 2); } static void widgetbase_draw(uiWidgetBase *wtb, uiWidgetColors *wcol) { int j, a; - + glEnable(GL_BLEND); /* backdrop non AA */ @@ -655,78 +676,76 @@ static void widgetbase_draw(uiWidgetBase *wtb, uiWidgetColors *wcol) float inner_v_half[WIDGET_SIZE_MAX][2]; float x_mid = 0.0f; /* used for dumb clamping of values */ - /* dark checkers */ - glColor4ub(UI_ALPHA_CHECKER_DARK, UI_ALPHA_CHECKER_DARK, UI_ALPHA_CHECKER_DARK, 255); - glEnableClientState(GL_VERTEX_ARRAY); - glVertexPointer(2, GL_FLOAT, 0, wtb->inner_v); - glDrawArrays(GL_POLYGON, 0, wtb->totvert); + unsigned int pos = add_attrib(immVertexFormat(), "pos", GL_FLOAT, 2, KEEP_FLOAT); + immBindBuiltinProgram(GPU_SHADER_2D_CHECKER); - /* light checkers */ - GPU_basic_shader_bind(GPU_SHADER_STIPPLE | GPU_SHADER_USE_COLOR); - glColor4ub(UI_ALPHA_CHECKER_LIGHT, UI_ALPHA_CHECKER_LIGHT, UI_ALPHA_CHECKER_LIGHT, 255); - GPU_basic_shader_stipple(GPU_SHADER_STIPPLE_CHECKER_8PX); + /* checkers */ + immUniform4f("color1", UI_ALPHA_CHECKER_DARK / 255.0f, UI_ALPHA_CHECKER_DARK / 255.0f, UI_ALPHA_CHECKER_DARK / 255.0f, 1.0f); + immUniform4f("color2", UI_ALPHA_CHECKER_LIGHT / 255.0f, UI_ALPHA_CHECKER_LIGHT / 255.0f, UI_ALPHA_CHECKER_LIGHT / 255.0f, 1.0f); + immUniform1i("size", 8); - glVertexPointer(2, GL_FLOAT, 0, wtb->inner_v); - glDrawArrays(GL_POLYGON, 0, wtb->totvert); + widget_draw_vertex_buffer(pos, 0, GL_TRIANGLE_FAN, wtb->inner_v, NULL, wtb->totvert); - GPU_basic_shader_bind(GPU_SHADER_USE_COLOR); + immUnbindProgram(); /* alpha fill */ - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + immUniformColor4ubv((unsigned char *)wcol->inner); - glColor4ubv((unsigned char *)wcol->inner); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); for (a = 0; a < wtb->totvert; a++) { x_mid += wtb->inner_v[a][0]; } x_mid /= wtb->totvert; - glVertexPointer(2, GL_FLOAT, 0, wtb->inner_v); - glDrawArrays(GL_POLYGON, 0, wtb->totvert); + widget_draw_vertex_buffer(pos, 0, GL_TRIANGLE_FAN, wtb->inner_v, NULL, wtb->totvert); /* 1/2 solid color */ - glColor4ub(wcol->inner[0], wcol->inner[1], wcol->inner[2], 255); + immUniformColor4ub(wcol->inner[0], wcol->inner[1], wcol->inner[2], 255); for (a = 0; a < wtb->totvert; a++) { inner_v_half[a][0] = MIN2(wtb->inner_v[a][0], x_mid); inner_v_half[a][1] = wtb->inner_v[a][1]; } - glVertexPointer(2, GL_FLOAT, 0, inner_v_half); - glDrawArrays(GL_POLYGON, 0, wtb->totvert); - glDisableClientState(GL_VERTEX_ARRAY); + widget_draw_vertex_buffer(pos, 0, GL_TRIANGLE_FAN, inner_v_half, NULL, wtb->totvert); + + immUnbindProgram(); } else { /* simple fill */ - glColor4ubv((unsigned char *)wcol->inner); + unsigned int pos = add_attrib(immVertexFormat(), "pos", GL_FLOAT, 2, KEEP_FLOAT); + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + immUniformColor4ubv((unsigned char *)wcol->inner); + + widget_draw_vertex_buffer(pos, 0, GL_TRIANGLE_FAN, wtb->inner_v, NULL, wtb->totvert); - glEnableClientState(GL_VERTEX_ARRAY); - glVertexPointer(2, GL_FLOAT, 0, wtb->inner_v); - glDrawArrays(GL_POLYGON, 0, wtb->totvert); - glDisableClientState(GL_VERTEX_ARRAY); + immUnbindProgram(); } } else { char col1[4], col2[4]; - unsigned char col_array[WIDGET_SIZE_MAX * 4]; - unsigned char *col_pt = col_array; - + unsigned char col_array[WIDGET_SIZE_MAX][4]; + unsigned char *col_pt = &col_array[0][0]; + + VertexFormat *format = immVertexFormat(); + unsigned int pos = add_attrib(format, "pos", GL_FLOAT, 2, KEEP_FLOAT); + unsigned int col = add_attrib(format, "color", GL_UNSIGNED_BYTE, 4, NORMALIZE_INT_TO_FLOAT); + + immBindBuiltinProgram(GPU_SHADER_2D_SMOOTH_COLOR); + shadecolors4(col1, col2, wcol->inner, wcol->shadetop, wcol->shadedown); for (a = 0; a < wtb->totvert; a++, col_pt += 4) { round_box_shade_col4_r(col_pt, col1, col2, wtb->inner_uv[a][wtb->draw_shadedir ? 1 : 0]); } - glEnableClientState(GL_VERTEX_ARRAY); - glEnableClientState(GL_COLOR_ARRAY); - glVertexPointer(2, GL_FLOAT, 0, wtb->inner_v); - glColorPointer(4, GL_UNSIGNED_BYTE, 0, col_array); - glDrawArrays(GL_POLYGON, 0, wtb->totvert); - glDisableClientState(GL_VERTEX_ARRAY); - glDisableClientState(GL_COLOR_ARRAY); + widget_draw_vertex_buffer(pos, col, GL_TRIANGLE_FAN, wtb->inner_v, col_array, wtb->totvert); + immUnbindProgram(); } } - + /* for each AA step */ if (wtb->draw_outline) { float triangle_strip[WIDGET_SIZE_MAX * 2 + 2][2]; /* + 2 because the last pair is wrapped */ @@ -745,52 +764,63 @@ static void widgetbase_draw(uiWidgetBase *wtb, uiWidgetColors *wcol) UI_GetThemeColor4ubv(TH_WIDGET_EMBOSS, emboss); } - glEnableClientState(GL_VERTEX_ARRAY); + unsigned int pos = add_attrib(immVertexFormat(), "pos", GL_FLOAT, 2, KEEP_FLOAT); + gpuMatrixBegin3D_legacy(); + + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); for (j = 0; j < WIDGET_AA_JITTER; j++) { - glTranslate2fv(jit[j]); + gpuTranslate3f(jit[j][0], jit[j][1], 0.0f); /* outline */ - glColor4ubv(tcol); + immUniformColor4ubv(tcol); - glVertexPointer(2, GL_FLOAT, 0, triangle_strip); - glDrawArrays(GL_TRIANGLE_STRIP, 0, wtb->totvert * 2 + 2); + widget_draw_vertex_buffer(pos, 0, GL_TRIANGLE_STRIP, triangle_strip, NULL, wtb->totvert * 2 + 2); /* emboss bottom shadow */ if (wtb->draw_emboss) { if (emboss[3]) { - glColor4ubv(emboss); - glVertexPointer(2, GL_FLOAT, 0, triangle_strip_emboss); - glDrawArrays(GL_TRIANGLE_STRIP, 0, wtb->halfwayvert * 2); + immUniformColor4ubv(emboss); + widget_draw_vertex_buffer(pos, 0, GL_TRIANGLE_STRIP, triangle_strip_emboss, NULL, wtb->halfwayvert * 2); } } - glTranslatef(-jit[j][0], -jit[j][1], 0.0f); + gpuTranslate3f(-jit[j][0], -jit[j][1], 0.0f); } + immUnbindProgram(); - glDisableClientState(GL_VERTEX_ARRAY); + gpuMatrixEnd(); } - + /* decoration */ if (wtb->tria1.tot || wtb->tria2.tot) { const unsigned char tcol[4] = {wcol->item[0], wcol->item[1], wcol->item[2], (unsigned char)((float)wcol->item[3] / WIDGET_AA_JITTER)}; - glColor4ubv(tcol); + + unsigned int pos = add_attrib(immVertexFormat(), "pos", GL_FLOAT, 2, KEEP_FLOAT); + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + immUniformColor4ubv(tcol); + + gpuMatrixBegin3D_legacy(); /* for each AA step */ for (j = 0; j < WIDGET_AA_JITTER; j++) { - glTranslate2fv(jit[j]); + gpuTranslate3f(jit[j][0], jit[j][1], 0.0f); if (wtb->tria1.tot) - widget_trias_draw(&wtb->tria1); + widget_trias_draw(&wtb->tria1, pos); if (wtb->tria2.tot) - widget_trias_draw(&wtb->tria2); + widget_trias_draw(&wtb->tria2, pos); - glTranslatef(-jit[j][0], -jit[j][1], 0.0f); + gpuTranslate3f(-jit[j][0], -jit[j][1], 0.0f); } + + gpuMatrixEnd(); + + immUnbindProgram(); } glDisable(GL_BLEND); @@ -1249,6 +1279,7 @@ static void widget_draw_text_ime_underline( int ofs_x, width; int rect_x = BLI_rcti_size_x(rect); int sel_start = ime_data->sel_start, sel_end = ime_data->sel_end; + float fcol[4]; if (drawstr[0] != 0) { if (but->pos >= but->ofs) { @@ -1261,8 +1292,8 @@ static void widget_draw_text_ime_underline( width = BLF_width(fstyle->uifont_id, drawstr + but->ofs, ime_data->composite_len + but->pos - but->ofs); - glColor4ubv((unsigned char *)wcol->text); - UI_draw_text_underline(rect->xmin + ofs_x, rect->ymin + 6 * U.pixelsize, min_ii(width, rect_x - 2) - ofs_x, 1); + rgba_uchar_to_float(fcol, wcol->text); + UI_draw_text_underline(rect->xmin + ofs_x, rect->ymin + 6 * U.pixelsize, min_ii(width, rect_x - 2) - ofs_x, 1, fcol); /* draw the thick line */ if (sel_start != -1 && sel_end != -1) { @@ -1279,7 +1310,7 @@ static void widget_draw_text_ime_underline( width = BLF_width(fstyle->uifont_id, drawstr + but->ofs, sel_end + sel_start - but->ofs); - UI_draw_text_underline(rect->xmin + ofs_x, rect->ymin + 6 * U.pixelsize, min_ii(width, rect_x - 2) - ofs_x, 2); + UI_draw_text_underline(rect->xmin + ofs_x, rect->ymin + 6 * U.pixelsize, min_ii(width, rect_x - 2) - ofs_x, 2, fcol); } } } @@ -1363,11 +1394,16 @@ static void widget_draw_text(uiFontStyle *fstyle, uiWidgetColors *wcol, uiBut *b selwidth_draw = BLF_width(fstyle->uifont_id, drawstr + but->ofs, but->selend - but->ofs); - glColor4ubv((unsigned char *)wcol->item); - glRecti(rect->xmin + selsta_draw, - rect->ymin + 2, - min_ii(rect->xmin + selwidth_draw, rect->xmax - 2), - rect->ymax - 2); + unsigned int pos = add_attrib(immVertexFormat(), "pos", GL_INT, 2, KEEP_INT); + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + + immUniformColor4ubv((unsigned char *)wcol->item); + immRecti(pos, rect->xmin + selsta_draw, + rect->ymin + 2, + min_ii(rect->xmin + selwidth_draw, rect->xmax - 2), + rect->ymax - 2); + + immUnbindProgram(); } } @@ -1390,13 +1426,18 @@ static void widget_draw_text(uiFontStyle *fstyle, uiWidgetColors *wcol, uiBut *b t = 0; } - glColor3f(0.2, 0.6, 0.9); + unsigned int pos = add_attrib(immVertexFormat(), "pos", GL_INT, 2, KEEP_INT); + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + + immUniformColor3f(0.2f, 0.6f, 0.9f); tx = rect->xmin + t + 2; ty = rect->ymin + 2; /* draw cursor */ - glRecti(rect->xmin + t, ty, tx, rect->ymax - 2); + immRecti(pos, rect->xmin + t, ty, tx, rect->ymax - 2); + + immUnbindProgram(); } #ifdef WITH_INPUT_IME @@ -1455,43 +1496,46 @@ static void widget_draw_text(uiFontStyle *fstyle, uiWidgetColors *wcol, uiBut *b } #endif - glColor4ubv((unsigned char *)wcol->text); - if (!use_right_only) { /* for underline drawing */ float font_xofs, font_yofs; - UI_fontstyle_draw_ex(fstyle, rect, drawstr + but->ofs, - drawstr_left_len - but->ofs, &font_xofs, &font_yofs); + int drawlen = (drawstr_left_len == INT_MAX) ? strlen(drawstr + but->ofs) : (drawstr_left_len - but->ofs); - if (but->menu_key != '\0') { - char fixedbuf[128]; - const char *str; + if (drawlen > 0) { + UI_fontstyle_draw_ex(fstyle, rect, drawstr + but->ofs, (unsigned char *)wcol->text, + drawlen, &font_xofs, &font_yofs); - BLI_strncpy(fixedbuf, drawstr + but->ofs, min_ii(sizeof(fixedbuf), drawstr_left_len)); + if (but->menu_key != '\0') { + char fixedbuf[128]; + const char *str; - str = strchr(fixedbuf, but->menu_key - 32); /* upper case */ - if (str == NULL) - str = strchr(fixedbuf, but->menu_key); + BLI_strncpy(fixedbuf, drawstr + but->ofs, min_ii(sizeof(fixedbuf), drawlen)); - if (str) { - int ul_index = -1; - float ul_advance; + str = strchr(fixedbuf, but->menu_key - 32); /* upper case */ + if (str == NULL) + str = strchr(fixedbuf, but->menu_key); - ul_index = (int)(str - fixedbuf); + if (str) { + int ul_index = -1; + float ul_advance; - if (fstyle->kerning == 1) { - BLF_enable(fstyle->uifont_id, BLF_KERNING_DEFAULT); - } + ul_index = (int)(str - fixedbuf); + + if (fstyle->kerning == 1) { + BLF_enable(fstyle->uifont_id, BLF_KERNING_DEFAULT); + } - fixedbuf[ul_index] = '\0'; - ul_advance = BLF_width(fstyle->uifont_id, fixedbuf, ul_index); + fixedbuf[ul_index] = '\0'; + ul_advance = BLF_width(fstyle->uifont_id, fixedbuf, ul_index); - BLF_position(fstyle->uifont_id, rect->xmin + font_xofs + ul_advance, rect->ymin + font_yofs, 0.0f); - BLF_draw(fstyle->uifont_id, "_", 2); + BLF_position(fstyle->uifont_id, rect->xmin + font_xofs + ul_advance, rect->ymin + font_yofs, 0.0f); + BLF_color4ubv(fstyle->uifont_id, (unsigned char *)wcol->text); + BLF_draw(fstyle->uifont_id, "_", 2); - if (fstyle->kerning == 1) { - BLF_disable(fstyle->uifont_id, BLF_KERNING_DEFAULT); + if (fstyle->kerning == 1) { + BLF_disable(fstyle->uifont_id, BLF_KERNING_DEFAULT); + } } } } @@ -1501,7 +1545,7 @@ static void widget_draw_text(uiFontStyle *fstyle, uiWidgetColors *wcol, uiBut *b if (drawstr_right) { fstyle->align = UI_STYLE_TEXT_RIGHT; rect->xmax -= UI_TEXT_CLIP_MARGIN; - UI_fontstyle_draw(fstyle, rect, drawstr_right); + UI_fontstyle_draw(fstyle, rect, drawstr_right, (unsigned char *)wcol->text); } } @@ -2158,23 +2202,24 @@ static void widget_softshadow(const rcti *rect, int roundboxalign, const float r /* we draw a number of increasing size alpha quad strips */ alphastep = 3.0f * btheme->tui.menu_shadow_fac / radout; - - glEnableClientState(GL_VERTEX_ARRAY); + + unsigned int pos = add_attrib(immVertexFormat(), "pos", GL_FLOAT, 2, KEEP_FLOAT); + + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); for (step = 1; step <= (int)radout; step++) { float expfac = sqrtf(step / radout); round_box_shadow_edges(wtb.outer_v, &rect1, radin, UI_CNR_ALL, (float)step); - glColor4f(0.0f, 0.0f, 0.0f, alphastep * (1.0f - expfac)); + immUniformColor4f(0.0f, 0.0f, 0.0f, alphastep * (1.0f - expfac)); widget_verts_to_triangle_strip(&wtb, totvert, triangle_strip); - glVertexPointer(2, GL_FLOAT, 0, triangle_strip); - glDrawArrays(GL_TRIANGLE_STRIP, 0, totvert * 2); /* add + 2 for getting a complete soft rect. Now it skips top edge to allow transparent menus */ + widget_draw_vertex_buffer(pos, 0, GL_TRIANGLE_STRIP, triangle_strip, NULL, totvert * 2); } - glDisableClientState(GL_VERTEX_ARRAY); + immUnbindProgram(); } static void widget_menu_back(uiWidgetColors *wcol, rcti *rect, int flag, int direction) @@ -2211,20 +2256,21 @@ static void widget_menu_back(uiWidgetColors *wcol, rcti *rect, int flag, int dir static void ui_hsv_cursor(float x, float y) { - glPushMatrix(); - glTranslatef(x, y, 0.0f); - - glColor3f(1.0f, 1.0f, 1.0f); - glutil_draw_filled_arc(0.0f, M_PI * 2.0, 3.0f * U.pixelsize, 8); + unsigned int pos = add_attrib(immVertexFormat(), "pos", GL_FLOAT, 2, KEEP_FLOAT); + + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + + immUniformColor3f(1.0f, 1.0f, 1.0f); + imm_draw_filled_circle(pos, x, y, 3.0f * U.pixelsize, 8); glEnable(GL_BLEND); glEnable(GL_LINE_SMOOTH); - glColor3f(0.0f, 0.0f, 0.0f); - glutil_draw_lined_arc(0.0f, M_PI * 2.0, 3.0f * U.pixelsize, 12); + immUniformColor3f(0.0f, 0.0f, 0.0f); + imm_draw_lined_circle(pos, x, y, 3.0f * U.pixelsize, 12); glDisable(GL_BLEND); glDisable(GL_LINE_SMOOTH); - - glPopMatrix(); + + immUnbindProgram(); } void ui_hsvcircle_vals_from_pos(float *val_rad, float *val_dist, const rcti *rect, @@ -2264,18 +2310,17 @@ void ui_hsvcircle_pos_from_vals(uiBut *but, const rcti *rect, float *hsv, float static void ui_draw_but_HSVCIRCLE(uiBut *but, uiWidgetColors *wcol, const rcti *rect) { + /* TODO(merwin): reimplement as shader for pixel-perfect colors */ + const int tot = 64; const float radstep = 2.0f * (float)M_PI / (float)tot; const float centx = BLI_rcti_cent_x_fl(rect); const float centy = BLI_rcti_cent_y_fl(rect); float radius = (float)min_ii(BLI_rcti_size_x(rect), BLI_rcti_size_y(rect)) / 2.0f; - /* gouraud triangle fan */ ColorPicker *cpicker = but->custom_data; const float *hsv_ptr = cpicker->color_data; - float xpos, ypos, ang = 0.0f; float rgb[3], hsvo[3], hsv[3], col[3], colcent[3]; - int a; bool color_profile = ui_but_is_colorpicker_display_space(but); /* color */ @@ -2306,11 +2351,18 @@ static void ui_draw_but_HSVCIRCLE(uiBut *but, uiWidgetColors *wcol, const rcti * ui_color_picker_to_rgb(0.0f, 0.0f, hsv[2], colcent, colcent + 1, colcent + 2); - glBegin(GL_TRIANGLE_FAN); - glColor3fv(colcent); - glVertex2f(centx, centy); + VertexFormat *format = immVertexFormat(); + unsigned int pos = add_attrib(format, "pos", GL_FLOAT, 2, KEEP_FLOAT); + unsigned int color = add_attrib(format, "color", GL_FLOAT, 3, KEEP_FLOAT); + + immBindBuiltinProgram(GPU_SHADER_2D_SMOOTH_COLOR); + + immBegin(GL_TRIANGLE_FAN, tot + 2); + immAttrib3fv(color, colcent); + immVertex2f(pos, centx, centy); - for (a = 0; a <= tot; a++, ang += radstep) { + float ang = 0.0f; + for (int a = 0; a <= tot; a++, ang += radstep) { float si = sinf(ang); float co = cosf(ang); @@ -2318,25 +2370,32 @@ static void ui_draw_but_HSVCIRCLE(uiBut *but, uiWidgetColors *wcol, const rcti * ui_color_picker_to_rgb_v(hsv, col); - glColor3fv(col); - glVertex2f(centx + co * radius, centy + si * radius); + immAttrib3fv(color, col); + immVertex2f(pos, centx + co * radius, centy + si * radius); } - glEnd(); - + immEnd(); + immUnbindProgram(); + /* fully rounded outline */ - glPushMatrix(); - glTranslatef(centx, centy, 0.0f); + format = immVertexFormat(); + pos = add_attrib(format, "pos", GL_FLOAT, 2, KEEP_FLOAT); + + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + glEnable(GL_BLEND); glEnable(GL_LINE_SMOOTH); - glColor3ubv((unsigned char *)wcol->outline); - glutil_draw_lined_arc(0.0f, M_PI * 2.0, radius, tot + 1); + + immUniformColor3ubv((unsigned char *)wcol->outline); + imm_draw_lined_circle(pos, centx, centy, radius, tot); + + immUnbindProgram(); + glDisable(GL_BLEND); glDisable(GL_LINE_SMOOTH); - glPopMatrix(); /* cursor */ + float xpos, ypos; ui_hsvcircle_pos_from_vals(but, rect, hsvo, &xpos, &ypos); - ui_hsv_cursor(xpos, ypos); } @@ -2346,7 +2405,8 @@ static void ui_draw_but_HSVCIRCLE(uiBut *but, uiWidgetColors *wcol, const rcti * void ui_draw_gradient(const rcti *rect, const float hsv[3], const int type, const float alpha) { /* allows for 4 steps (red->yellow) */ - const float color_step = 1.0f / 48.0f; + const int steps = 48; + const float color_step = 1.0f / steps; int a; float h = hsv[0], s = hsv[1], v = hsv[2]; float dx, dy, sx1, sx2, sy; @@ -2400,9 +2460,14 @@ void ui_draw_gradient(const rcti *rect, const float hsv[3], const int type, cons copy_v3_v3(col1[3], col1[2]); break; } - + /* old below */ + VertexFormat *format = immVertexFormat(); + unsigned int pos = add_attrib(format, "pos", GL_FLOAT, 2, KEEP_FLOAT); + unsigned int col = add_attrib(format, "color", GL_FLOAT, 4, KEEP_FLOAT); + immBindBuiltinProgram(GPU_SHADER_2D_SMOOTH_COLOR); + immBegin(GL_TRIANGLES, steps * 3 * 6); for (dx = 0.0f; dx < 0.999f; dx += color_step) { /* 0.999 = prevent float inaccuracy for steps */ const float dx_next = dx + color_step; @@ -2460,22 +2525,29 @@ void ui_draw_gradient(const rcti *rect, const float hsv[3], const int type, cons sy = rect->ymin; dy = (float)BLI_rcti_size_y(rect) / 3.0f; - glBegin(GL_QUADS); for (a = 0; a < 3; a++, sy += dy) { - glColor4f(col0[a][0], col0[a][1], col0[a][2], alpha); - glVertex2f(sx1, sy); + immAttrib4f(col, col0[a][0], col0[a][1], col0[a][2], alpha); + immVertex2f(pos, sx1, sy); - glColor4f(col1[a][0], col1[a][1], col1[a][2], alpha); - glVertex2f(sx2, sy); + immAttrib4f(col, col1[a][0], col1[a][1], col1[a][2], alpha); + immVertex2f(pos, sx2, sy); - glColor4f(col1[a + 1][0], col1[a + 1][1], col1[a + 1][2], alpha); - glVertex2f(sx2, sy + dy); + immAttrib4f(col, col1[a + 1][0], col1[a + 1][1], col1[a + 1][2], alpha); + immVertex2f(pos, sx2, sy + dy); + + immAttrib4f(col, col0[a][0], col0[a][1], col0[a][2], alpha); + immVertex2f(pos, sx1, sy); + + immAttrib4f(col, col1[a + 1][0], col1[a + 1][1], col1[a + 1][2], alpha); + immVertex2f(pos, sx2, sy + dy); - glColor4f(col0[a + 1][0], col0[a + 1][1], col0[a + 1][2], alpha); - glVertex2f(sx1, sy + dy); + immAttrib4f(col, col0[a + 1][0], col0[a + 1][1], col0[a + 1][2], alpha); + immVertex2f(pos, sx1, sy + dy); } - glEnd(); } + immEnd(); + + immUnbindProgram(); } bool ui_but_is_colorpicker_display_space(uiBut *but) @@ -2551,8 +2623,11 @@ static void ui_draw_but_HSVCUBE(uiBut *but, const rcti *rect) ui_hsv_cursor(x, y); /* outline */ - glColor3ub(0, 0, 0); - fdrawbox((rect->xmin), (rect->ymin), (rect->xmax), (rect->ymax)); + unsigned int pos = add_attrib(immVertexFormat(), "pos", GL_FLOAT, 2, KEEP_FLOAT); + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + immUniformColor3ub(0, 0, 0); + imm_draw_line_box(pos, (rect->xmin), (rect->ymin), (rect->xmax), (rect->ymax)); + immUnbindProgram(); } /* vertical 'value' slider, using new widget code */ @@ -2620,12 +2695,22 @@ static void ui_draw_separator(const rcti *rect, uiWidgetColors *wcol) wcol->text[2], 30 }; - + + unsigned int pos = add_attrib(immVertexFormat(), "pos", GL_FLOAT, 2, KEEP_FLOAT); + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + glEnable(GL_BLEND); - glColor4ubv(col); + immUniformColor4ubv(col); glLineWidth(1.0f); - sdrawline(rect->xmin, y, rect->xmax, y); + + immBegin(GL_LINES, 2); + immVertex2f(pos, rect->xmin, y); + immVertex2f(pos, rect->xmax, y); + immEnd(); + glDisable(GL_BLEND); + + immUnbindProgram(); } /* ************ button callbacks, draw ***************** */ @@ -2697,11 +2782,14 @@ bool ui_link_bezier_points(const rcti *rect, float coord_array[][2], int resol) } #define LINK_RESOL 24 -void ui_draw_link_bezier(const rcti *rect) +void ui_draw_link_bezier(const rcti *rect, const float color[4]) { float coord_array[LINK_RESOL + 1][2]; if (ui_link_bezier_points(rect, coord_array, LINK_RESOL)) { + unsigned int pos = add_attrib(immVertexFormat(), "pos", GL_FLOAT, 2, KEEP_FLOAT); + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + #if 0 /* unused */ /* we can reuse the dist variable here to increment the GL curve eval amount*/ const float dist = 1.0f / (float)LINK_RESOL; @@ -2709,13 +2797,17 @@ void ui_draw_link_bezier(const rcti *rect) glEnable(GL_BLEND); glEnable(GL_LINE_SMOOTH); - glEnableClientState(GL_VERTEX_ARRAY); - glVertexPointer(2, GL_FLOAT, 0, coord_array); - glDrawArrays(GL_LINE_STRIP, 0, LINK_RESOL + 1); - glDisableClientState(GL_VERTEX_ARRAY); + immUniformColor4fv(color); + + immBegin(GL_LINE_STRIP, LINK_RESOL + 1); + for (int i = 0; i <= LINK_RESOL; ++i) + immVertex2fv(pos, coord_array[i]); + immEnd(); glDisable(GL_BLEND); glDisable(GL_LINE_SMOOTH); + + immUnbindProgram(); } } @@ -2897,15 +2989,16 @@ static void widget_link(uiBut *but, uiWidgetColors *UNUSED(wcol), rcti *rect, in if (but->flag & UI_SELECT) { rcti rectlink; + float color[4]; - UI_ThemeColor(TH_TEXT_HI); + UI_GetThemeColor4fv(TH_TEXT_HI, color); rectlink.xmin = BLI_rcti_cent_x(rect); rectlink.ymin = BLI_rcti_cent_y(rect); rectlink.xmax = but->linkto[0]; rectlink.ymax = but->linkto[1]; - ui_draw_link_bezier(&rectlink); + ui_draw_link_bezier(&rectlink, color); } } @@ -3057,13 +3150,18 @@ static void widget_swatch(uiBut *but, uiWidgetColors *wcol, rcti *rect, int stat float bw = rgb_to_grayscale(col); bw += (bw < 0.5f) ? 0.5f : -0.5f; - - glColor4f(bw, bw, bw, 1.0); - glBegin(GL_TRIANGLES); - glVertex2f(rect->xmin + 0.1f * width, rect->ymin + 0.9f * height); - glVertex2f(rect->xmin + 0.1f * width, rect->ymin + 0.5f * height); - glVertex2f(rect->xmin + 0.5f * width, rect->ymin + 0.9f * height); - glEnd(); + + unsigned int pos = add_attrib(immVertexFormat(), "pos", GL_FLOAT, 2, KEEP_FLOAT); + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + + immUniformColor4f(bw, bw, bw, 1.0f); + immBegin(GL_TRIANGLES, 3); + immVertex2f(pos, rect->xmin + 0.1f * width, rect->ymin + 0.9f * height); + immVertex2f(pos, rect->xmin + 0.1f * width, rect->ymin + 0.5f * height); + immVertex2f(pos, rect->xmin + 0.5f * width, rect->ymin + 0.9f * height); + immEnd(); + + immUnbindProgram(); } } @@ -3364,7 +3462,7 @@ static void widget_draw_extra_mask(const bContext *C, uiBut *but, uiWidgetType * uiWidgetBase wtb; const float rad = 0.25f * U.widget_unit; unsigned char col[4]; - + /* state copy! */ wt->wcol = *(wt->wcol_theme); @@ -3374,12 +3472,17 @@ static void widget_draw_extra_mask(const bContext *C, uiBut *but, uiWidgetType * /* note: drawextra can change rect +1 or -1, to match round errors of existing previews */ but->block->drawextra(C, but->poin, but->block->drawextra_arg1, but->block->drawextra_arg2, rect); + unsigned int pos = add_attrib(immVertexFormat(), "pos", GL_FLOAT, 2, KEEP_FLOAT); + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + /* make mask to draw over image */ UI_GetThemeColor3ubv(TH_BACK, col); - glColor3ubv(col); - + immUniformColor3ubv(col); + round_box__edges(&wtb, UI_CNR_ALL, rect, 0.0f, rad); - widgetbase_outline(&wtb); + widgetbase_outline(&wtb, pos); + + immUnbindProgram(); } /* outline */ @@ -3888,15 +3991,21 @@ void ui_draw_menu_back(uiStyle *UNUSED(style), uiBlock *block, rcti *rect) wt->draw(&wt->wcol, rect, 0, 0); if (block) { + float draw_color[4]; + unsigned char *color = (unsigned char *)wt->wcol.text; + + draw_color[0] = ((float)color[0]) / 255.0f; + draw_color[1] = ((float)color[1]) / 255.0f; + draw_color[2] = ((float)color[2]) / 255.0f; + draw_color[3] = 1.0f; + if (block->flag & UI_BLOCK_CLIPTOP) { /* XXX no scaling for UI here yet */ - glColor3ubv((unsigned char *)wt->wcol.text); - UI_draw_icon_tri(BLI_rcti_cent_x(rect), rect->ymax - 8, 't'); + UI_draw_icon_tri(BLI_rcti_cent_x(rect), rect->ymax - 8, 't', draw_color); } if (block->flag & UI_BLOCK_CLIPBOTTOM) { /* XXX no scaling for UI here yet */ - glColor3ubv((unsigned char *)wt->wcol.text); - UI_draw_icon_tri(BLI_rcti_cent_x(rect), rect->ymin + 10, 'v'); + UI_draw_icon_tri(BLI_rcti_cent_x(rect), rect->ymin + 10, 'v', draw_color); } } } @@ -3914,33 +4023,21 @@ static void draw_disk_shaded( float y1, y2; float fac; unsigned char r_col[4]; + unsigned int pos, col; - glBegin(GL_TRIANGLE_STRIP); - - s = sinf(start); - c = cosf(start); - - y1 = s * radius_int; - y2 = s * radius_ext; - + VertexFormat *format = immVertexFormat(); + pos = add_attrib(format, "pos", GL_FLOAT, 2, KEEP_FLOAT); if (shaded) { - fac = (y1 + radius_ext) * radius_ext_scale; - round_box_shade_col4_r(r_col, col1, col2, fac); - - glColor4ubv(r_col); + col = add_attrib(format, "color", GL_UNSIGNED_BYTE, 4, NORMALIZE_INT_TO_FLOAT); + immBindBuiltinProgram(GPU_SHADER_2D_SMOOTH_COLOR); } - - glVertex2f(c * radius_int, s * radius_int); - - if (shaded) { - fac = (y2 + radius_ext) * radius_ext_scale; - round_box_shade_col4_r(r_col, col1, col2, fac); - - glColor4ubv(r_col); + else { + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + immUniformColor4ubv((unsigned char *)col1); } - glVertex2f(c * radius_ext, s * radius_ext); - for (i = 1; i < subd; i++) { + immBegin(GL_TRIANGLE_STRIP, subd * 2); + for (i = 0; i < subd; i++) { float a; a = start + ((i) / (float)(subd - 1)) * angle; @@ -3952,20 +4049,20 @@ static void draw_disk_shaded( if (shaded) { fac = (y1 + radius_ext) * radius_ext_scale; round_box_shade_col4_r(r_col, col1, col2, fac); - - glColor4ubv(r_col); + immAttrib4ubv(col, r_col); } - glVertex2f(c * radius_int, s * radius_int); + immVertex2f(pos, c * radius_int, s * radius_int); if (shaded) { fac = (y2 + radius_ext) * radius_ext_scale; round_box_shade_col4_r(r_col, col1, col2, fac); - - glColor4ubv(r_col); + immAttrib4ubv(col, r_col); } - glVertex2f(c * radius_ext, s * radius_ext); + immVertex2f(pos, c * radius_ext, s * radius_ext); } - glEnd(); + immEnd(); + + immUnbindProgram(); } void ui_draw_pie_center(uiBlock *block) @@ -3984,8 +4081,9 @@ void ui_draw_pie_center(uiBlock *block) float angle = atan2f(pie_dir[1], pie_dir[0]); float range = (block->pie_data.flags & UI_PIE_DEGREES_RANGE_LARGE) ? M_PI_2 : M_PI_4; - glPushMatrix(); - glTranslatef(cx, cy, 0.0f); + gpuMatrixBegin3D_legacy(); + gpuPushMatrix(); + gpuTranslate3f(cx, cy, 0.0f); glEnable(GL_BLEND); if (btheme->tui.wcol_pie_menu.shaded) { @@ -3994,8 +4092,7 @@ void ui_draw_pie_center(uiBlock *block) draw_disk_shaded(0.0f, (float)(M_PI * 2.0), pie_radius_internal, pie_radius_external, subd, col1, col2, true); } else { - glColor4ubv((GLubyte *)btheme->tui.wcol_pie_menu.inner); - draw_disk_shaded(0.0f, (float)(M_PI * 2.0), pie_radius_internal, pie_radius_external, subd, NULL, NULL, false); + draw_disk_shaded(0.0f, (float)(M_PI * 2.0), pie_radius_internal, pie_radius_external, subd, btheme->tui.wcol_pie_menu.inner, NULL, false); } if (!(block->pie_data.flags & UI_PIE_INVALID_DIR)) { @@ -4005,25 +4102,35 @@ void ui_draw_pie_center(uiBlock *block) draw_disk_shaded(angle - range / 2.0f, range, pie_radius_internal, pie_radius_external, subd, col1, col2, true); } else { - glColor4ubv((GLubyte *)btheme->tui.wcol_pie_menu.inner_sel); - draw_disk_shaded(angle - range / 2.0f, range, pie_radius_internal, pie_radius_external, subd, NULL, NULL, false); + draw_disk_shaded(angle - range / 2.0f, range, pie_radius_internal, pie_radius_external, subd, btheme->tui.wcol_pie_menu.inner, NULL, false); } } - glColor4ubv((GLubyte *)btheme->tui.wcol_pie_menu.outline); - glutil_draw_lined_arc(0.0f, (float)M_PI * 2.0f, pie_radius_internal, subd); - glutil_draw_lined_arc(0.0f, (float)M_PI * 2.0f, pie_radius_external, subd); + VertexFormat *format = immVertexFormat(); + unsigned int pos = add_attrib(format, "pos", GL_FLOAT, 2, KEEP_FLOAT); + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + immUniformColor4ubv((unsigned char *)btheme->tui.wcol_pie_menu.outline); + + imm_draw_lined_circle(pos, 0.0f, 0.0f, pie_radius_internal, subd); + imm_draw_lined_circle(pos, 0.0f, 0.0f, pie_radius_external, subd); + + immUnbindProgram(); if (U.pie_menu_confirm > 0 && !(block->pie_data.flags & (UI_PIE_INVALID_DIR | UI_PIE_CLICK_STYLE))) { float pie_confirm_radius = U.pixelsize * (pie_radius_internal + U.pie_menu_confirm); float pie_confirm_external = U.pixelsize * (pie_radius_internal + U.pie_menu_confirm + 7.0f); - glColor4ub(btheme->tui.wcol_pie_menu.text_sel[0], btheme->tui.wcol_pie_menu.text_sel[1], btheme->tui.wcol_pie_menu.text_sel[2], 64); - draw_disk_shaded(angle - range / 2.0f, range, pie_confirm_radius, pie_confirm_external, subd, NULL, NULL, false); + const char col[4] = {btheme->tui.wcol_pie_menu.text_sel[0], + btheme->tui.wcol_pie_menu.text_sel[1], + btheme->tui.wcol_pie_menu.text_sel[2], + 64}; + + draw_disk_shaded(angle - range / 2.0f, range, pie_confirm_radius, pie_confirm_external, subd, col, NULL, false); } glDisable(GL_BLEND); - glPopMatrix(); + gpuPopMatrix(); + gpuMatrixEnd(); } @@ -4107,8 +4214,7 @@ void ui_draw_menu_item(uiFontStyle *fstyle, rcti *rect, const char *name, int ic UI_text_clip_middle_ex(fstyle, drawstr, okwidth, minwidth, max_len, '\0'); } - glColor4ubv((unsigned char *)wt->wcol.text); - UI_fontstyle_draw(fstyle, rect, drawstr); + UI_fontstyle_draw(fstyle, rect, drawstr, (unsigned char *)wt->wcol.text); } /* part text right aligned */ @@ -4116,7 +4222,7 @@ void ui_draw_menu_item(uiFontStyle *fstyle, rcti *rect, const char *name, int ic if (cpoin) { fstyle->align = UI_STYLE_TEXT_RIGHT; rect->xmax = _rect.xmax - 5; - UI_fontstyle_draw(fstyle, rect, cpoin + 1); + UI_fontstyle_draw(fstyle, rect, cpoin + 1, (unsigned char *)wt->wcol.text); *cpoin = UI_SEP_CHAR; } } @@ -4174,7 +4280,6 @@ void ui_draw_preview_item(uiFontStyle *fstyle, rcti *rect, const char *name, int BLI_strncpy(drawstr, name, sizeof(drawstr)); UI_text_clip_middle_ex(fstyle, drawstr, okwidth, minwidth, max_len, '\0'); - glColor4ubv((unsigned char *)wt->wcol.text); - UI_fontstyle_draw(fstyle, &trect, drawstr); + UI_fontstyle_draw(fstyle, &trect, drawstr, (unsigned char *)wt->wcol.text); } } diff --git a/source/blender/editors/interface/resources.c b/source/blender/editors/interface/resources.c index 539284030c2..a6235a8d26d 100644 --- a/source/blender/editors/interface/resources.c +++ b/source/blender/editors/interface/resources.c @@ -53,6 +53,8 @@ #include "BIF_gl.h" +#include "BLF_api.h" + #include "UI_interface.h" #include "UI_interface_icons.h" @@ -1272,25 +1274,35 @@ void UI_ThemeColor4(int colorid) cp = UI_ThemeGetColorPtr(theme_active, theme_spacetype, colorid); glColor4ubv(cp); - } /* set the color with offset for shades */ void UI_ThemeColorShade(int colorid, int offset) { - int r, g, b; + unsigned char col[4]; + UI_GetThemeColorShade4ubv(colorid, offset, col); + glColor4ubv(col); +} + +void UI_ThemeColorShadeAlpha(int colorid, int coloffset, int alphaoffset) +{ + int r, g, b, a; const unsigned char *cp; cp = UI_ThemeGetColorPtr(theme_active, theme_spacetype, colorid); - r = offset + (int) cp[0]; + r = coloffset + (int) cp[0]; CLAMP(r, 0, 255); - g = offset + (int) cp[1]; + g = coloffset + (int) cp[1]; CLAMP(g, 0, 255); - b = offset + (int) cp[2]; + b = coloffset + (int) cp[2]; CLAMP(b, 0, 255); - glColor4ub(r, g, b, cp[3]); + a = alphaoffset + (int) cp[3]; + CLAMP(a, 0, 255); + + glColor4ub(r, g, b, a); } -void UI_ThemeColorShadeAlpha(int colorid, int coloffset, int alphaoffset) + +void UI_GetThemeColorShadeAlpha4ubv(int colorid, int coloffset, int alphaoffset, unsigned char col[4]) { int r, g, b, a; const unsigned char *cp; @@ -1304,7 +1316,11 @@ void UI_ThemeColorShadeAlpha(int colorid, int coloffset, int alphaoffset) CLAMP(b, 0, 255); a = alphaoffset + (int) cp[3]; CLAMP(a, 0, 255); - glColor4ub(r, g, b, a); + + col[0] = r; + col[1] = g; + col[2] = b; + col[3] = a; } void UI_GetThemeColorBlend3ubv(int colorid1, int colorid2, float fac, unsigned char col[3]) @@ -1372,6 +1388,12 @@ void UI_ThemeColorBlendShadeAlpha(int colorid1, int colorid2, float fac, int off glColor4ub(r, g, b, a); } +void UI_FontThemeColor(int fontid, int colorid) +{ + unsigned char color[4]; + UI_GetThemeColor4ubv(colorid, color); + BLF_color4ubv(fontid, color); +} /* get individual values, not scaled */ float UI_GetThemeValuef(int colorid) @@ -1470,6 +1492,89 @@ void UI_GetThemeColorShade3ubv(int colorid, int offset, unsigned char col[3]) col[2] = b; } +void UI_GetThemeColorBlendShade3ubv(int colorid1, int colorid2, float fac, int offset, unsigned char col[3]) +{ + const unsigned char *cp1, *cp2; + + cp1 = UI_ThemeGetColorPtr(theme_active, theme_spacetype, colorid1); + cp2 = UI_ThemeGetColorPtr(theme_active, theme_spacetype, colorid2); + + CLAMP(fac, 0.0f, 1.0f); + col[0] = offset + floorf((1.0f - fac) * cp1[0] + fac * cp2[0]); + col[1] = offset + floorf((1.0f - fac) * cp1[1] + fac * cp2[1]); + col[2] = offset + floorf((1.0f - fac) * cp1[2] + fac * cp2[2]); + + CLAMP(col[0], 0, 255); + CLAMP(col[1], 0, 255); + CLAMP(col[2], 0, 255); +} + +void UI_GetThemeColorShade4ubv(int colorid, int offset, unsigned char col[4]) +{ + int r, g, b; + const unsigned char *cp; + + cp = UI_ThemeGetColorPtr(theme_active, theme_spacetype, colorid); + r = offset + (int) cp[0]; + CLAMP(r, 0, 255); + g = offset + (int) cp[1]; + CLAMP(g, 0, 255); + b = offset + (int) cp[2]; + CLAMP(b, 0, 255); + + col[0] = r; + col[1] = g; + col[2] = b; + col[3] = cp[3]; +} + +void UI_GetThemeColorShadeAlpha4fv(int colorid, int coloffset, int alphaoffset, float col[4]) +{ + int r, g, b, a; + const unsigned char *cp; + + cp = UI_ThemeGetColorPtr(theme_active, theme_spacetype, colorid); + + r = coloffset + (int) cp[0]; + CLAMP(r, 0, 255); + g = coloffset + (int) cp[1]; + CLAMP(g, 0, 255); + b = coloffset + (int) cp[2]; + CLAMP(b, 0, 255); + a = alphaoffset + (int) cp[3]; + CLAMP(b, 0, 255); + + col[0] = ((float)r) / 255.0f; + col[1] = ((float)g) / 255.0f; + col[2] = ((float)b) / 255.0f; + col[3] = ((float)a) / 255.0f; +} + +void UI_GetThemeColorBlendShade4fv(int colorid1, int colorid2, float fac, int offset, float col[4]) +{ + int r, g, b, a; + const unsigned char *cp1, *cp2; + + cp1 = UI_ThemeGetColorPtr(theme_active, theme_spacetype, colorid1); + cp2 = UI_ThemeGetColorPtr(theme_active, theme_spacetype, colorid2); + + CLAMP(fac, 0.0f, 1.0f); + + r = offset + floorf((1.0f - fac) * cp1[0] + fac * cp2[0]); + CLAMP(r, 0, 255); + g = offset + floorf((1.0f - fac) * cp1[1] + fac * cp2[1]); + CLAMP(g, 0, 255); + b = offset + floorf((1.0f - fac) * cp1[2] + fac * cp2[2]); + CLAMP(b, 0, 255); + a = offset + floorf((1.0f - fac) * cp1[3] + fac * cp2[3]); + CLAMP(a, 0, 255); + + col[0] = ((float)r) / 255.0f; + col[1] = ((float)g) / 255.0f; + col[2] = ((float)b) / 255.0f; + col[3] = ((float)a) / 255.0f; +} + /* get the color, in char pointer */ void UI_GetThemeColor3ubv(int colorid, unsigned char col[3]) { @@ -1664,6 +1769,8 @@ void init_userdef_do_versions(void) U.tw_size = 25; /* percentage of window size */ U.tw_handlesize = 16; /* percentage of widget radius */ } + if (U.manipulator_scale == 0) + U.manipulator_scale = 75; if (U.pad_rot_angle == 0.0f) U.pad_rot_angle = 15.0f; diff --git a/source/blender/editors/interface/view2d.c b/source/blender/editors/interface/view2d.c index c78d97ef86f..5c2d4cafd84 100644 --- a/source/blender/editors/interface/view2d.c +++ b/source/blender/editors/interface/view2d.c @@ -49,6 +49,7 @@ #include "BKE_screen.h" #include "BKE_global.h" +#include "GPU_immediate.h" #include "WM_api.h" @@ -1100,9 +1101,6 @@ void UI_view2d_view_ortho(View2D *v2d) /* set matrix on all appropriate axes */ wmOrtho2(curmasked.xmin, curmasked.xmax, curmasked.ymin, curmasked.ymax); - - /* XXX is this necessary? */ - glLoadIdentity(); } /** @@ -1130,9 +1128,6 @@ void UI_view2d_view_orthoSpecial(ARegion *ar, View2D *v2d, const bool xaxis) wmOrtho2(curmasked.xmin - xofs, curmasked.xmax - xofs, -yofs, ar->winy - yofs); else wmOrtho2(-xofs, ar->winx - xofs, curmasked.ymin - yofs, curmasked.ymax - yofs); - - /* XXX is this necessary? */ - glLoadIdentity(); } @@ -1298,12 +1293,45 @@ void UI_view2d_grid_draw(View2D *v2d, View2DGrid *grid, int flag) { float vec1[2], vec2[2]; int a, step; + int vertical_minor_step = (BLI_rcti_size_x(&v2d->mask) + 1) / (U.v2d_min_gridsize * UI_DPI_FAC), + horizontal_major_step = (BLI_rcti_size_y(&v2d->mask) + 1) / (U.v2d_min_gridsize * UI_DPI_FAC); + unsigned char grid_line_color[3]; /* check for grid first, as it may not exist */ if (grid == NULL) return; - glBegin(GL_LINES); + /* Count the needed vertices for the gridlines */ + unsigned vertex_count = 0; + if (flag & V2D_VERTICAL_LINES) { + /* vertical lines */ + vertex_count += 2 * vertical_minor_step; /* minor gridlines */ + vertex_count += 2 * (vertical_minor_step + 2); /* major gridlines */ + } + if (flag & V2D_HORIZONTAL_LINES) { + /* horizontal lines */ + vertex_count += 2 * (horizontal_major_step + 1); /* major gridlines */ + + /* fine lines */ + if (flag & V2D_HORIZONTAL_FINELINES) + vertex_count += 2 * (horizontal_major_step + 1); + } + /* axes */ + if (flag & V2D_HORIZONTAL_AXIS) + vertex_count += 2; + if (flag & V2D_VERTICAL_AXIS) + vertex_count += 2; + + /* If there is nothing to render, exit early */ + if (vertex_count == 0) + return; + + VertexFormat *format = immVertexFormat(); + unsigned pos = add_attrib(format, "pos", GL_FLOAT, 2, KEEP_FLOAT); + unsigned color = add_attrib(format, "color", GL_UNSIGNED_BYTE, 3, NORMALIZE_INT_TO_FLOAT); + + immBindBuiltinProgram(GPU_SHADER_2D_FLAT_COLOR); + immBegin(GL_LINES, vertex_count); /* vertical lines */ if (flag & V2D_VERTICAL_LINES) { @@ -1313,24 +1341,31 @@ void UI_view2d_grid_draw(View2D *v2d, View2DGrid *grid, int flag) vec2[1] = v2d->cur.ymax; /* minor gridlines */ - step = (BLI_rcti_size_x(&v2d->mask) + 1) / (U.v2d_min_gridsize * UI_DPI_FAC); - UI_ThemeColor(TH_GRID); - - for (a = 0; a < step; a++) { - glVertex2fv(vec1); - glVertex2fv(vec2); - - vec2[0] = vec1[0] += grid->dx; + step = vertical_minor_step; + if (step != 0) { + UI_GetThemeColor3ubv(TH_GRID, grid_line_color); + + for (a = 0; a < step; a++) { + immSkipAttrib(color); + immVertex2fv(pos, vec1); + immAttrib3ubv(color, grid_line_color); + immVertex2fv(pos, vec2); + + vec2[0] = vec1[0] += grid->dx; + } } /* major gridlines */ vec2[0] = vec1[0] -= 0.5f * grid->dx; - UI_ThemeColorShade(TH_GRID, 16); + + UI_GetThemeColorShade3ubv(TH_GRID, 16, grid_line_color); step++; for (a = 0; a <= step; a++) { - glVertex2fv(vec1); - glVertex2fv(vec2); + immSkipAttrib(color); + immVertex2fv(pos, vec1); + immAttrib3ubv(color, grid_line_color); + immVertex2fv(pos, vec2); vec2[0] = vec1[0] -= grid->dx; } @@ -1343,12 +1378,15 @@ void UI_view2d_grid_draw(View2D *v2d, View2DGrid *grid, int flag) vec1[0] = grid->startx; vec2[0] = v2d->cur.xmax; - step = (BLI_rcti_size_y(&v2d->mask) + 1) / (U.v2d_min_gridsize * UI_DPI_FAC); - - UI_ThemeColor(TH_GRID); + step = horizontal_major_step; + + UI_GetThemeColor3ubv(TH_GRID, grid_line_color); + for (a = 0; a <= step; a++) { - glVertex2fv(vec1); - glVertex2fv(vec2); + immSkipAttrib(color); + immVertex2fv(pos, vec1); + immAttrib3ubv(color, grid_line_color); + immVertex2fv(pos, vec2); vec2[1] = vec1[1] += grid->dy; } @@ -1358,10 +1396,12 @@ void UI_view2d_grid_draw(View2D *v2d, View2DGrid *grid, int flag) step++; if (flag & V2D_HORIZONTAL_FINELINES) { - UI_ThemeColorShade(TH_GRID, 16); + UI_GetThemeColorShade3ubv(TH_GRID, 16, grid_line_color); for (a = 0; a < step; a++) { - glVertex2fv(vec1); - glVertex2fv(vec2); + immSkipAttrib(color); + immVertex2fv(pos, vec1); + immAttrib3ubv(color, grid_line_color); + immVertex2fv(pos, vec2); vec2[1] = vec1[1] -= grid->dy; } @@ -1369,7 +1409,7 @@ void UI_view2d_grid_draw(View2D *v2d, View2DGrid *grid, int flag) } /* Axes are drawn as darker lines */ - UI_ThemeColorShade(TH_GRID, -50); + UI_GetThemeColorShade3ubv(TH_GRID, -50, grid_line_color); /* horizontal axis */ if (flag & V2D_HORIZONTAL_AXIS) { @@ -1377,8 +1417,10 @@ void UI_view2d_grid_draw(View2D *v2d, View2DGrid *grid, int flag) vec2[0] = v2d->cur.xmax; vec1[1] = vec2[1] = 0.0f; - glVertex2fv(vec1); - glVertex2fv(vec2); + immSkipAttrib(color); + immVertex2fv(pos, vec1); + immAttrib3ubv(color, grid_line_color); + immVertex2fv(pos, vec2); } /* vertical axis */ @@ -1387,91 +1429,157 @@ void UI_view2d_grid_draw(View2D *v2d, View2DGrid *grid, int flag) vec2[1] = v2d->cur.ymax; vec1[0] = vec2[0] = 0.0f; - glVertex2fv(vec1); - glVertex2fv(vec2); + immSkipAttrib(color); + immVertex2fv(pos, vec1); + immAttrib3ubv(color, grid_line_color); + immVertex2fv(pos, vec2); } - glEnd(); + immEnd(); + immUnbindProgram(); } /* Draw a constant grid in given 2d-region */ void UI_view2d_constant_grid_draw(View2D *v2d) { - float start, step = 25.0f; - - UI_ThemeColorShade(TH_BACK, -10); + float start_x, start_y, step = 25.0f; + int count_x, count_y; - start = v2d->cur.xmin - (float)fmod(v2d->cur.xmin, step); + start_x = v2d->cur.xmin; + if (start_x < 0.0) + start_x += -(float)fmod(v2d->cur.xmin, step); + else + start_x += (step - (float)fmod(v2d->cur.xmin, step)); + + if (start_x > v2d->cur.xmax) + count_x = 0; + else + count_x = (v2d->cur.xmax - start_x) / step + 1; + + start_y = v2d->cur.ymin; + if (start_y < 0.0) + start_y += -(float)fmod(v2d->cur.ymin, step); + else + start_y += (step - (float)fabs(fmod(v2d->cur.ymin, step))); + + if (start_y > v2d->cur.ymax) + count_y = 0; + else + count_y = (v2d->cur.ymax - start_y) / step + 1; - glBegin(GL_LINES); - for (; start < v2d->cur.xmax; start += step) { - glVertex2f(start, v2d->cur.ymin); - glVertex2f(start, v2d->cur.ymax); - } + if (count_x > 0 || count_y > 0) { + VertexFormat *format = immVertexFormat(); + unsigned int pos = add_attrib(format, "pos", GL_FLOAT, 2, KEEP_FLOAT); + unsigned int color = add_attrib(format, "color", GL_FLOAT, 3, KEEP_FLOAT); + float theme_color[3]; - start = v2d->cur.ymin - (float)fmod(v2d->cur.ymin, step); - for (; start < v2d->cur.ymax; start += step) { - glVertex2f(v2d->cur.xmin, start); - glVertex2f(v2d->cur.xmax, start); - } + UI_GetThemeColorShade3fv(TH_BACK, -10, theme_color); + + immBindBuiltinProgram(GPU_SHADER_2D_FLAT_COLOR); + immBegin(GL_LINES, count_x * 2 + count_y * 2 + 4); + + immAttrib3fv(color, theme_color); + for (int i = 0; i < count_x ; start_x += step, i++) { + immVertex2f(pos, start_x, v2d->cur.ymin); + immVertex2f(pos, start_x, v2d->cur.ymax); + } + + for (int i = 0; i < count_y; start_y += step, i++) { + immVertex2f(pos, v2d->cur.xmin, start_y); + immVertex2f(pos, v2d->cur.xmax, start_y); + } - /* X and Y axis */ - UI_ThemeColorShade(TH_BACK, -18); - glVertex2f(0.0f, v2d->cur.ymin); - glVertex2f(0.0f, v2d->cur.ymax); - glVertex2f(v2d->cur.xmin, 0.0f); - glVertex2f(v2d->cur.xmax, 0.0f); + /* X and Y axis */ + UI_GetThemeColorShade3fv(TH_BACK, -18, theme_color); + + immAttrib3fv(color, theme_color); + immVertex2f(pos, 0.0f, v2d->cur.ymin); + immVertex2f(pos, 0.0f, v2d->cur.ymax); + immVertex2f(pos, v2d->cur.xmin, 0.0f); + immVertex2f(pos, v2d->cur.xmax, 0.0f); - glEnd(); + immEnd(); + immUnbindProgram(); + } } /* Draw a multi-level grid in given 2d-region */ void UI_view2d_multi_grid_draw(View2D *v2d, int colorid, float step, int level_size, int totlevels) { + /* Exit if there is nothing to draw */ + if (totlevels == 0) + return; + int offset = -10; float lstep = step; - int level; + unsigned char grid_line_color[3]; + + /* Make an estimate of at least how many vertices will be needed */ + unsigned vertex_count = 4; + vertex_count += 2 * ((int)((v2d->cur.xmax - v2d->cur.xmin) / lstep) + 1); + vertex_count += 2 * ((int)((v2d->cur.ymax - v2d->cur.ymin) / lstep) + 1); + + VertexFormat *format = immVertexFormat(); + unsigned pos = add_attrib(format, "pos", GL_FLOAT, 2, KEEP_FLOAT); + unsigned color = add_attrib(format, "color", GL_UNSIGNED_BYTE, 3, NORMALIZE_INT_TO_FLOAT); glLineWidth(1.0f); - for (level = 0; level < totlevels; ++level) { - int i; - float start; - - UI_ThemeColorShade(colorid, offset); + + immBindBuiltinProgram(GPU_SHADER_2D_FLAT_COLOR); + immBeginAtMost(GL_LINES, vertex_count); + + for (int level = 0; level < totlevels; ++level) { + UI_GetThemeColorShade3ubv(colorid, offset, grid_line_color); - i = (v2d->cur.xmin >= 0.0f ? -(int)(-v2d->cur.xmin / lstep) : (int)(v2d->cur.xmin / lstep)); - start = i * lstep; + int i = (int)(v2d->cur.xmin / lstep); + if (v2d->cur.xmin > 0.0f) + i++; + float start = i * lstep; - glBegin(GL_LINES); for (; start < v2d->cur.xmax; start += lstep, ++i) { if (i == 0 || (level < totlevels - 1 && i % level_size == 0)) continue; - glVertex2f(start, v2d->cur.ymin); - glVertex2f(start, v2d->cur.ymax); + + immSkipAttrib(color); + immVertex2f(pos, start, v2d->cur.ymin); + immAttrib3ubv(color, grid_line_color); + immVertex2f(pos, start, v2d->cur.ymax); } - i = (v2d->cur.ymin >= 0.0f ? -(int)(-v2d->cur.ymin / lstep) : (int)(v2d->cur.ymin / lstep)); + i = (int)(v2d->cur.ymin / lstep); + if (v2d->cur.ymin > 0.0f) + i++; start = i * lstep; for (; start < v2d->cur.ymax; start += lstep, ++i) { if (i == 0 || (level < totlevels - 1 && i % level_size == 0)) continue; - glVertex2f(v2d->cur.xmin, start); - glVertex2f(v2d->cur.xmax, start); + + immSkipAttrib(color); + immVertex2f(pos, v2d->cur.xmin, start); + immAttrib3ubv(color, grid_line_color); + immVertex2f(pos, v2d->cur.xmax, start); } - /* X and Y axis */ - UI_ThemeColorShade(colorid, offset - 8); - glVertex2f(0.0f, v2d->cur.ymin); - glVertex2f(0.0f, v2d->cur.ymax); - glVertex2f(v2d->cur.xmin, 0.0f); - glVertex2f(v2d->cur.xmax, 0.0f); - - glEnd(); - lstep *= level_size; offset -= 6; } + + /* X and Y axis */ + UI_GetThemeColorShade3ubv(colorid, -18 + ((totlevels - 1) * -6) , grid_line_color); + + immSkipAttrib(color); + immVertex2f(pos, 0.0f, v2d->cur.ymin); + immAttrib3ubv(color, grid_line_color); + immVertex2f(pos, 0.0f, v2d->cur.ymax); + + immSkipAttrib(color); + immVertex2f(pos, v2d->cur.xmin, 0.0f); + immAttrib3ubv(color, grid_line_color); + immVertex2f(pos, v2d->cur.xmax, 0.0f); + + immEnd(); + immUnbindProgram(); } /* the price we pay for not exposting structs :( */ @@ -1693,6 +1801,10 @@ void UI_view2d_scrollers_draw(const bContext *C, View2D *v2d, View2DScrollers *v Scene *scene = CTX_data_scene(C); rcti vert, hor; int scroll = view2d_scroll_mapped(v2d->scroll); + unsigned char scrollers_back_color[4]; + + /* Color for scrollbar backs */ + UI_GetThemeColor4ubv(TH_BACK, scrollers_back_color); /* make copies of rects for less typing */ vert = vs->vert; @@ -1704,7 +1816,6 @@ void UI_view2d_scrollers_draw(const bContext *C, View2D *v2d, View2DScrollers *v uiWidgetColors wcol = btheme->tui.wcol_scroll; rcti slider; int state; - unsigned char col[4]; slider.xmin = vs->hor_min; slider.xmax = vs->hor_max; @@ -1728,16 +1839,23 @@ void UI_view2d_scrollers_draw(const bContext *C, View2D *v2d, View2DScrollers *v } /* clean rect behind slider, but not with transparent background */ - UI_GetThemeColor4ubv(TH_BACK, col); - if (col[3] == 255) { - glColor3ub(col[0], col[1], col[2]); - glRecti(v2d->hor.xmin, v2d->hor.ymin, v2d->hor.xmax, v2d->hor.ymax); + if (scrollers_back_color[3] == 255) { + VertexFormat *format = immVertexFormat(); + unsigned pos = add_attrib(format, "pos", GL_INT, 2, CONVERT_INT_TO_FLOAT); + + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + + immUniformColor3ubv(scrollers_back_color); + immRecti(pos, v2d->hor.xmin, v2d->hor.ymin, v2d->hor.xmax, v2d->hor.ymax); + + immUnbindProgram(); } UI_draw_widget_scroll(&wcol, &hor, &slider, state); /* scale indicators */ if ((scroll & V2D_SCROLL_SCALE_HORIZONTAL) && (vs->grid)) { + const int font_id = BLF_default(); View2DGrid *grid = vs->grid; float fac, dfac, fac2, val; @@ -1752,7 +1870,7 @@ void UI_view2d_scrollers_draw(const bContext *C, View2D *v2d, View2DScrollers *v dfac = dfac * BLI_rcti_size_x(&hor); /* set starting value, and text color */ - UI_ThemeColor(TH_TEXT); + UI_FontThemeColor(font_id, TH_TEXT); val = grid->startx; /* if we're clamping to whole numbers only, make sure entries won't be repeated */ @@ -1764,7 +1882,7 @@ void UI_view2d_scrollers_draw(const bContext *C, View2D *v2d, View2DScrollers *v } if (vs->xunits == V2D_UNIT_FRAMES) grid->powerx = 1; - + /* draw numbers in the appropriate range */ if (dfac > 0.0f) { float h = 0.1f * UI_UNIT_Y + (float)(hor.ymin); @@ -1805,7 +1923,6 @@ void UI_view2d_scrollers_draw(const bContext *C, View2D *v2d, View2DScrollers *v uiWidgetColors wcol = btheme->tui.wcol_scroll; rcti slider; int state; - unsigned char col[4]; slider.xmin = vert.xmin; slider.xmax = vert.xmax; @@ -1829,10 +1946,16 @@ void UI_view2d_scrollers_draw(const bContext *C, View2D *v2d, View2DScrollers *v } /* clean rect behind slider, but not with transparent background */ - UI_GetThemeColor4ubv(TH_BACK, col); - if (col[3] == 255) { - glColor3ub(col[0], col[1], col[2]); - glRecti(v2d->vert.xmin, v2d->vert.ymin, v2d->vert.xmax, v2d->vert.ymax); + if (scrollers_back_color[3] == 255) { + VertexFormat *format = immVertexFormat(); + unsigned pos = add_attrib(format, "pos", GL_INT, 2, CONVERT_INT_TO_FLOAT); + + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + + immUniformColor3ubv(scrollers_back_color); + immRecti(pos, v2d->vert.xmin, v2d->vert.ymin, v2d->vert.xmax, v2d->vert.ymax); + + immUnbindProgram(); } UI_draw_widget_scroll(&wcol, &vert, &slider, state); @@ -1856,7 +1979,8 @@ void UI_view2d_scrollers_draw(const bContext *C, View2D *v2d, View2DScrollers *v dfac = dfac * BLI_rcti_size_y(&vert); /* set starting value, and text color */ - UI_ThemeColor(TH_TEXT); + const int font_id = BLF_default(); + UI_FontThemeColor(font_id, TH_TEXT); val = grid->starty; /* if vertical clamping (to whole numbers) is used (i.e. in Sequencer), apply correction */ @@ -1865,9 +1989,8 @@ void UI_view2d_scrollers_draw(const bContext *C, View2D *v2d, View2DScrollers *v /* draw vertical steps */ if (dfac > 0.0f) { - - BLF_rotation_default(M_PI_2); - BLF_enable_default(BLF_ROTATION); + BLF_rotation(font_id, M_PI_2); + BLF_enable(font_id, BLF_ROTATION); for (; fac < vert.ymax - 10; fac += dfac, val += grid->dy) { @@ -1878,7 +2001,7 @@ void UI_view2d_scrollers_draw(const bContext *C, View2D *v2d, View2DScrollers *v scroll_printstr(scene, (float)(vert.xmax) - 2.0f, fac, val, grid->powery, vs->yunits, 'v'); } - BLF_disable_default(BLF_ROTATION); + BLF_disable(font_id, BLF_ROTATION); } } } @@ -2392,7 +2515,8 @@ void UI_view2d_text_cache_draw(ARegion *ar) int col_pack_prev = 0; /* investigate using BLF_ascender() */ - const float default_height = g_v2d_strings ? BLF_height_default("28", 3) : 0.0f; + const int font_id = BLF_default(); + const float default_height = g_v2d_strings ? BLF_height(font_id, "28", 3) : 0.0f; wmOrtho2_region_pixelspace(ar); @@ -2403,7 +2527,7 @@ void UI_view2d_text_cache_draw(ARegion *ar) if (yofs < 1) yofs = 1; if (col_pack_prev != v2s->col.pack) { - glColor3ubv(v2s->col.ub); + BLF_color3ubv(font_id, v2s->col.ub); col_pack_prev = v2s->col.pack; } @@ -2411,11 +2535,11 @@ void UI_view2d_text_cache_draw(ARegion *ar) BLF_draw_default((float)(v2s->mval[0] + xofs), (float)(v2s->mval[1] + yofs), 0.0, v2s->str, BLF_DRAW_STR_DUMMY_MAX); else { - BLF_clipping_default(v2s->rect.xmin - 4, v2s->rect.ymin - 4, v2s->rect.xmax + 4, v2s->rect.ymax + 4); - BLF_enable_default(BLF_CLIPPING); + BLF_enable(font_id, BLF_CLIPPING); + BLF_clipping(font_id, v2s->rect.xmin - 4, v2s->rect.ymin - 4, v2s->rect.xmax + 4, v2s->rect.ymax + 4); BLF_draw_default(v2s->rect.xmin + xofs, v2s->rect.ymin + yofs, 0.0f, v2s->str, BLF_DRAW_STR_DUMMY_MAX); - BLF_disable_default(BLF_CLIPPING); + BLF_disable(font_id, BLF_CLIPPING); } } g_v2d_strings = NULL; @@ -2424,11 +2548,6 @@ void UI_view2d_text_cache_draw(ARegion *ar) BLI_memarena_free(g_v2d_strings_arena); g_v2d_strings_arena = NULL; } - - // glMatrixMode(GL_PROJECTION); - // glPopMatrix(); - // glMatrixMode(GL_MODELVIEW); - // glPopMatrix(); } diff --git a/source/blender/editors/mask/mask_draw.c b/source/blender/editors/mask/mask_draw.c index 2b4f94a37ef..b20862e7630 100644 --- a/source/blender/editors/mask/mask_draw.c +++ b/source/blender/editors/mask/mask_draw.c @@ -36,6 +36,7 @@ #include "BLI_math.h" #include "BLI_rect.h" #include "BLI_task.h" +#include "BLI_listbase.h" #include "BKE_context.h" #include "BKE_mask.h" @@ -48,10 +49,11 @@ #include "ED_clip.h" #include "ED_mask.h" /* own include */ #include "ED_space_api.h" -#include "BIF_gl.h" + #include "BIF_glutil.h" -#include "GPU_basic_shader.h" +#include "GPU_immediate.h" +#include "GPU_draw.h" #include "UI_resources.h" #include "UI_view2d.h" @@ -93,40 +95,6 @@ static void mask_spline_feather_color_get(MaskLayer *UNUSED(masklay), MaskSpline r_rgb[3] = 255; } -#if 0 -static void draw_spline_parents(MaskLayer *UNUSED(masklay), MaskSpline *spline) -{ - int i; - MaskSplinePoint *points_array = BKE_mask_spline_point_array(spline); - - if (!spline->tot_point) - return; - - GPU_basic_shader_bind_enable(GPU_SHADER_LINE | GPU_SHADER_STIPPLE); - GPU_basic_shader_line_stipple(1, 0xAAAA); - - glColor3ub(0, 0, 0); - glBegin(GL_LINES); - - for (i = 0; i < spline->tot_point; i++) { - MaskSplinePoint *point = &points_array[i]; - BezTriple *bezt = &point->bezt; - - if (point->parent.id) { - glVertex2f(bezt->vec[1][0], - bezt->vec[1][1]); - - glVertex2f(bezt->vec[1][0] - point->parent.offset[0], - bezt->vec[1][1] - point->parent.offset[1]); - } - } - - glEnd(); - - GPU_basic_shader_bind_disable(GPU_SHADER_LINE | GPU_SHADER_STIPPLE); -} -#endif - static void mask_point_undistort_pos(SpaceClip *sc, float r_co[2], const float co[2]) { BKE_mask_coord_to_movieclip(sc->clip, &sc->user, r_co, co); @@ -134,46 +102,9 @@ static void mask_point_undistort_pos(SpaceClip *sc, float r_co[2], const float c BKE_mask_coord_from_movieclip(sc->clip, &sc->user, r_co, r_co); } -static void draw_circle(const float x, const float y, - const float size, const bool fill, - const float xscale, const float yscale) -{ - static GLuint wire_displist = 0; - static GLuint fill_displist = 0; - GLuint displist = fill ? fill_displist : wire_displist; - - /* Initialize round circle shape. */ - if (displist == 0) { - GLUquadricObj *qobj; - - displist = glGenLists(1); - glNewList(displist, GL_COMPILE); - - qobj = gluNewQuadric(); - gluQuadricDrawStyle(qobj, fill ? GLU_FILL : GLU_SILHOUETTE); - gluDisk(qobj, 0, 0.7, 8, 1); - gluDeleteQuadric(qobj); - - glEndList(); - - if (fill) { - fill_displist = displist; - } - else { - wire_displist = displist; - } - } - - glPushMatrix(); - glTranslatef(x, y, 0.0f); - glScalef(1.0f / xscale * size, 1.0f / yscale * size, 1.0f); - glCallList(displist); - glPopMatrix(); -} - static void draw_single_handle(const MaskLayer *mask_layer, const MaskSplinePoint *point, const eMaskWhichHandle which_handle, const int draw_type, - const float handle_size, const float xscale, const float yscale, + const float handle_size, const float point_pos[2], const float handle_pos[2]) { const BezTriple *bezt = &point->bezt; @@ -190,54 +121,70 @@ static void draw_single_handle(const MaskLayer *mask_layer, const MaskSplinePoin return; } + VertexFormat *format = immVertexFormat(); + unsigned pos = add_attrib(format, "pos", COMP_F32, 2, KEEP_FLOAT); + const unsigned char rgb_gray[4] = {0x60, 0x60, 0x60, 0xff}; + + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + immUniformColor3ubv(rgb_gray); + /* this could be split into its own loop */ if (draw_type == MASK_DT_OUTLINE) { - const unsigned char rgb_gray[4] = {0x60, 0x60, 0x60, 0xff}; - glLineWidth(3); - glColor4ubv(rgb_gray); - glBegin(GL_LINES); - glVertex2fv(point_pos); - glVertex2fv(handle_pos); - glEnd(); + glLineWidth(3.0f); + immBegin(PRIM_LINES, 2); + immVertex2fv(pos, point_pos); + immVertex2fv(pos, handle_pos); + immEnd(); } switch (handle_type) { case HD_FREE: - UI_ThemeColor(TH_HANDLE_FREE); + immUniformThemeColor(TH_HANDLE_FREE); break; case HD_AUTO: - UI_ThemeColor(TH_HANDLE_AUTO); + immUniformThemeColor(TH_HANDLE_AUTO); break; case HD_ALIGN: case HD_ALIGN_DOUBLESIDE: - UI_ThemeColor(TH_HANDLE_ALIGN); + immUniformThemeColor(TH_HANDLE_ALIGN); break; } - glLineWidth(1); - glBegin(GL_LINES); - glVertex2fv(point_pos); - glVertex2fv(handle_pos); - glEnd(); + glLineWidth(1.0f); + immBegin(PRIM_LINES, 2); + immVertex2fv(pos, point_pos); + immVertex2fv(pos, handle_pos); + immEnd(); + immUnbindProgram(); /* draw handle points */ + immBindBuiltinProgram(GPU_SHADER_2D_POINT_UNIFORM_SIZE_UNIFORM_COLOR_OUTLINE_SMOOTH); + immUniform1f("size", handle_size); + immUniform1f("outlineWidth", 1.5f); + + float point_color[4] = { 1.0f, 1.0f, 1.0f, 1.0f }; /* active color by default */ if (MASKPOINT_ISSEL_HANDLE(point, which_handle)) { - if (point == mask_layer->act_point) - glColor3f(1.0f, 1.0f, 1.0f); - else - UI_ThemeColor(TH_HANDLE_VERTEX_SELECT); + if (point != mask_layer->act_point) { + UI_GetThemeColor3fv(TH_HANDLE_VERTEX_SELECT, point_color); + } } else { - UI_ThemeColor(TH_HANDLE_VERTEX); + UI_GetThemeColor3fv(TH_HANDLE_VERTEX, point_color); } - draw_circle(handle_pos[0], handle_pos[1], handle_size, false, xscale, yscale); + immUniform4fv("outlineColor", point_color); + immUniformColor3fvAlpha(point_color, 0.25f); + + immBegin(PRIM_POINTS, 1); + immVertex2fv(pos, handle_pos); + immEnd(); + + immUnbindProgram(); } /* return non-zero if spline is selected */ static void draw_spline_points(const bContext *C, MaskLayer *masklay, MaskSpline *spline, - const char draw_flag, const char draw_type, - const float xscale, const float yscale) + const char draw_flag, const char draw_type) { const bool is_spline_sel = (spline->flag & SELECT) && (masklay->restrictflag & MASK_RESTRICT_SELECT) == 0; const bool is_smooth = (draw_flag & MASK_DRAWFLAG_SMOOTH) != 0; @@ -247,7 +194,7 @@ static void draw_spline_points(const bContext *C, MaskLayer *masklay, MaskSpline SpaceClip *sc = CTX_wm_space_clip(C); bool undistort = false; - int i, handle_size, tot_feather_point; + int tot_feather_point; float (*feather_points)[2], (*fp)[2]; float min[2], max[2]; @@ -258,22 +205,24 @@ static void draw_spline_points(const bContext *C, MaskLayer *masklay, MaskSpline undistort = sc->clip && (sc->user.render_flag & MCLIP_PROXY_RENDER_UNDISTORT); /* TODO, add this to sequence editor */ - handle_size = UI_GetThemeValuef(TH_HANDLE_VERTEX_SIZE) * U.pixelsize; - - glPointSize(handle_size); + float handle_size = 2.0f * UI_GetThemeValuef(TH_HANDLE_VERTEX_SIZE) * U.pixelsize; mask_spline_color_get(masklay, spline, is_spline_sel, rgb_spline); + VertexFormat *format = immVertexFormat(); + unsigned int pos = add_attrib(format, "pos", COMP_F32, 2, KEEP_FLOAT); + + immBindBuiltinProgram(GPU_SHADER_2D_POINT_UNIFORM_SIZE_UNIFORM_COLOR_SMOOTH); + immUniform1f("size", 0.7f * handle_size); + /* feather points */ feather_points = fp = BKE_mask_spline_feather_points(spline, &tot_feather_point); - for (i = 0; i < spline->tot_point; i++) { + for (int i = 0; i < spline->tot_point; i++) { /* watch it! this is intentionally not the deform array, only check for sel */ MaskSplinePoint *point = &spline->points[i]; - int j; - - for (j = 0; j <= point->tot_uw; j++) { + for (int j = 0; j <= point->tot_uw; j++) { float feather_point[2]; bool sel = false; @@ -291,32 +240,32 @@ static void draw_spline_points(const bContext *C, MaskLayer *masklay, MaskSpline if (sel) { if (point == masklay->act_point) - glColor3f(1.0f, 1.0f, 1.0f); + immUniformColor3f(1.0f, 1.0f, 1.0f); else - UI_ThemeColor(TH_HANDLE_VERTEX_SELECT); + immUniformThemeColor(TH_HANDLE_VERTEX_SELECT); } else { - UI_ThemeColor(TH_HANDLE_VERTEX); + immUniformThemeColor(TH_HANDLE_VERTEX); } - glBegin(GL_POINTS); - glVertex2fv(feather_point); - glEnd(); + immBegin(PRIM_POINTS, 1); + immVertex2fv(pos, feather_point); + immEnd(); fp++; } } MEM_freeN(feather_points); + immUnbindProgram(); + if (is_smooth) { glEnable(GL_LINE_SMOOTH); - glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); } /* control points */ INIT_MINMAX2(min, max); - for (i = 0; i < spline->tot_point; i++) { + for (int i = 0; i < spline->tot_point; i++) { /* watch it! this is intentionally not the deform array, only check for sel */ MaskSplinePoint *point = &spline->points[i]; @@ -339,7 +288,7 @@ static void draw_spline_points(const bContext *C, MaskLayer *masklay, MaskSpline mask_point_undistort_pos(sc, handle, handle); } draw_single_handle(masklay, point, MASK_WHICH_HANDLE_STICK, - draw_type, handle_size, xscale, yscale, vert, handle); + draw_type, handle_size, vert, handle); } else { float handle_left[2], handle_right[2]; @@ -350,53 +299,62 @@ static void draw_spline_points(const bContext *C, MaskLayer *masklay, MaskSpline mask_point_undistort_pos(sc, handle_left, handle_left); } draw_single_handle(masklay, point, MASK_WHICH_HANDLE_LEFT, - draw_type, handle_size, xscale, yscale, vert, handle_left); + draw_type, handle_size, vert, handle_left); draw_single_handle(masklay, point, MASK_WHICH_HANDLE_RIGHT, - draw_type, handle_size, xscale, yscale, vert, handle_right); + draw_type, handle_size, vert, handle_right); } + /* bind program in loop so it does not interfere with draw_single_handle */ + immBindBuiltinProgram(GPU_SHADER_2D_POINT_UNIFORM_SIZE_UNIFORM_COLOR_SMOOTH); + /* draw CV point */ if (MASKPOINT_ISSEL_KNOT(point)) { if (point == masklay->act_point) - glColor3f(1.0f, 1.0f, 1.0f); + immUniformColor3f(1.0f, 1.0f, 1.0f); else - UI_ThemeColor(TH_HANDLE_VERTEX_SELECT); + immUniformThemeColor(TH_HANDLE_VERTEX_SELECT); } else - UI_ThemeColor(TH_HANDLE_VERTEX); + immUniformThemeColor(TH_HANDLE_VERTEX); - glBegin(GL_POINTS); - glVertex2fv(vert); - glEnd(); + immBegin(PRIM_POINTS, 1); + immVertex2fv(pos, vert); + immEnd(); + + immUnbindProgram(); minmax_v2v2_v2(min, max, vert); } + if (is_smooth) { + glDisable(GL_LINE_SMOOTH); + } + if (is_spline_sel) { - float x = (min[0] + max[0]) / 2.0f; - float y = (min[1] + max[1]) / 2.0f; - /* TODO(sergey): Remove hardcoded colors. */ + float x = (min[0] + max[0]) * 0.5f; + float y = (min[1] + max[1]) * 0.5f; + + immBindBuiltinProgram(GPU_SHADER_2D_POINT_UNIFORM_SIZE_UNIFORM_COLOR_OUTLINE_SMOOTH); + immUniform1f("outlineWidth", 1.5f); + if (masklay->act_spline == spline) { - glColor3ub(255, 255, 255); + immUniformColor3f(1.0f, 1.0f, 1.0f); } else { - glColor3ub(255, 255, 0); + immUniformColor3f(1.0f, 1.0f, 0.0f); } - draw_circle(x, y, 6.0f, true, xscale, yscale); + immUniform4f("outlineColor", 0.0f, 0.0f, 0.0f, 1.0f); + immUniform1f("size", 12.0f); - glColor3ub(0, 0, 0); - draw_circle(x, y, 6.0f, false, xscale, yscale); - } + immBegin(PRIM_POINTS, 1); + immVertex2f(pos, x, y); + immEnd(); - if (is_smooth) { - glDisable(GL_LINE_SMOOTH); - glDisable(GL_BLEND); + immUnbindProgram(); } } -/* #define USE_XOR */ - static void mask_color_active_tint(unsigned char r_rgb[4], const unsigned char rgb[4], const bool is_active) { if (!is_active) { @@ -410,13 +368,21 @@ static void mask_color_active_tint(unsigned char r_rgb[4], const unsigned char r } } +static void mask_draw_array(unsigned int pos, PrimitiveType prim_type, const float (*points)[2], unsigned int vertex_ct) +{ + immBegin(prim_type, vertex_ct); + for (unsigned int i = 0; i < vertex_ct; ++i) { + immVertex2fv(pos, points[i]); + } + immEnd(); +} + static void mask_draw_curve_type(const bContext *C, MaskSpline *spline, float (*orig_points)[2], int tot_point, - const bool is_feather, const bool is_smooth, const bool is_active, + const bool is_feather, const bool is_active, const unsigned char rgb_spline[4], const char draw_type) { - const int draw_method = (spline->flag & MASK_SPLINE_CYCLIC) ? GL_LINE_LOOP : GL_LINE_STRIP; + const PrimitiveType draw_method = (spline->flag & MASK_SPLINE_CYCLIC) ? PRIM_LINE_LOOP : PRIM_LINE_STRIP; const unsigned char rgb_black[4] = {0x00, 0x00, 0x00, 0xff}; -// const unsigned char rgb_white[4] = {0xff, 0xff, 0xff, 0xff}; unsigned char rgb_tmp[4]; SpaceClip *sc = CTX_wm_space_clip(C); float (*points)[2] = orig_points; @@ -425,65 +391,45 @@ static void mask_draw_curve_type(const bContext *C, MaskSpline *spline, float (* const bool undistort = sc->clip && (sc->user.render_flag & MCLIP_PROXY_RENDER_UNDISTORT); if (undistort) { - int i; - points = MEM_callocN(2 * tot_point * sizeof(float), "undistorthed mask curve"); - for (i = 0; i < tot_point; i++) { + for (int i = 0; i < tot_point; i++) { mask_point_undistort_pos(sc, points[i], orig_points[i]); } } } - glEnableClientState(GL_VERTEX_ARRAY); - glVertexPointer(2, GL_FLOAT, 0, points); + VertexFormat *format = immVertexFormat(); + unsigned int pos = add_attrib(format, "pos", COMP_F32, 2, KEEP_FLOAT); switch (draw_type) { case MASK_DT_OUTLINE: - glLineWidth(3); + /* TODO(merwin): use fancy line shader here + * probably better with geometry shader (after core profile switch) + */ + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + + glLineWidth(3.0f); mask_color_active_tint(rgb_tmp, rgb_black, is_active); - glColor4ubv(rgb_tmp); + immUniformColor4ubv(rgb_tmp); + mask_draw_array(pos, draw_method, points, tot_point); - glDrawArrays(draw_method, 0, tot_point); + glLineWidth(1.0f); - glLineWidth(1); mask_color_active_tint(rgb_tmp, rgb_spline, is_active); - glColor4ubv(rgb_tmp); - glDrawArrays(draw_method, 0, tot_point); + immUniformColor4ubv(rgb_tmp); + mask_draw_array(pos, draw_method, points, tot_point); + immUnbindProgram(); break; - case MASK_DT_DASH: - default: - GPU_basic_shader_bind_enable(GPU_SHADER_LINE | GPU_SHADER_STIPPLE); - GPU_basic_shader_line_stipple(3, 0xAAAA); - -#ifdef USE_XOR - glEnable(GL_COLOR_LOGIC_OP); - glLogicOp(GL_OR); -#endif - mask_color_active_tint(rgb_tmp, rgb_spline, is_active); - glColor4ubv(rgb_tmp); - glEnableClientState(GL_VERTEX_ARRAY); - glVertexPointer(2, GL_FLOAT, 0, points); - glDrawArrays(draw_method, 0, tot_point); - -#ifdef USE_XOR - glDisable(GL_COLOR_LOGIC_OP); -#endif - mask_color_active_tint(rgb_tmp, rgb_black, is_active); - glColor4ubv(rgb_tmp); - GPU_basic_shader_line_stipple(3, 0x5555); - glDrawArrays(draw_method, 0, tot_point); - - GPU_basic_shader_bind_disable(GPU_SHADER_LINE | GPU_SHADER_STIPPLE); - break; - - case MASK_DT_BLACK: case MASK_DT_WHITE: + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + glLineWidth(1.0f); + if (draw_type == MASK_DT_BLACK) { rgb_tmp[0] = rgb_tmp[1] = rgb_tmp[2] = 0; } else { rgb_tmp[0] = rgb_tmp[1] = rgb_tmp[2] = 255; } /* alpha values seem too low but gl draws many points that compensate for it */ @@ -496,26 +442,39 @@ static void mask_draw_curve_type(const bContext *C, MaskSpline *spline, float (* rgb_tmp[2] = (unsigned char)(((short)rgb_tmp[2] + (short)rgb_spline[2]) / 2); } - if (is_smooth == false && is_feather) { - glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - } - mask_color_active_tint(rgb_tmp, rgb_tmp, is_active); - glColor4ubv(rgb_tmp); + immUniformColor4ubv(rgb_tmp); + mask_draw_array(pos, draw_method, points, tot_point); - glEnableClientState(GL_VERTEX_ARRAY); - glVertexPointer(2, GL_FLOAT, 0, points); - glDrawArrays(draw_method, 0, tot_point); + immUnbindProgram(); + break; - if (is_smooth == false && is_feather) { - glDisable(GL_BLEND); - } + case MASK_DT_DASH: + /* TODO(merwin): use dashed line shader here + * probably better with geometry shader (after core profile switch) + */ +#if 0 + glLineWidth(1.0f); + + GPU_basic_shader_bind_enable(GPU_SHADER_LINE | GPU_SHADER_STIPPLE); + GPU_basic_shader_line_stipple(3, 0xAAAA); + mask_color_active_tint(rgb_tmp, rgb_spline, is_active); + immUniformColor4ubv(rgb_tmp); + mask_draw_array(pos, draw_method, points, tot_point); + + mask_color_active_tint(rgb_tmp, rgb_black, is_active); + immUniformColor4ubv(rgb_tmp); + GPU_basic_shader_line_stipple(3, 0x5555); + mask_draw_array(pos, draw_method, points, tot_point); + + GPU_basic_shader_bind_disable(GPU_SHADER_LINE | GPU_SHADER_STIPPLE); +#endif break; - } - glDisableClientState(GL_VERTEX_ARRAY); + default: + BLI_assert(false); + } if (points != orig_points) MEM_freeN(points); @@ -548,8 +507,6 @@ static void draw_spline_curve(const bContext *C, MaskLayer *masklay, MaskSpline if (is_smooth) { glEnable(GL_LINE_SMOOTH); - glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); } feather_points = BKE_mask_spline_feather_differentiated_points_with_resolution(spline, &tot_feather_point, resol, (is_fill != false)); @@ -557,26 +514,24 @@ static void draw_spline_curve(const bContext *C, MaskLayer *masklay, MaskSpline /* draw feather */ mask_spline_feather_color_get(masklay, spline, is_spline_sel, rgb_tmp); mask_draw_curve_type(C, spline, feather_points, tot_feather_point, - true, is_smooth, is_active, + true, is_active, rgb_tmp, draw_type); if (!is_fill) { - const float *fp = &diff_points[0][0]; float *fp_feather = &feather_points[0][0]; - float tvec[2]; - int i; BLI_assert(tot_diff_point == tot_feather_point); - for (i = 0; i < tot_diff_point; i++, fp += 2, fp_feather += 2) { + for (int i = 0; i < tot_diff_point; i++, fp += 2, fp_feather += 2) { + float tvec[2]; sub_v2_v2v2(tvec, fp, fp_feather); add_v2_v2v2(fp_feather, fp, tvec); } /* same as above */ mask_draw_curve_type(C, spline, feather_points, tot_feather_point, - true, is_smooth, is_active, + true, is_active, rgb_tmp, draw_type); } @@ -585,21 +540,22 @@ static void draw_spline_curve(const bContext *C, MaskLayer *masklay, MaskSpline /* draw main curve */ mask_spline_color_get(masklay, spline, is_spline_sel, rgb_tmp); mask_draw_curve_type(C, spline, diff_points, tot_diff_point, - false, is_smooth, is_active, + false, is_active, rgb_tmp, draw_type); MEM_freeN(diff_points); - if (draw_flag & MASK_DRAWFLAG_SMOOTH) { + if (is_smooth) { glDisable(GL_LINE_SMOOTH); - glDisable(GL_BLEND); } - - (void)draw_type; } static void draw_masklays(const bContext *C, Mask *mask, const char draw_flag, const char draw_type, - const int width, const int height, const float xscale, const float yscale) + const int width, const int height) { + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + GPU_enable_program_point_size(); + MaskLayer *masklay; int i; @@ -616,11 +572,9 @@ static void draw_masklays(const bContext *C, Mask *mask, const char draw_flag, c /* draw curve itself first... */ draw_spline_curve(C, masklay, spline, draw_flag, draw_type, is_active, width, height); -// draw_spline_parents(masklay, spline); - if (!(masklay->restrictflag & MASK_RESTRICT_SELECT)) { /* ...and then handles over the curve so they're nicely visible */ - draw_spline_points(C, masklay, spline, draw_flag, draw_type, xscale, yscale); + draw_spline_points(C, masklay, spline, draw_flag, draw_type); } /* show undeform for testing */ @@ -629,33 +583,29 @@ static void draw_masklays(const bContext *C, Mask *mask, const char draw_flag, c spline->points_deform = NULL; draw_spline_curve(C, masklay, spline, draw_flag, draw_type, is_active, width, height); -// draw_spline_parents(masklay, spline); - draw_spline_points(C, masklay, spline, draw_flag, draw_type, xscale, yscale); + draw_spline_points(C, masklay, spline, draw_flag, draw_type); spline->points_deform = back; } } } + + GPU_disable_program_point_size(); + glDisable(GL_BLEND); } void ED_mask_draw(const bContext *C, const char draw_flag, const char draw_type) { ScrArea *sa = CTX_wm_area(C); - ARegion *ar = CTX_wm_region(C); - Mask *mask = CTX_data_edit_mask(C); int width, height; - float aspx, aspy; - float xscale, yscale; if (!mask) return; ED_mask_get_size(sa, &width, &height); - ED_mask_get_aspect(sa, ar, &aspx, &aspy); - UI_view2d_scale_get(&ar->v2d, &xscale, &yscale); - draw_masklays(C, mask, draw_flag, draw_type, width, height, xscale * aspx, yscale * aspy); + draw_masklays(C, mask, draw_flag, draw_type, width, height); } typedef struct ThreadedMaskRasterizeState { @@ -820,7 +770,7 @@ void ED_mask_draw_region(Mask *mask, ARegion *ar, glTranslatef(x, y, 0); glScalef(zoomx, zoomy, 0); if (stabmat) { - glMultMatrixf(stabmat); + glMultMatrixf((const float *) stabmat); } glaDrawPixelsTex(0.0f, 0.0f, width, height, format, GL_FLOAT, GL_NEAREST, buffer); glPopMatrix(); @@ -836,7 +786,7 @@ void ED_mask_draw_region(Mask *mask, ARegion *ar, glPushMatrix(); if (stabmat) { - glMultMatrixf(stabmat); + glMultMatrixf((const float *) stabmat); } glTranslatef(x + xofs, y + yofs, 0); @@ -847,7 +797,7 @@ void ED_mask_draw_region(Mask *mask, ARegion *ar, } /* draw! */ - draw_masklays(C, mask, draw_flag, draw_type, width, height, maxdim * zoomx, maxdim * zoomy); + draw_masklays(C, mask, draw_flag, draw_type, width, height); if (do_draw_cb) { ED_region_draw_cb_draw(C, ar, REGION_DRAW_POST_VIEW); @@ -862,25 +812,31 @@ void ED_mask_draw_frames(Mask *mask, ARegion *ar, const int cfra, const int sfra MaskLayer *masklay = BKE_mask_layer_active(mask); - glBegin(GL_LINES); - glColor4ub(255, 175, 0, 255); - if (masklay) { - MaskLayerShape *masklay_shape; - - for (masklay_shape = masklay->splines_shapes.first; - masklay_shape; - masklay_shape = masklay_shape->next) - { - int frame = masklay_shape->frame; - - /* draw_keyframe(i, CFRA, sfra, framelen, 1); */ - int height = (frame == cfra) ? 22 : 10; - int x = (frame - sfra) * framelen; - glVertex2i(x, 0); - glVertex2i(x, height); + unsigned int num_lines = BLI_listbase_count(&masklay->splines_shapes); + + if (num_lines > 0) { + unsigned pos = add_attrib(immVertexFormat(), "pos", COMP_I32, 2, CONVERT_INT_TO_FLOAT); + + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + immUniformColor4ub(255, 175, 0, 255); + + immBegin(PRIM_LINES, 2 * num_lines); + + for (MaskLayerShape *masklay_shape = masklay->splines_shapes.first; + masklay_shape; + masklay_shape = masklay_shape->next) + { + int frame = masklay_shape->frame; + + /* draw_keyframe(i, CFRA, sfra, framelen, 1); */ + int height = (frame == cfra) ? 22 : 10; + int x = (frame - sfra) * framelen; + immVertex2i(pos, x, 0); + immVertex2i(pos, x, height); + } + immEnd(); + immUnbindProgram(); } } - - glEnd(); } diff --git a/source/blender/editors/mesh/editmesh_knife.c b/source/blender/editors/mesh/editmesh_knife.c index bf59693b856..2250aaab310 100644 --- a/source/blender/editors/mesh/editmesh_knife.c +++ b/source/blender/editors/mesh/editmesh_knife.c @@ -57,6 +57,8 @@ #include "BIF_gl.h" #include "BIF_glutil.h" /* for paint cursor */ +#include "GPU_immediate.h" + #include "ED_screen.h" #include "ED_space_api.h" #include "ED_view3d.h" @@ -1002,12 +1004,18 @@ static void knifetool_draw_angle_snapping(const KnifeTool_OpData *kcd) copy_v3_v3(v2, ray_hit_best[1]); } - UI_ThemeColor(TH_TRANSFORM); + unsigned pos = add_attrib(immVertexFormat(), "pos", GL_FLOAT, 3, KEEP_FLOAT); + + immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR); + immUniformThemeColor(TH_TRANSFORM); glLineWidth(2.0); - glBegin(GL_LINES); - glVertex3fv(v1); - glVertex3fv(v2); - glEnd(); + + immBegin(GL_LINES, 2); + immVertex3fv(pos, v1); + immVertex3fv(pos, v2); + immEnd(); + + immUnbindProgram(); } static void knife_init_colors(KnifeColors *colors) @@ -1038,63 +1046,66 @@ static void knifetool_draw(const bContext *C, ARegion *UNUSED(ar), void *arg) glPushMatrix(); glMultMatrixf(kcd->ob->obmat); + unsigned pos = add_attrib(immVertexFormat(), "pos", GL_FLOAT, 3, KEEP_FLOAT); + + immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR); + if (kcd->mode == MODE_DRAGGING) { if (kcd->is_angle_snapping) knifetool_draw_angle_snapping(kcd); - glColor3ubv(kcd->colors.line); - + immUniformColor3ubv(kcd->colors.line); glLineWidth(2.0); - glBegin(GL_LINES); - glVertex3fv(kcd->prev.cage); - glVertex3fv(kcd->curr.cage); - glEnd(); + immBegin(GL_LINES, 2); + immVertex3fv(pos, kcd->prev.cage); + immVertex3fv(pos, kcd->curr.cage); + immEnd(); } if (kcd->prev.vert) { - glColor3ubv(kcd->colors.point); + immUniformColor3ubv(kcd->colors.point); glPointSize(11); - glBegin(GL_POINTS); - glVertex3fv(kcd->prev.cage); - glEnd(); + immBegin(GL_POINTS, 1); + immVertex3fv(pos, kcd->prev.cage); + immEnd(); } if (kcd->prev.bmface) { - glColor3ubv(kcd->colors.curpoint); + immUniformColor3ubv(kcd->colors.curpoint); glPointSize(9); - glBegin(GL_POINTS); - glVertex3fv(kcd->prev.cage); - glEnd(); + immBegin(GL_POINTS, 1); + immVertex3fv(pos, kcd->prev.cage); + immEnd(); } if (kcd->curr.edge) { - glColor3ubv(kcd->colors.edge); + immUniformColor3ubv(kcd->colors.edge); glLineWidth(2.0); - glBegin(GL_LINES); - glVertex3fv(kcd->curr.edge->v1->cageco); - glVertex3fv(kcd->curr.edge->v2->cageco); - glEnd(); + immBegin(GL_LINES, 2); + immVertex3fv(pos, kcd->curr.edge->v1->cageco); + immVertex3fv(pos, kcd->curr.edge->v2->cageco); + immEnd(); } else if (kcd->curr.vert) { - glColor3ubv(kcd->colors.point); + immUniformColor3ubv(kcd->colors.point); glPointSize(11); - glBegin(GL_POINTS); - glVertex3fv(kcd->curr.cage); - glEnd(); + immBegin(GL_POINTS, 1); + immVertex3fv(pos, kcd->curr.cage); + immEnd(); } if (kcd->curr.bmface) { - glColor3ubv(kcd->colors.curpoint); + immUniformColor3ubv(kcd->colors.curpoint); glPointSize(9); - glBegin(GL_POINTS); - glVertex3fv(kcd->curr.cage); - glEnd(); + immBegin(GL_POINTS, 1); + immVertex3fv(pos, kcd->curr.cage); + immEnd(); } if (kcd->totlinehit > 0) { @@ -1105,26 +1116,35 @@ static void knifetool_draw(const bContext *C, ARegion *UNUSED(ar), void *arg) glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); /* draw any snapped verts first */ - glColor4ubv(kcd->colors.point_a); + immUniformColor4ubv(kcd->colors.point_a); glPointSize(11); - glBegin(GL_POINTS); + + immBeginAtMost(GL_POINTS, kcd->totlinehit); + lh = kcd->linehits; for (i = 0; i < kcd->totlinehit; i++, lh++) { - if (lh->v) - glVertex3fv(lh->cagehit); + if (lh->v) { + immVertex3fv(pos, lh->cagehit); + } } - glEnd(); + + immEnd(); /* now draw the rest */ - glColor4ubv(kcd->colors.curpoint_a); + immUniformColor4ubv(kcd->colors.curpoint_a); glPointSize(7); - glBegin(GL_POINTS); + + immBeginAtMost(GL_POINTS, kcd->totlinehit); + lh = kcd->linehits; for (i = 0; i < kcd->totlinehit; i++, lh++) { - if (!lh->v) - glVertex3fv(lh->cagehit); + if (!lh->v) { + immVertex3fv(pos, lh->cagehit); + } } - glEnd(); + + immEnd(); + glDisable(GL_BLEND); } @@ -1132,43 +1152,45 @@ static void knifetool_draw(const bContext *C, ARegion *UNUSED(ar), void *arg) BLI_mempool_iter iter; KnifeEdge *kfe; + immUniformColor3ubv(kcd->colors.line); glLineWidth(1.0); - glBegin(GL_LINES); + + immBeginAtMost(GL_LINES, BLI_mempool_count(kcd->kedges) * 2); BLI_mempool_iternew(kcd->kedges, &iter); for (kfe = BLI_mempool_iterstep(&iter); kfe; kfe = BLI_mempool_iterstep(&iter)) { if (!kfe->is_cut) continue; - glColor3ubv(kcd->colors.line); - - glVertex3fv(kfe->v1->cageco); - glVertex3fv(kfe->v2->cageco); + immVertex3fv(pos, kfe->v1->cageco); + immVertex3fv(pos, kfe->v2->cageco); } - glEnd(); + immEnd(); } if (kcd->totkvert > 0) { BLI_mempool_iter iter; KnifeVert *kfv; + immUniformColor3ubv(kcd->colors.point); glPointSize(5.0); - glBegin(GL_POINTS); + immBeginAtMost(GL_POINTS, BLI_mempool_count(kcd->kverts)); + BLI_mempool_iternew(kcd->kverts, &iter); for (kfv = BLI_mempool_iterstep(&iter); kfv; kfv = BLI_mempool_iterstep(&iter)) { if (!kfv->is_cut) continue; - glColor3ubv(kcd->colors.point); - - glVertex3fv(kfv->cageco); + immVertex3fv(pos, kfv->cageco); } - glEnd(); + immEnd(); } + immUnbindProgram(); + glPopMatrix(); if (v3d->zbuf) glEnable(GL_DEPTH_TEST); diff --git a/source/blender/editors/mesh/editmesh_loopcut.c b/source/blender/editors/mesh/editmesh_loopcut.c index f1c1e4105d0..6d8a220dd86 100644 --- a/source/blender/editors/mesh/editmesh_loopcut.c +++ b/source/blender/editors/mesh/editmesh_loopcut.c @@ -45,7 +45,8 @@ #include "BKE_DerivedMesh.h" #include "BKE_unit.h" -#include "BIF_gl.h" +#include "GPU_immediate.h" +#include "GPU_matrix.h" #include "UI_interface.h" @@ -104,27 +105,41 @@ static void ringsel_draw(const bContext *C, ARegion *UNUSED(ar), void *arg) if (v3d && v3d->zbuf) glDisable(GL_DEPTH_TEST); - glPushMatrix(); - glMultMatrixf(lcd->ob->obmat); + gpuMatrixBegin3D_legacy(); + gpuMultMatrix3D(lcd->ob->obmat); + + unsigned pos = add_attrib(immVertexFormat(), "pos", GL_FLOAT, 3, KEEP_FLOAT); + + immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR); + immUniformColor3ub(255, 0, 255); - glColor3ub(255, 0, 255); if (lcd->totedge > 0) { - glEnableClientState(GL_VERTEX_ARRAY); - glVertexPointer(3, GL_FLOAT, 0, lcd->edges); - glDrawArrays(GL_LINES, 0, lcd->totedge * 2); - glDisableClientState(GL_VERTEX_ARRAY); + immBegin(GL_LINES, lcd->totedge * 2); + + for (int i = 0; i < lcd->totedge; i++) { + immVertex3fv(pos, lcd->edges[i][0]); + immVertex3fv(pos, lcd->edges[i][1]); + } + + immEnd(); } if (lcd->totpoint > 0) { glPointSize(3.0f); - glEnableClientState(GL_VERTEX_ARRAY); - glVertexPointer(3, GL_FLOAT, 0, lcd->points); - glDrawArrays(GL_POINTS, 0, lcd->totpoint); - glDisableClientState(GL_VERTEX_ARRAY); + immBegin(GL_POINTS, lcd->totpoint); + + for (int i = 0; i < lcd->totpoint; i++) { + immVertex3fv(pos, lcd->points[i]); + } + + immEnd(); } - glPopMatrix(); + immUnbindProgram(); + + gpuMatrixEnd(); + if (v3d && v3d->zbuf) glEnable(GL_DEPTH_TEST); } diff --git a/source/blender/editors/mesh/editmesh_tools.c b/source/blender/editors/mesh/editmesh_tools.c index 65ee097e8e1..d76dba4088a 100644 --- a/source/blender/editors/mesh/editmesh_tools.c +++ b/source/blender/editors/mesh/editmesh_tools.c @@ -47,6 +47,7 @@ #include "BLI_rand.h" #include "BLI_sort_utils.h" +#include "BKE_layer.h" #include "BKE_material.h" #include "BKE_context.h" #include "BKE_deform.h" @@ -3010,7 +3011,7 @@ enum { MESH_SEPARATE_LOOSE = 2, }; -static Base *mesh_separate_tagged(Main *bmain, Scene *scene, Base *base_old, BMesh *bm_old) +static Base *mesh_separate_tagged(Main *bmain, Scene *scene, SceneLayer *sl, Base *base_old, BMesh *bm_old) { Base *base_new; Object *obedit = base_old->object; @@ -3031,11 +3032,11 @@ static Base *mesh_separate_tagged(Main *bmain, Scene *scene, Base *base_old, BMe CustomData_bmesh_init_pool(&bm_new->ldata, bm_mesh_allocsize_default.totloop, BM_LOOP); CustomData_bmesh_init_pool(&bm_new->pdata, bm_mesh_allocsize_default.totface, BM_FACE); - base_new = ED_object_add_duplicate(bmain, scene, base_old, USER_DUP_MESH); + base_new = ED_object_add_duplicate(bmain, scene, sl, base_old, USER_DUP_MESH); /* DAG_relations_tag_update(bmain); */ /* normally would call directly after but in this case delay recalc */ assign_matarar(base_new->object, give_matarar(obedit), *give_totcolp(obedit)); /* new in 2.5 */ - ED_base_object_select(base_new, BA_SELECT); + ED_object_base_select(base_new, BA_SELECT); BMO_op_callf(bm_old, (BMO_FLAG_DEFAULTS & ~BMO_FLAG_RESPECT_HIDE), "duplicate geom=%hvef dest=%p", BM_ELEM_TAG, bm_new); @@ -3057,7 +3058,7 @@ static Base *mesh_separate_tagged(Main *bmain, Scene *scene, Base *base_old, BMe return base_new; } -static bool mesh_separate_selected(Main *bmain, Scene *scene, Base *base_old, BMesh *bm_old) +static bool mesh_separate_selected(Main *bmain, Scene *scene, SceneLayer *sl, Base *base_old, BMesh *bm_old) { /* we may have tags from previous operators */ BM_mesh_elem_hflag_disable_all(bm_old, BM_FACE | BM_EDGE | BM_VERT, BM_ELEM_TAG, false); @@ -3065,7 +3066,7 @@ static bool mesh_separate_selected(Main *bmain, Scene *scene, Base *base_old, BM /* sel -> tag */ BM_mesh_elem_hflag_enable_test(bm_old, BM_FACE | BM_EDGE | BM_VERT, BM_ELEM_TAG, true, false, BM_ELEM_SELECT); - return (mesh_separate_tagged(bmain, scene, base_old, bm_old) != NULL); + return (mesh_separate_tagged(bmain, scene, sl, base_old, bm_old) != NULL); } /* flush a hflag to from verts to edges/faces */ @@ -3164,7 +3165,7 @@ static void mesh_separate_material_assign_mat_nr(Main *bmain, Object *ob, const } } -static bool mesh_separate_material(Main *bmain, Scene *scene, Base *base_old, BMesh *bm_old) +static bool mesh_separate_material(Main *bmain, Scene *scene, SceneLayer *sl, Base *base_old, BMesh *bm_old) { BMFace *f_cmp, *f; BMIter iter; @@ -3205,7 +3206,7 @@ static bool mesh_separate_material(Main *bmain, Scene *scene, Base *base_old, BM } /* Move selection into a separate object */ - base_new = mesh_separate_tagged(bmain, scene, base_old, bm_old); + base_new = mesh_separate_tagged(bmain, scene, sl, base_old, bm_old); if (base_new) { mesh_separate_material_assign_mat_nr(bmain, base_new->object, mat_nr); } @@ -3216,7 +3217,7 @@ static bool mesh_separate_material(Main *bmain, Scene *scene, Base *base_old, BM return result; } -static bool mesh_separate_loose(Main *bmain, Scene *scene, Base *base_old, BMesh *bm_old) +static bool mesh_separate_loose(Main *bmain, Scene *scene, SceneLayer *sl, Base *base_old, BMesh *bm_old) { int i; BMEdge *e; @@ -3269,7 +3270,7 @@ static bool mesh_separate_loose(Main *bmain, Scene *scene, Base *base_old, BMesh bm_mesh_hflag_flush_vert(bm_old, BM_ELEM_TAG); /* Move selection into a separate object */ - result |= (mesh_separate_tagged(bmain, scene, base_old, bm_old) != NULL); + result |= (mesh_separate_tagged(bmain, scene, sl, base_old, bm_old) != NULL); } return result; @@ -3279,6 +3280,7 @@ static int edbm_separate_exec(bContext *C, wmOperator *op) { Main *bmain = CTX_data_main(C); Scene *scene = CTX_data_scene(C); + SceneLayer *sl = CTX_data_scene_layer(C); const int type = RNA_enum_get(op->ptr, "type"); int retval = 0; @@ -3299,13 +3301,13 @@ static int edbm_separate_exec(bContext *C, wmOperator *op) /* editmode separate */ switch (type) { case MESH_SEPARATE_SELECTED: - retval = mesh_separate_selected(bmain, scene, base, em->bm); + retval = mesh_separate_selected(bmain, scene, sl, base, em->bm); break; case MESH_SEPARATE_MATERIAL: - retval = mesh_separate_material(bmain, scene, base, em->bm); + retval = mesh_separate_material(bmain, scene, sl, base, em->bm); break; case MESH_SEPARATE_LOOSE: - retval = mesh_separate_loose(bmain, scene, base, em->bm); + retval = mesh_separate_loose(bmain, scene, sl, base, em->bm); break; default: BLI_assert(0); @@ -3340,10 +3342,10 @@ static int edbm_separate_exec(bContext *C, wmOperator *op) switch (type) { case MESH_SEPARATE_MATERIAL: - retval_iter = mesh_separate_material(bmain, scene, base_iter, bm_old); + retval_iter = mesh_separate_material(bmain, scene, sl, base_iter, bm_old); break; case MESH_SEPARATE_LOOSE: - retval_iter = mesh_separate_loose(bmain, scene, base_iter, bm_old); + retval_iter = mesh_separate_loose(bmain, scene, sl, base_iter, bm_old); break; default: BLI_assert(0); diff --git a/source/blender/editors/mesh/mesh_data.c b/source/blender/editors/mesh/mesh_data.c index 772bb1bd308..036d084a91c 100644 --- a/source/blender/editors/mesh/mesh_data.c +++ b/source/blender/editors/mesh/mesh_data.c @@ -551,7 +551,7 @@ static int drop_named_image_invoke(bContext *C, wmOperator *op, const wmEvent *e Main *bmain = CTX_data_main(C); Scene *scene = CTX_data_scene(C); View3D *v3d = CTX_wm_view3d(C); - Base *base; + BaseLegacy *base; Image *ima = NULL; Mesh *me; Object *obedit; diff --git a/source/blender/editors/mesh/mesh_navmesh.c b/source/blender/editors/mesh/mesh_navmesh.c index b95921964eb..443f2f0baa8 100644 --- a/source/blender/editors/mesh/mesh_navmesh.c +++ b/source/blender/editors/mesh/mesh_navmesh.c @@ -326,7 +326,7 @@ static bool buildNavMesh(const RecastData *recastParams, int nverts, float *vert } static Object *createRepresentation(bContext *C, struct recast_polyMesh *pmesh, struct recast_polyMeshDetail *dmesh, - Base *base, unsigned int lay) + BaseLegacy *base, unsigned int lay) { float co[3], rot[3]; BMEditMesh *em; @@ -461,14 +461,15 @@ static Object *createRepresentation(bContext *C, struct recast_polyMesh *pmesh, static int navmesh_create_exec(bContext *C, wmOperator *op) { Scene *scene = CTX_data_scene(C); + SceneLayer *sl = CTX_data_scene_layer(C); LinkNode *obs = NULL; - Base *navmeshBase = NULL; + BaseLegacy *navmeshBase = NULL; CTX_DATA_BEGIN (C, Base *, base, selected_editable_bases) { if (base->object->type == OB_MESH) { if (base->object->body_type == OB_BODY_TYPE_NAVMESH) { - if (!navmeshBase || base == scene->basact) { + if (!navmeshBase || base == sl->basact) { navmeshBase = base; } } diff --git a/source/blender/editors/mesh/meshtools.c b/source/blender/editors/mesh/meshtools.c index 743efb246ab..c8b0955c70f 100644 --- a/source/blender/editors/mesh/meshtools.c +++ b/source/blender/editors/mesh/meshtools.c @@ -526,7 +526,7 @@ int join_mesh_exec(bContext *C, wmOperator *op) /* free base, now that data is merged */ if (base->object != ob) { - ED_base_object_free_and_unlink(bmain, scene, base); + ED_base_object_free_and_unlink(bmain, scene, base->object); } } } diff --git a/source/blender/editors/object/object_add.c b/source/blender/editors/object/object_add.c index 02b2d8492b4..97db8458d08 100644 --- a/source/blender/editors/object/object_add.c +++ b/source/blender/editors/object/object_add.c @@ -63,6 +63,7 @@ #include "BKE_animsys.h" #include "BKE_armature.h" #include "BKE_camera.h" +#include "BKE_collection.h" #include "BKE_context.h" #include "BKE_curve.h" #include "BKE_depsgraph.h" @@ -73,6 +74,7 @@ #include "BKE_group.h" #include "BKE_lamp.h" #include "BKE_lattice.h" +#include "BKE_layer.h" #include "BKE_library.h" #include "BKE_library_query.h" #include "BKE_library_remap.h" @@ -405,10 +407,11 @@ Object *ED_object_add_type( bContext *C, int type, const char *name, const float loc[3], const float rot[3], - bool enter_editmode, unsigned int layer) + bool enter_editmode, unsigned int UNUSED(layer)) { Main *bmain = CTX_data_main(C); Scene *scene = CTX_data_scene(C); + SceneLayer *sl = CTX_data_scene_layer(C); Object *ob; /* for as long scene has editmode... */ @@ -416,13 +419,12 @@ Object *ED_object_add_type( ED_object_editmode_exit(C, EM_FREEDATA | EM_FREEUNDO | EM_WAITCURSOR | EM_DO_UNDO); /* freedata, and undo */ /* deselects all, sets scene->basact */ - ob = BKE_object_add(bmain, scene, type, name); - BASACT->lay = ob->lay = layer; + ob = BKE_object_add(bmain, scene, sl, type, name); /* editor level activate, notifiers */ - ED_base_object_activate(C, BASACT); + ED_object_base_activate(C, sl->basact); /* more editor stuff */ - ED_object_base_init_transform(C, BASACT, loc, rot); + ED_object_base_init_transform(C, sl->basact, loc, rot); /* Ignore collisions by default for non-mesh objects */ if (type != OB_MESH) { @@ -830,7 +832,7 @@ static int empty_drop_named_image_invoke(bContext *C, wmOperator *op, const wmEv { Scene *scene = CTX_data_scene(C); - Base *base = NULL; + BaseLegacy *base = NULL; Image *ima = NULL; Object *ob = NULL; @@ -1109,21 +1111,19 @@ static void object_delete_check_glsl_update(Object *ob) /* remove base from a specific scene */ /* note: now unlinks constraints as well */ -void ED_base_object_free_and_unlink(Main *bmain, Scene *scene, Base *base) +void ED_base_object_free_and_unlink(Main *bmain, Scene *scene, Object *ob) { - if (BKE_library_ID_is_indirectly_used(bmain, base->object) && - ID_REAL_USERS(base->object) <= 1 && ID_EXTRA_USERS(base->object) == 0) + if (BKE_library_ID_is_indirectly_used(bmain, ob) && + ID_REAL_USERS(ob) <= 1 && ID_EXTRA_USERS(ob) == 0) { /* We cannot delete indirectly used object... */ printf("WARNING, undeletable object '%s', should have been catched before reaching this function!", - base->object->id.name + 2); + ob->id.name + 2); return; } - BKE_scene_base_unlink(scene, base); - object_delete_check_glsl_update(base->object); - BKE_libblock_free_us(bmain, base->object); - MEM_freeN(base); + object_delete_check_glsl_update(ob); + BKE_collections_object_remove(bmain, scene, ob, true); DAG_id_type_tag(bmain, ID_OB); } @@ -1139,56 +1139,46 @@ static int object_delete_exec(bContext *C, wmOperator *op) if (CTX_data_edit_object(C)) return OPERATOR_CANCELLED; - CTX_DATA_BEGIN (C, Base *, base, selected_bases) + CTX_DATA_BEGIN (C, Object *, ob, selected_objects) { - const bool is_indirectly_used = BKE_library_ID_is_indirectly_used(bmain, base->object); - if (base->object->id.tag & LIB_TAG_INDIRECT) { + const bool is_indirectly_used = BKE_library_ID_is_indirectly_used(bmain, ob); + if (ob->id.tag & LIB_TAG_INDIRECT) { /* Can this case ever happen? */ - BKE_reportf(op->reports, RPT_WARNING, "Cannot delete indirectly linked object '%s'", base->object->id.name + 2); + BKE_reportf(op->reports, RPT_WARNING, "Cannot delete indirectly linked object '%s'", ob->id.name + 2); continue; } - else if (is_indirectly_used && ID_REAL_USERS(base->object) <= 1 && ID_EXTRA_USERS(base->object) == 0) { + else if (is_indirectly_used && ID_REAL_USERS(ob) <= 1 && ID_EXTRA_USERS(ob) == 0) { BKE_reportf(op->reports, RPT_WARNING, "Cannot delete object '%s' from scene '%s', indirectly used objects need at least one user", - base->object->id.name + 2, scene->id.name + 2); + ob->id.name + 2, scene->id.name + 2); continue; } /* remove from Grease Pencil parent */ for (bGPdata *gpd = bmain->gpencil.first; gpd; gpd = gpd->id.next) { for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) { if (gpl->parent != NULL) { - Object *ob = gpl->parent; - Object *curob = base->object; - if (ob == curob) { + if (gpl->parent == ob) { gpl->parent = NULL; } } } } - /* deselect object -- it could be used in other scenes */ - base->object->flag &= ~SELECT; - /* remove from current scene only */ - ED_base_object_free_and_unlink(bmain, scene, base); + ED_base_object_free_and_unlink(bmain, scene, ob); changed = true; if (use_global) { Scene *scene_iter; - Base *base_other; - for (scene_iter = bmain->scene.first; scene_iter; scene_iter = scene_iter->id.next) { if (scene_iter != scene && !ID_IS_LINKED_DATABLOCK(scene_iter)) { - base_other = BKE_scene_base_find(scene_iter, base->object); - if (base_other) { - if (is_indirectly_used && ID_REAL_USERS(base->object) <= 1 && ID_EXTRA_USERS(base->object) == 0) { - BKE_reportf(op->reports, RPT_WARNING, - "Cannot delete object '%s' from scene '%s', indirectly used objects need at least one user", - base->object->id.name + 2, scene_iter->id.name + 2); - break; - } - ED_base_object_free_and_unlink(bmain, scene_iter, base_other); + if (is_indirectly_used && ID_REAL_USERS(ob) <= 1 && ID_EXTRA_USERS(ob) == 0) { + BKE_reportf(op->reports, RPT_WARNING, + "Cannot delete object '%s' from scene '%s', indirectly used objects need at least one user", + ob->id.name + 2, scene_iter->id.name + 2); + break; } + ED_base_object_free_and_unlink(bmain, scene_iter, ob); } } } @@ -1329,6 +1319,7 @@ static void make_object_duplilist_real(bContext *C, Scene *scene, Base *base, const bool use_hierarchy) { Main *bmain = CTX_data_main(C); + SceneLayer *sl = CTX_data_scene_layer(C); ListBase *lb; DupliObject *dob; GHash *dupli_gh = NULL, *parent_gh = NULL; @@ -1360,12 +1351,10 @@ static void make_object_duplilist_real(bContext *C, Scene *scene, Base *base, */ if (ob->mat == NULL) ob->totcol = 0; - basen = MEM_dupallocN(base); - basen->flag &= ~(OB_FROMDUPLI | OB_FROMGROUP); - ob->flag = basen->flag; - basen->lay = base->lay; - BLI_addhead(&scene->base, basen); /* addhead: othwise eternal loop */ - basen->object = ob; + BKE_collection_object_add_from(scene, dob->ob, ob); + basen = BKE_scene_layer_base_find(sl, ob); + + BKE_scene_object_base_flag_sync_from_base(basen); /* make sure apply works */ BKE_animdata_free(&ob->id, true); @@ -1380,7 +1369,6 @@ static void make_object_duplilist_real(bContext *C, Scene *scene, Base *base, BLI_listbase_clear(&ob->constraints); ob->curve_cache = NULL; ob->transflag &= ~OB_DUPLI; - ob->lay = base->lay; copy_m4_m4(ob->obmat, dob->mat); BKE_object_apply_mat4(ob, ob->obmat, false, false); @@ -1589,7 +1577,7 @@ static int convert_poll(bContext *C) } /* Helper for convert_exec */ -static Base *duplibase_for_convert(Main *bmain, Scene *scene, Base *base, Object *ob) +static Base *duplibase_for_convert(Main *bmain, Scene *scene, SceneLayer *sl, Base *base, Object *ob) { Object *obn; Base *basen; @@ -1600,16 +1588,11 @@ static Base *duplibase_for_convert(Main *bmain, Scene *scene, Base *base, Object obn = BKE_object_copy(bmain, ob); DAG_id_tag_update(&ob->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME); + BKE_collection_object_add_from(scene, ob, obn); - basen = MEM_mallocN(sizeof(Base), "duplibase"); - *basen = *base; - BLI_addhead(&scene->base, basen); /* addhead: otherwise eternal loop */ - basen->object = obn; - basen->flag |= SELECT; - obn->flag |= SELECT; - base->flag &= ~SELECT; - ob->flag &= ~SELECT; - + basen = BKE_scene_layer_base_find(sl, obn); + ED_object_base_select(basen, BA_SELECT); + ED_object_base_select(basen, BA_DESELECT); return basen; } @@ -1617,6 +1600,7 @@ static int convert_exec(bContext *C, wmOperator *op) { Main *bmain = CTX_data_main(C); Scene *scene = CTX_data_scene(C); + SceneLayer *sl = CTX_data_scene_layer(C); Base *basen = NULL, *basact = NULL; Object *ob, *ob1, *newob, *obact = CTX_data_active_object(C); DerivedMesh *dm; @@ -1631,7 +1615,7 @@ static int convert_exec(bContext *C, wmOperator *op) /* don't forget multiple users! */ { - Base *base; + BaseLegacy *base; for (base = scene->base.first; base; base = base->next) { ob = base->object; @@ -1678,7 +1662,7 @@ static int convert_exec(bContext *C, wmOperator *op) ob->flag |= OB_DONE; if (keep_original) { - basen = duplibase_for_convert(bmain, scene, base, NULL); + basen = duplibase_for_convert(bmain, scene, sl, base, NULL); newob = basen->object; /* decrement original mesh's usage count */ @@ -1703,7 +1687,7 @@ static int convert_exec(bContext *C, wmOperator *op) ob->flag |= OB_DONE; if (keep_original) { - basen = duplibase_for_convert(bmain, scene, base, NULL); + basen = duplibase_for_convert(bmain, scene, sl, base, NULL); newob = basen->object; /* decrement original mesh's usage count */ @@ -1735,7 +1719,7 @@ static int convert_exec(bContext *C, wmOperator *op) ob->flag |= OB_DONE; if (keep_original) { - basen = duplibase_for_convert(bmain, scene, base, NULL); + basen = duplibase_for_convert(bmain, scene, sl, base, NULL); newob = basen->object; /* decrement original curve's usage count */ @@ -1806,7 +1790,7 @@ static int convert_exec(bContext *C, wmOperator *op) if (target == OB_MESH) { if (keep_original) { - basen = duplibase_for_convert(bmain, scene, base, NULL); + basen = duplibase_for_convert(bmain, scene, sl, base, NULL); newob = basen->object; /* decrement original curve's usage count */ @@ -1841,7 +1825,7 @@ static int convert_exec(bContext *C, wmOperator *op) if (!(baseob->flag & OB_DONE)) { baseob->flag |= OB_DONE; - basen = duplibase_for_convert(bmain, scene, base, baseob); + basen = duplibase_for_convert(bmain, scene, sl, base, baseob); newob = basen->object; mb = newob->data; @@ -1892,23 +1876,20 @@ static int convert_exec(bContext *C, wmOperator *op) if (!keep_original) { if (mballConverted) { - Base *base, *base_next; - - for (base = scene->base.first; base; base = base_next) { - base_next = base->next; - - ob = base->object; + FOREACH_SCENE_OBJECT(scene, ob_mball) + { if (ob->type == OB_MBALL) { if (ob->flag & OB_DONE) { Object *ob_basis = NULL; - if (BKE_mball_is_basis(ob) || - ((ob_basis = BKE_mball_basis_find(scene, ob)) && (ob_basis->flag & OB_DONE))) + if (BKE_mball_is_basis(ob_mball) || + ((ob_basis = BKE_mball_basis_find(scene, ob_mball)) && (ob_basis->flag & OB_DONE))) { - ED_base_object_free_and_unlink(bmain, scene, base); + ED_base_object_free_and_unlink(bmain, scene, ob_mball); } } } } + FOREACH_SCENE_OBJECT_END } /* delete object should renew depsgraph */ @@ -1920,12 +1901,12 @@ static int convert_exec(bContext *C, wmOperator *op) if (basact) { /* active base was changed */ - ED_base_object_activate(C, basact); - BASACT = basact; + ED_object_base_activate(C, basact); + BASACT_NEW = basact; } - else if (BASACT->object->flag & OB_DONE) { - WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, BASACT->object); - WM_event_add_notifier(C, NC_OBJECT | ND_DATA, BASACT->object); + else if (BASACT_NEW->object->flag & OB_DONE) { + WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, BASACT_NEW->object); + WM_event_add_notifier(C, NC_OBJECT | ND_DATA, BASACT_NEW->object); } DAG_relations_tag_update(bmain); @@ -1967,18 +1948,17 @@ void OBJECT_OT_convert(wmOperatorType *ot) /* used below, assumes id.new is correct */ /* leaves selection of base/object unaltered */ /* Does set ID->newid pointers. */ -static Base *object_add_duplicate_internal(Main *bmain, Scene *scene, Base *base, int dupflag) +static Base *object_add_duplicate_internal(Main *bmain, Scene *scene, SceneLayer *sl, Object *ob, int dupflag) { #define ID_NEW_REMAP_US(a) if ( (a)->id.newid) { (a) = (void *)(a)->id.newid; (a)->id.us++; } #define ID_NEW_REMAP_US2(a) if (((ID *)a)->newid) { (a) = ((ID *)a)->newid; ((ID *)a)->us++; } Base *basen = NULL; Material ***matarar; - Object *ob, *obn; + Object *obn; ID *id; int a, didit; - ob = base->object; if (ob->mode & OB_MODE_POSE) { ; /* nothing? */ } @@ -1986,20 +1966,18 @@ static Base *object_add_duplicate_internal(Main *bmain, Scene *scene, Base *base obn = ID_NEW_SET(ob, BKE_object_copy(bmain, ob)); DAG_id_tag_update(&obn->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME); - basen = MEM_mallocN(sizeof(Base), "duplibase"); - *basen = *base; - BLI_addhead(&scene->base, basen); /* addhead: prevent eternal loop */ - basen->object = obn; + BKE_collection_object_add_from(scene, ob, obn); + basen = BKE_scene_layer_base_find(sl, obn); /* 1) duplis should end up in same group as the original * 2) Rigid Body sim participants MUST always be part of a group... */ // XXX: is 2) really a good measure here? - if ((basen->flag & OB_FROMGROUP) || ob->rigidbody_object || ob->rigidbody_constraint) { + if ((ob->flag & OB_FROMGROUP) != 0 || ob->rigidbody_object || ob->rigidbody_constraint) { Group *group; for (group = bmain->group.first; group; group = group->id.next) { if (BKE_group_object_exists(group, ob)) - BKE_group_object_add(group, obn, scene, basen); + BKE_group_object_add(group, obn); } } @@ -2207,14 +2185,14 @@ static Base *object_add_duplicate_internal(Main *bmain, Scene *scene, Base *base * note: don't call this within a loop since clear_* funcs loop over the entire database. * note: caller must do DAG_relations_tag_update(bmain); * this is not done automatic since we may duplicate many objects in a batch */ -Base *ED_object_add_duplicate(Main *bmain, Scene *scene, Base *base, int dupflag) +Base *ED_object_add_duplicate(Main *bmain, Scene *scene, SceneLayer *sl, Base *base, int dupflag) { Base *basen; Object *ob; clear_sca_new_poins(); /* BGE logic */ - basen = object_add_duplicate_internal(bmain, scene, base, dupflag); + basen = object_add_duplicate_internal(bmain, scene, sl, base->object, dupflag); if (basen == NULL) { return NULL; } @@ -2241,6 +2219,7 @@ static int duplicate_exec(bContext *C, wmOperator *op) { Main *bmain = CTX_data_main(C); Scene *scene = CTX_data_scene(C); + SceneLayer *sl = CTX_data_scene_layer(C); const bool linked = RNA_boolean_get(op->ptr, "linked"); int dupflag = (linked) ? 0 : U.dupflag; @@ -2248,19 +2227,19 @@ static int duplicate_exec(bContext *C, wmOperator *op) CTX_DATA_BEGIN (C, Base *, base, selected_bases) { - Base *basen = object_add_duplicate_internal(bmain, scene, base, dupflag); + Base *basen = object_add_duplicate_internal(bmain, scene, sl, base->object, dupflag); /* note that this is safe to do with this context iterator, * the list is made in advance */ - ED_base_object_select(base, BA_DESELECT); + ED_object_base_select(base, BA_DESELECT); if (basen == NULL) { continue; } /* new object becomes active */ - if (BASACT == base) - ED_base_object_activate(C, basen); + if (BASACT_NEW == base) + ED_object_base_activate(C, basen); if (basen->object->data) { DAG_id_tag_update(basen->object->data, 0); @@ -2308,9 +2287,9 @@ static int add_named_exec(bContext *C, wmOperator *op) wmWindow *win = CTX_wm_window(C); const wmEvent *event = win ? win->eventstate : NULL; Main *bmain = CTX_data_main(C); - View3D *v3d = CTX_wm_view3d(C); /* may be NULL */ Scene *scene = CTX_data_scene(C); - Base *basen, *base; + SceneLayer *sl = CTX_data_scene_layer(C); + Base *basen; Object *ob; const bool linked = RNA_boolean_get(op->ptr, "linked"); int dupflag = (linked) ? 0 : U.dupflag; @@ -2325,22 +2304,17 @@ static int add_named_exec(bContext *C, wmOperator *op) return OPERATOR_CANCELLED; } - base = MEM_callocN(sizeof(Base), "duplibase"); - base->object = ob; - base->flag = ob->flag; - /* prepare dupli */ clear_sca_new_poins(); /* BGE logic */ - basen = object_add_duplicate_internal(bmain, scene, base, dupflag); + basen = object_add_duplicate_internal(bmain, scene, sl, ob, dupflag); + BKE_scene_object_base_flag_sync_from_object(basen); if (basen == NULL) { - MEM_freeN(base); BKE_report(op->reports, RPT_ERROR, "Object could not be duplicated"); return OPERATOR_CANCELLED; } - basen->lay = basen->object->lay = BKE_screen_view3d_layer_active(v3d, scene); basen->object->restrictflag &= ~OB_RESTRICT_VIEW; if (event) { @@ -2351,8 +2325,8 @@ static int add_named_exec(bContext *C, wmOperator *op) ED_view3d_cursor3d_position(C, basen->object->loc, mval); } - ED_base_object_select(basen, BA_SELECT); - ED_base_object_activate(C, basen); + ED_object_base_select(basen, BA_SELECT); + ED_object_base_activate(C, basen); copy_object_set_idnew(C); @@ -2360,8 +2334,6 @@ static int add_named_exec(bContext *C, wmOperator *op) DAG_relations_tag_update(bmain); - MEM_freeN(base); - WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT | ND_OB_ACTIVE, scene); return OPERATOR_FINISHED; diff --git a/source/blender/editors/object/object_constraint.c b/source/blender/editors/object/object_constraint.c index 59d78f13ccb..2437a6bff28 100644 --- a/source/blender/editors/object/object_constraint.c +++ b/source/blender/editors/object/object_constraint.c @@ -1682,14 +1682,15 @@ static bool get_new_constraint_target(bContext *C, int con_type, Object **tar_ob if ((found == false) && (add)) { Main *bmain = CTX_data_main(C); Scene *scene = CTX_data_scene(C); - Base *base = BASACT, *newbase = NULL; + SceneLayer *sl = CTX_data_scene_layer(C); + Base *base = BASACT_NEW, *newbase = NULL; Object *obt; /* add new target object */ - obt = BKE_object_add(bmain, scene, OB_EMPTY, NULL); + obt = BKE_object_add(bmain, scene, sl, OB_EMPTY, NULL); /* set layers OK */ - newbase = BASACT; + newbase = BASACT_NEW; newbase->lay = base->lay; obt->lay = newbase->lay; @@ -1708,8 +1709,8 @@ static bool get_new_constraint_target(bContext *C, int con_type, Object **tar_ob } /* restore, BKE_object_add sets active */ - BASACT = base; - base->flag |= SELECT; + BASACT_NEW = base; + base->flag |= BASE_SELECTED; /* make our new target the new object */ *tar_ob = obt; diff --git a/source/blender/editors/object/object_edit.c b/source/blender/editors/object/object_edit.c index edd7b5dd1be..2a4557f3610 100644 --- a/source/blender/editors/object/object_edit.c +++ b/source/blender/editors/object/object_edit.c @@ -132,189 +132,6 @@ Object *ED_object_active_context(bContext *C) } -/* ********* clear/set restrict view *********/ -static int object_hide_view_clear_exec(bContext *C, wmOperator *UNUSED(op)) -{ - Main *bmain = CTX_data_main(C); - ScrArea *sa = CTX_wm_area(C); - View3D *v3d = sa->spacedata.first; - Scene *scene = CTX_data_scene(C); - Base *base; - bool changed = false; - - /* XXX need a context loop to handle such cases */ - for (base = FIRSTBASE; base; base = base->next) { - if ((base->lay & v3d->lay) && base->object->restrictflag & OB_RESTRICT_VIEW) { - if (!(base->object->restrictflag & OB_RESTRICT_SELECT)) { - base->flag |= SELECT; - } - base->object->flag = base->flag; - base->object->restrictflag &= ~OB_RESTRICT_VIEW; - changed = true; - } - } - if (changed) { - DAG_id_type_tag(bmain, ID_OB); - DAG_relations_tag_update(bmain); - WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene); - } - - return OPERATOR_FINISHED; -} - -void OBJECT_OT_hide_view_clear(wmOperatorType *ot) -{ - - /* identifiers */ - ot->name = "Clear Restrict View"; - ot->description = "Reveal the object by setting the hide flag"; - ot->idname = "OBJECT_OT_hide_view_clear"; - - /* api callbacks */ - ot->exec = object_hide_view_clear_exec; - ot->poll = ED_operator_view3d_active; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; -} - -static int object_hide_view_set_exec(bContext *C, wmOperator *op) -{ - Main *bmain = CTX_data_main(C); - Scene *scene = CTX_data_scene(C); - bool changed = false; - const bool unselected = RNA_boolean_get(op->ptr, "unselected"); - - CTX_DATA_BEGIN(C, Base *, base, visible_bases) - { - if (!unselected) { - if (base->flag & SELECT) { - base->flag &= ~SELECT; - base->object->flag = base->flag; - base->object->restrictflag |= OB_RESTRICT_VIEW; - changed = true; - if (base == BASACT) { - ED_base_object_activate(C, NULL); - } - } - } - else { - if (!(base->flag & SELECT)) { - base->object->restrictflag |= OB_RESTRICT_VIEW; - changed = true; - if (base == BASACT) { - ED_base_object_activate(C, NULL); - } - } - } - } - CTX_DATA_END; - - if (changed) { - DAG_id_type_tag(bmain, ID_OB); - DAG_relations_tag_update(bmain); - - WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene); - - } - - return OPERATOR_FINISHED; -} - -void OBJECT_OT_hide_view_set(wmOperatorType *ot) -{ - /* identifiers */ - ot->name = "Set Restrict View"; - ot->description = "Hide the object by setting the hide flag"; - ot->idname = "OBJECT_OT_hide_view_set"; - - /* api callbacks */ - ot->exec = object_hide_view_set_exec; - ot->poll = ED_operator_view3d_active; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - - RNA_def_boolean(ot->srna, "unselected", 0, "Unselected", "Hide unselected rather than selected objects"); - -} - -/* 99% same as above except no need for scene refreshing (TODO, update render preview) */ -static int object_hide_render_clear_exec(bContext *C, wmOperator *UNUSED(op)) -{ - bool changed = false; - - /* XXX need a context loop to handle such cases */ - CTX_DATA_BEGIN(C, Object *, ob, selected_editable_objects) - { - if (ob->restrictflag & OB_RESTRICT_RENDER) { - ob->restrictflag &= ~OB_RESTRICT_RENDER; - changed = true; - } - } - CTX_DATA_END; - - if (changed) - WM_event_add_notifier(C, NC_SPACE | ND_SPACE_OUTLINER, NULL); - - return OPERATOR_FINISHED; -} - -void OBJECT_OT_hide_render_clear(wmOperatorType *ot) -{ - - /* identifiers */ - ot->name = "Clear Restrict Render"; - ot->description = "Reveal the render object by setting the hide render flag"; - ot->idname = "OBJECT_OT_hide_render_clear"; - - /* api callbacks */ - ot->exec = object_hide_render_clear_exec; - ot->poll = ED_operator_view3d_active; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; -} - -static int object_hide_render_set_exec(bContext *C, wmOperator *op) -{ - const bool unselected = RNA_boolean_get(op->ptr, "unselected"); - - CTX_DATA_BEGIN(C, Base *, base, visible_bases) - { - if (!unselected) { - if (base->flag & SELECT) { - base->object->restrictflag |= OB_RESTRICT_RENDER; - } - } - else { - if (!(base->flag & SELECT)) { - base->object->restrictflag |= OB_RESTRICT_RENDER; - } - } - } - CTX_DATA_END; - WM_event_add_notifier(C, NC_SPACE | ND_SPACE_OUTLINER, NULL); - return OPERATOR_FINISHED; -} - -void OBJECT_OT_hide_render_set(wmOperatorType *ot) -{ - /* identifiers */ - ot->name = "Set Restrict Render"; - ot->description = "Hide the render object by setting the hide render flag"; - ot->idname = "OBJECT_OT_hide_render_set"; - - /* api callbacks */ - ot->exec = object_hide_render_set_exec; - ot->poll = ED_operator_view3d_active; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - - RNA_def_boolean(ot->srna, "unselected", 0, "Unselected", "Hide unselected rather than selected objects"); -} - /* ******************* toggle editmode operator ***************** */ static bool mesh_needs_keyindex(const Mesh *me) @@ -465,31 +282,22 @@ void ED_object_editmode_exit(bContext *C, int flag) void ED_object_editmode_enter(bContext *C, int flag) { Scene *scene = CTX_data_scene(C); - Base *base = NULL; + SceneLayer *sl = CTX_data_scene_layer(C); Object *ob; - ScrArea *sa = CTX_wm_area(C); - View3D *v3d = NULL; bool ok = false; if (ID_IS_LINKED_DATABLOCK(scene)) return; - if (sa && sa->spacetype == SPACE_VIEW3D) - v3d = sa->spacedata.first; - if ((flag & EM_IGNORE_LAYER) == 0) { - base = CTX_data_active_base(C); /* active layer checked here for view3d */ + ob = CTX_data_active_object(C); /* active layer checked here for view3d */ - if (base == NULL) return; - else if (v3d && (base->lay & v3d->lay) == 0) return; - else if (!v3d && (base->lay & scene->lay) == 0) return; + if (ob == NULL) return; } else { - base = scene->basact; + ob = sl->basact->object; } - if (ELEM(NULL, base, base->object, base->object->data)) return; - - ob = base->object; + if (ELEM(NULL, ob, ob->data)) return; /* this checks actual object->data, for cases when other scenes have it in editmode context */ if (BKE_object_is_in_editmode(ob)) @@ -698,7 +506,7 @@ static void copymenu_properties(Scene *scene, View3D *v3d, Object *ob) { //XXX no longer used - to be removed - replaced by game_properties_copy_exec bProperty *prop; - Base *base; + BaseLegacy *base; int nr, tot = 0; char *str; @@ -758,7 +566,7 @@ static void copymenu_properties(Scene *scene, View3D *v3d, Object *ob) static void copymenu_logicbricks(Scene *scene, View3D *v3d, Object *ob) { //XXX no longer used - to be removed - replaced by logicbricks_copy_exec - Base *base; + BaseLegacy *base; for (base = FIRSTBASE; base; base = base->next) { if (base->object != ob) { @@ -844,7 +652,7 @@ static void copy_texture_space(Object *to, Object *ob) static void copy_attr(Main *bmain, Scene *scene, View3D *v3d, short event) { Object *ob; - Base *base; + BaseLegacy *base; Curve *cu, *cu1; Nurb *nu; bool do_depgraph_update = false; @@ -1512,7 +1320,7 @@ void OBJECT_OT_shade_smooth(wmOperatorType *ot) static void UNUSED_FUNCTION(image_aspect) (Scene *scene, View3D *v3d) { /* all selected objects with an image map: scale in image aspect */ - Base *base; + BaseLegacy *base; Object *ob; Material *ma; Tex *tex; diff --git a/source/blender/editors/object/object_group.c b/source/blender/editors/object/object_group.c index 0fe43c44d7d..b22b034ecab 100644 --- a/source/blender/editors/object/object_group.c +++ b/source/blender/editors/object/object_group.c @@ -128,7 +128,6 @@ static int objects_add_active_exec(bContext *C, wmOperator *op) { Object *ob = ED_object_context(C); Main *bmain = CTX_data_main(C); - Scene *scene = CTX_data_scene(C); int single_group_index = RNA_enum_get(op->ptr, "group"); Group *single_group = group_object_active_find_index(ob, single_group_index); Group *group; @@ -151,7 +150,7 @@ static int objects_add_active_exec(bContext *C, wmOperator *op) continue; if (!BKE_group_object_cyclic_check(bmain, base->object, group)) { - BKE_group_object_add(group, base->object, scene, base); + BKE_group_object_add(group, base->object); updated = true; } else { @@ -200,8 +199,8 @@ void GROUP_OT_objects_add_active(wmOperatorType *ot) static int objects_remove_active_exec(bContext *C, wmOperator *op) { Main *bmain = CTX_data_main(C); - Scene *scene = CTX_data_scene(C); - Object *ob = OBACT; + SceneLayer *sl = CTX_data_scene_layer(C); + Object *ob = OBACT_NEW; int single_group_index = RNA_enum_get(op->ptr, "group"); Group *single_group = group_object_active_find_index(ob, single_group_index); Group *group; @@ -221,7 +220,7 @@ static int objects_remove_active_exec(bContext *C, wmOperator *op) /* Remove groups from selected objects */ CTX_DATA_BEGIN (C, Base *, base, selected_editable_bases) { - BKE_group_object_unlink(group, base->object, scene, base); + BKE_group_object_unlink(group, base->object); ok = 1; } CTX_DATA_END; @@ -264,11 +263,10 @@ void GROUP_OT_objects_remove_active(wmOperatorType *ot) static int group_objects_remove_all_exec(bContext *C, wmOperator *UNUSED(op)) { Main *bmain = CTX_data_main(C); - Scene *scene = CTX_data_scene(C); CTX_DATA_BEGIN (C, Base *, base, selected_editable_bases) { - BKE_object_groups_clear(scene, base, base->object); + BKE_object_groups_clear(base->object); } CTX_DATA_END; @@ -297,7 +295,6 @@ static int group_objects_remove_exec(bContext *C, wmOperator *op) { Object *ob = ED_object_context(C); Main *bmain = CTX_data_main(C); - Scene *scene = CTX_data_scene(C); int single_group_index = RNA_enum_get(op->ptr, "group"); Group *single_group = group_object_active_find_index(ob, single_group_index); Group *group; @@ -315,7 +312,7 @@ static int group_objects_remove_exec(bContext *C, wmOperator *op) /* now remove all selected objects from the group */ CTX_DATA_BEGIN (C, Base *, base, selected_editable_bases) { - BKE_group_object_unlink(group, base->object, scene, base); + BKE_group_object_unlink(group, base->object); updated = true; } CTX_DATA_END; @@ -357,7 +354,6 @@ void GROUP_OT_objects_remove(wmOperatorType *ot) static int group_create_exec(bContext *C, wmOperator *op) { Main *bmain = CTX_data_main(C); - Scene *scene = CTX_data_scene(C); Group *group = NULL; char name[MAX_ID_NAME - 2]; /* id name */ @@ -367,7 +363,7 @@ static int group_create_exec(bContext *C, wmOperator *op) CTX_DATA_BEGIN (C, Base *, base, selected_bases) { - BKE_group_object_add(group, base->object, scene, base); + BKE_group_object_add(group, base->object); } CTX_DATA_END; @@ -398,7 +394,6 @@ void GROUP_OT_create(wmOperatorType *ot) static int group_add_exec(bContext *C, wmOperator *UNUSED(op)) { - Scene *scene = CTX_data_scene(C); Object *ob = ED_object_context(C); Main *bmain = CTX_data_main(C); Group *group; @@ -407,7 +402,7 @@ static int group_add_exec(bContext *C, wmOperator *UNUSED(op)) return OPERATOR_CANCELLED; group = BKE_group_add(bmain, "Group"); - BKE_group_object_add(group, ob, scene, NULL); + BKE_group_object_add(group, ob); WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob); @@ -432,7 +427,6 @@ void OBJECT_OT_group_add(wmOperatorType *ot) static int group_link_exec(bContext *C, wmOperator *op) { Main *bmain = CTX_data_main(C); - Scene *scene = CTX_data_scene(C); Object *ob = ED_object_context(C); Group *group = BLI_findlink(&bmain->group, RNA_enum_get(op->ptr, "group")); @@ -457,7 +451,7 @@ static int group_link_exec(bContext *C, wmOperator *op) return OPERATOR_CANCELLED; } - BKE_group_object_add(group, ob, scene, NULL); + BKE_group_object_add(group, ob); WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob); @@ -490,14 +484,13 @@ void OBJECT_OT_group_link(wmOperatorType *ot) static int group_remove_exec(bContext *C, wmOperator *UNUSED(op)) { - Scene *scene = CTX_data_scene(C); Object *ob = ED_object_context(C); Group *group = CTX_data_pointer_get_type(C, "group", &RNA_Group).data; if (!ob || !group) return OPERATOR_CANCELLED; - BKE_group_object_unlink(group, ob, scene, NULL); /* base will be used if found */ + BKE_group_object_unlink(group, ob); WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob); @@ -560,8 +553,10 @@ static int select_grouped_exec(bContext *C, wmOperator *UNUSED(op)) /* Select o CTX_DATA_BEGIN (C, Base *, base, visible_bases) { - if (!(base->flag & SELECT) && BKE_group_object_exists(group, base->object)) { - ED_base_object_select(base, BA_SELECT); + if (((base->flag & BASE_SELECTED) == 0) && ((base->flag & BASE_SELECTABLED) != 0)) { + if (BKE_group_object_exists(group, base->object)) { + ED_object_base_select(base, BA_SELECT); + } } } CTX_DATA_END; diff --git a/source/blender/editors/object/object_hook.c b/source/blender/editors/object/object_hook.c index 438c10c51fa..f41f21f5bd4 100644 --- a/source/blender/editors/object/object_hook.c +++ b/source/blender/editors/object/object_hook.c @@ -445,12 +445,12 @@ static int hook_op_edit_poll(bContext *C) return 0; } -static Object *add_hook_object_new(Main *bmain, Scene *scene, Object *obedit) +static Object *add_hook_object_new(Main *bmain, Scene *scene, SceneLayer *sl, Object *obedit) { - Base *base, *basedit; + BaseLegacy *base, *basedit; Object *ob; - ob = BKE_object_add(bmain, scene, OB_EMPTY, NULL); + ob = BKE_object_add(bmain, scene, sl, OB_EMPTY, NULL); basedit = BKE_scene_base_find(scene, obedit); base = scene->basact; @@ -464,7 +464,7 @@ static Object *add_hook_object_new(Main *bmain, Scene *scene, Object *obedit) return ob; } -static int add_hook_object(Main *bmain, Scene *scene, Object *obedit, Object *ob, int mode, ReportList *reports) +static int add_hook_object(Main *bmain, Scene *scene, SceneLayer *sl, Object *obedit, Object *ob, int mode, ReportList *reports) { ModifierData *md = NULL; HookModifierData *hmd = NULL; @@ -482,7 +482,7 @@ static int add_hook_object(Main *bmain, Scene *scene, Object *obedit, Object *ob if (mode == OBJECT_ADDHOOK_NEWOB && !ob) { - ob = add_hook_object_new(bmain, scene, obedit); + ob = add_hook_object_new(bmain, scene, sl, obedit); /* transform cent to global coords for loc */ mul_v3_m4v3(ob->loc, obedit->obmat, cent); @@ -556,6 +556,7 @@ static int object_add_hook_selob_exec(bContext *C, wmOperator *op) { Main *bmain = CTX_data_main(C); Scene *scene = CTX_data_scene(C); + SceneLayer *sl = CTX_data_scene_layer(C); Object *obedit = CTX_data_edit_object(C); Object *obsel = NULL; const bool use_bone = RNA_boolean_get(op->ptr, "use_bone"); @@ -580,7 +581,7 @@ static int object_add_hook_selob_exec(bContext *C, wmOperator *op) return OPERATOR_CANCELLED; } - if (add_hook_object(bmain, scene, obedit, obsel, mode, op->reports)) { + if (add_hook_object(bmain, scene, sl, obedit, obsel, mode, op->reports)) { WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, obedit); return OPERATOR_FINISHED; } @@ -611,9 +612,10 @@ static int object_add_hook_newob_exec(bContext *C, wmOperator *op) { Main *bmain = CTX_data_main(C); Scene *scene = CTX_data_scene(C); + SceneLayer *sl = CTX_data_scene_layer(C); Object *obedit = CTX_data_edit_object(C); - if (add_hook_object(bmain, scene, obedit, NULL, OBJECT_ADDHOOK_NEWOB, op->reports)) { + if (add_hook_object(bmain, scene, sl, obedit, NULL, OBJECT_ADDHOOK_NEWOB, op->reports)) { WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene); WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, obedit); return OPERATOR_FINISHED; diff --git a/source/blender/editors/object/object_intern.h b/source/blender/editors/object/object_intern.h index 9710e4f843d..fe0ceb15d70 100644 --- a/source/blender/editors/object/object_intern.h +++ b/source/blender/editors/object/object_intern.h @@ -70,7 +70,6 @@ void OBJECT_OT_make_local(struct wmOperatorType *ot); void OBJECT_OT_make_single_user(struct wmOperatorType *ot); void OBJECT_OT_make_links_scene(struct wmOperatorType *ot); void OBJECT_OT_make_links_data(struct wmOperatorType *ot); -void OBJECT_OT_move_to_layer(struct wmOperatorType *ot); void OBJECT_OT_drop_named_material(struct wmOperatorType *ot); void OBJECT_OT_unlink_data(struct wmOperatorType *ot); @@ -78,10 +77,6 @@ void OBJECT_OT_unlink_data(struct wmOperatorType *ot); void OBJECT_OT_mode_set(struct wmOperatorType *ot); void OBJECT_OT_editmode_toggle(struct wmOperatorType *ot); void OBJECT_OT_posemode_toggle(struct wmOperatorType *ot); -void OBJECT_OT_hide_view_set(struct wmOperatorType *ot); -void OBJECT_OT_hide_view_clear(struct wmOperatorType *ot); -void OBJECT_OT_hide_render_set(struct wmOperatorType *ot); -void OBJECT_OT_hide_render_clear(struct wmOperatorType *ot); void OBJECT_OT_proxy_make(struct wmOperatorType *ot); void OBJECT_OT_shade_smooth(struct wmOperatorType *ot); void OBJECT_OT_shade_flat(struct wmOperatorType *ot); diff --git a/source/blender/editors/object/object_modifier.c b/source/blender/editors/object/object_modifier.c index 06f495fb9f1..bca7a163e90 100644 --- a/source/blender/editors/object/object_modifier.c +++ b/source/blender/editors/object/object_modifier.c @@ -411,7 +411,7 @@ int ED_object_modifier_move_down(ReportList *reports, Object *ob, ModifierData * return 1; } -int ED_object_modifier_convert(ReportList *UNUSED(reports), Main *bmain, Scene *scene, Object *ob, ModifierData *md) +int ED_object_modifier_convert(ReportList *UNUSED(reports), Main *bmain, Scene *scene, SceneLayer *sl, Object *ob, ModifierData *md) { Object *obn; ParticleSystem *psys; @@ -463,7 +463,7 @@ int ED_object_modifier_convert(ReportList *UNUSED(reports), Main *bmain, Scene * if (totvert == 0) return 0; /* add new mesh */ - obn = BKE_object_add(bmain, scene, OB_MESH, NULL); + obn = BKE_object_add(bmain, scene, sl, OB_MESH, NULL); me = obn->data; me->totvert = totvert; @@ -1048,10 +1048,11 @@ static int modifier_convert_exec(bContext *C, wmOperator *op) { Main *bmain = CTX_data_main(C); Scene *scene = CTX_data_scene(C); + SceneLayer *sl = CTX_data_scene_layer(C); Object *ob = ED_object_active_context(C); ModifierData *md = edit_modifier_property_get(op, ob, 0); - if (!md || !ED_object_modifier_convert(op->reports, bmain, scene, ob, md)) + if (!md || !ED_object_modifier_convert(op->reports, bmain, scene, sl, ob, md)) return OPERATOR_CANCELLED; DAG_id_tag_update(&ob->id, OB_RECALC_DATA); @@ -1683,7 +1684,7 @@ static void skin_armature_bone_create(Object *skin_ob, } } -static Object *modifier_skin_armature_create(Main *bmain, Scene *scene, Object *skin_ob) +static Object *modifier_skin_armature_create(Main *bmain, Scene *scene, SceneLayer *sl, Object *skin_ob) { BLI_bitmap *edges_visited; DerivedMesh *deform_dm; @@ -1706,7 +1707,7 @@ static Object *modifier_skin_armature_create(Main *bmain, Scene *scene, Object * NULL, me->totvert); - arm_ob = BKE_object_add(bmain, scene, OB_ARMATURE, NULL); + arm_ob = BKE_object_add(bmain, scene, sl, OB_ARMATURE, NULL); BKE_object_transform_copy(arm_ob, skin_ob); arm = arm_ob->data; arm->layer = 1; @@ -1765,6 +1766,7 @@ static int skin_armature_create_exec(bContext *C, wmOperator *op) { Main *bmain = CTX_data_main(C); Scene *scene = CTX_data_scene(C); + SceneLayer *sl = CTX_data_scene_layer(C); Object *ob = CTX_data_active_object(C), *arm_ob; Mesh *me = ob->data; ModifierData *skin_md; @@ -1776,7 +1778,7 @@ static int skin_armature_create_exec(bContext *C, wmOperator *op) } /* create new armature */ - arm_ob = modifier_skin_armature_create(bmain, scene, ob); + arm_ob = modifier_skin_armature_create(bmain, scene, sl, ob); /* add a modifier to connect the new armature to the mesh */ arm_md = (ArmatureModifierData *)modifier_new(eModifierType_Armature); diff --git a/source/blender/editors/object/object_ops.c b/source/blender/editors/object/object_ops.c index 7e7e1ef182c..19526db2ce8 100644 --- a/source/blender/editors/object/object_ops.c +++ b/source/blender/editors/object/object_ops.c @@ -67,10 +67,6 @@ void ED_operatortypes_object(void) WM_operatortype_append(OBJECT_OT_editmode_toggle); WM_operatortype_append(OBJECT_OT_posemode_toggle); WM_operatortype_append(OBJECT_OT_proxy_make); - WM_operatortype_append(OBJECT_OT_hide_view_clear); - WM_operatortype_append(OBJECT_OT_hide_view_set); - WM_operatortype_append(OBJECT_OT_hide_render_clear); - WM_operatortype_append(OBJECT_OT_hide_render_set); WM_operatortype_append(OBJECT_OT_shade_smooth); WM_operatortype_append(OBJECT_OT_shade_flat); WM_operatortype_append(OBJECT_OT_paths_calculate); @@ -90,13 +86,11 @@ void ED_operatortypes_object(void) WM_operatortype_append(OBJECT_OT_make_single_user); WM_operatortype_append(OBJECT_OT_make_links_scene); WM_operatortype_append(OBJECT_OT_make_links_data); - WM_operatortype_append(OBJECT_OT_move_to_layer); WM_operatortype_append(OBJECT_OT_select_random); WM_operatortype_append(OBJECT_OT_select_all); WM_operatortype_append(OBJECT_OT_select_same_group); WM_operatortype_append(OBJECT_OT_select_by_type); - WM_operatortype_append(OBJECT_OT_select_by_layer); WM_operatortype_append(OBJECT_OT_select_linked); WM_operatortype_append(OBJECT_OT_select_grouped); WM_operatortype_append(OBJECT_OT_select_mirror); @@ -382,25 +376,6 @@ void ED_keymap_object(wmKeyConfig *keyconf) WM_keymap_verify_item(keymap, "OBJECT_OT_origin_clear", OKEY, KM_PRESS, KM_ALT, 0); - WM_keymap_add_item(keymap, "OBJECT_OT_hide_view_clear", HKEY, KM_PRESS, KM_ALT, 0); - kmi = WM_keymap_add_item(keymap, "OBJECT_OT_hide_view_set", HKEY, KM_PRESS, 0, 0); - RNA_boolean_set(kmi->ptr, "unselected", false); - - kmi = WM_keymap_add_item(keymap, "OBJECT_OT_hide_view_set", HKEY, KM_PRESS, KM_SHIFT, 0); - RNA_boolean_set(kmi->ptr, "unselected", true); - - /* same as above but for rendering */ - WM_keymap_add_item(keymap, "OBJECT_OT_hide_render_clear", HKEY, KM_PRESS, KM_ALT | KM_CTRL, 0); - WM_keymap_add_item(keymap, "OBJECT_OT_hide_render_set", HKEY, KM_PRESS, KM_CTRL, 0); - - /* conflicts, removing */ -#if 0 - kmi = WM_keymap_add_item(keymap, "OBJECT_OT_hide_render_set", HKEY, KM_PRESS, KM_SHIFT | KM_CTRL, 0) - RNA_boolean_set(kmi->ptr, "unselected", true); -#endif - - WM_keymap_add_item(keymap, "OBJECT_OT_move_to_layer", MKEY, KM_PRESS, 0, 0); - kmi = WM_keymap_add_item(keymap, "OBJECT_OT_delete", XKEY, KM_PRESS, 0, 0); RNA_boolean_set(kmi->ptr, "use_global", false); diff --git a/source/blender/editors/object/object_relations.c b/source/blender/editors/object/object_relations.c index b5fbe4ba586..10439d49787 100644 --- a/source/blender/editors/object/object_relations.c +++ b/source/blender/editors/object/object_relations.c @@ -63,6 +63,7 @@ #include "BKE_animsys.h" #include "BKE_armature.h" #include "BKE_camera.h" +#include "BKE_collection.h" #include "BKE_context.h" #include "BKE_constraint.h" #include "BKE_curve.h" @@ -74,6 +75,7 @@ #include "BKE_fcurve.h" #include "BKE_lamp.h" #include "BKE_lattice.h" +#include "BKE_layer.h" #include "BKE_library.h" #include "BKE_library_query.h" #include "BKE_library_remap.h" @@ -331,6 +333,7 @@ static int make_proxy_exec(bContext *C, wmOperator *op) Object *ob, *gob = ED_object_active_context(C); GroupObject *go; Scene *scene = CTX_data_scene(C); + SceneLayer *sl = CTX_data_scene_layer(C); if (gob->dup_group != NULL) { go = BLI_findlink(&gob->dup_group->gobject, RNA_enum_get(op->ptr, "object")); @@ -343,13 +346,13 @@ static int make_proxy_exec(bContext *C, wmOperator *op) if (ob) { Object *newob; - Base *newbase, *oldbase = BASACT; + BaseLegacy *newbase, *oldbase = BASACT; char name[MAX_ID_NAME + 4]; BLI_snprintf(name, sizeof(name), "%s_proxy", ((ID *)(gob ? gob : ob))->name + 2); /* Add new object for the proxy */ - newob = BKE_object_add(bmain, scene, OB_EMPTY, name); + newob = BKE_object_add(bmain, scene, sl, OB_EMPTY, name); /* set layers OK */ newbase = BASACT; /* BKE_object_add sets active... */ @@ -1305,119 +1308,6 @@ void OBJECT_OT_track_set(wmOperatorType *ot) ot->prop = RNA_def_enum(ot->srna, "type", prop_make_track_types, 0, "Type", ""); } -/************************** Move to Layer Operator *****************************/ - -static unsigned int move_to_layer_init(bContext *C, wmOperator *op) -{ - int values[20], a; - unsigned int lay = 0; - - if (!RNA_struct_property_is_set(op->ptr, "layers")) { - /* note: layers are set in bases, library objects work for this */ - CTX_DATA_BEGIN (C, Base *, base, selected_bases) - { - lay |= base->lay; - } - CTX_DATA_END; - - for (a = 0; a < 20; a++) - values[a] = (lay & (1 << a)) != 0; - - RNA_boolean_set_array(op->ptr, "layers", values); - } - else { - RNA_boolean_get_array(op->ptr, "layers", values); - - for (a = 0; a < 20; a++) - if (values[a]) - lay |= (1 << a); - } - - return lay; -} - -static int move_to_layer_invoke(bContext *C, wmOperator *op, const wmEvent *event) -{ - View3D *v3d = CTX_wm_view3d(C); - if (v3d && v3d->localvd) { - return WM_operator_confirm_message(C, op, "Move out of Local View"); - } - else { - move_to_layer_init(C, op); - return WM_operator_props_popup(C, op, event); - } -} - -static int move_to_layer_exec(bContext *C, wmOperator *op) -{ - Main *bmain = CTX_data_main(C); - Scene *scene = CTX_data_scene(C); - View3D *v3d = CTX_wm_view3d(C); - unsigned int lay, local; - /* bool is_lamp = false; */ /* UNUSED */ - - lay = move_to_layer_init(C, op); - lay &= 0xFFFFFF; - - if (lay == 0) return OPERATOR_CANCELLED; - - if (v3d && v3d->localvd) { - /* now we can move out of localview. */ - /* note: layers are set in bases, library objects work for this */ - CTX_DATA_BEGIN (C, Base *, base, selected_bases) - { - lay = base->lay & ~v3d->lay; - base->lay = lay; - base->object->lay = lay; - base->object->flag &= ~SELECT; - base->flag &= ~SELECT; - /* if (base->object->type == OB_LAMP) is_lamp = true; */ - } - CTX_DATA_END; - } - else { - /* normal non localview operation */ - /* note: layers are set in bases, library objects work for this */ - CTX_DATA_BEGIN (C, Base *, base, selected_bases) - { - /* upper byte is used for local view */ - local = base->lay & 0xFF000000; - base->lay = lay + local; - base->object->lay = base->lay; - /* if (base->object->type == OB_LAMP) is_lamp = true; */ - } - CTX_DATA_END; - } - - /* warning, active object may be hidden now */ - - WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, scene); - WM_event_add_notifier(C, NC_SCENE | ND_LAYER_CONTENT, scene); - - DAG_relations_tag_update(bmain); - - return OPERATOR_FINISHED; -} - -void OBJECT_OT_move_to_layer(wmOperatorType *ot) -{ - /* identifiers */ - ot->name = "Move to Layer"; - ot->description = "Move the object to different layers"; - ot->idname = "OBJECT_OT_move_to_layer"; - - /* api callbacks */ - ot->invoke = move_to_layer_invoke; - ot->exec = move_to_layer_exec; - ot->poll = ED_operator_objectmode; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - - /* properties */ - RNA_def_boolean_layer_member(ot->srna, "layers", 20, NULL, "Layer", ""); -} - /************************** Link to Scene Operator *****************************/ #if 0 @@ -1440,20 +1330,6 @@ static void link_to_scene(Main *UNUSED(bmain), unsigned short UNUSED(nr)) } #endif -Base *ED_object_scene_link(Scene *scene, Object *ob) -{ - Base *base; - - if (BKE_scene_base_find(scene, ob)) { - return NULL; - } - - base = BKE_scene_base_add(scene, ob); - id_us_plus(&ob->id); - - return base; -} - static int make_links_scene_exec(bContext *C, wmOperator *op) { Scene *scene_to = BLI_findlink(&CTX_data_main(C)->scene, RNA_enum_get(op->ptr, "scene")); @@ -1473,9 +1349,10 @@ static int make_links_scene_exec(bContext *C, wmOperator *op) return OPERATOR_CANCELLED; } + SceneCollection *sc_to = BKE_collection_master(scene_to); CTX_DATA_BEGIN (C, Base *, base, selected_bases) { - ED_object_scene_link(scene_to, base->object); + BKE_collection_object_add(scene_to, sc_to, base->object); } CTX_DATA_END; @@ -1531,7 +1408,6 @@ static bool allow_make_links_data(const int type, Object *ob_src, Object *ob_dst static int make_links_data_exec(bContext *C, wmOperator *op) { Main *bmain = CTX_data_main(C); - Scene *scene = CTX_data_scene(C); const int type = RNA_enum_get(op->ptr, "type"); Object *ob_src; ID *obdata_id; @@ -1594,12 +1470,12 @@ static int make_links_data_exec(bContext *C, wmOperator *op) LinkNode *group_node; /* first clear groups */ - BKE_object_groups_clear(scene, base_dst, ob_dst); + BKE_object_groups_clear(ob_dst); /* now add in the groups from the link nodes */ for (group_node = ob_groups; group_node; group_node = group_node->next) { if (ob_dst->dup_group != group_node->link) { - BKE_group_object_add(group_node->link, ob_dst, scene, base_dst); + BKE_group_object_add(group_node->link, ob_dst); } else { is_cycle = true; @@ -1732,48 +1608,82 @@ void OBJECT_OT_make_links_data(wmOperatorType *ot) /**************************** Make Single User ********************************/ +static Object *single_object_users_object(Main *bmain, Scene *scene, Object *ob, const bool copy_groups) +{ + if (!ID_IS_LINKED_DATABLOCK(ob) && ob->id.us > 1) { + /* base gets copy of object */ + Object *obn = ID_NEW_SET(ob, BKE_object_copy(bmain, ob)); + + if (copy_groups) { + if (ob->flag & OB_FROMGROUP) { + obn->flag |= OB_FROMGROUP; + } + } + else { + /* copy already clears */ + } + /* remap gpencil parenting */ + + if (scene->gpd) { + bGPdata *gpd = scene->gpd; + for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) { + if (gpl->parent == ob) { + gpl->parent = obn; + } + } + } + + id_us_min(&ob->id); + return obn; + } + return NULL; +} + +static void libblock_relink_scene_collection(SceneCollection *sc) +{ + for (LinkData *link = sc->objects.first; link; link = link->next) { + BKE_libblock_relink_to_newid(link->data); + } + + for (SceneCollection *nsc = sc->scene_collections.first; nsc; nsc = nsc->next) { + libblock_relink_scene_collection(nsc); + } +} + +static void single_object_users_scene_collection(Main *bmain, Scene *scene, SceneCollection *sc, const int flag, const bool copy_groups) +{ + for (LinkData *link = sc->objects.first; link; link = link->next) { + Object *ob = link->data; + /* an object may be in more than one collection */ + if ((ob->id.newid == NULL) && ((ob->flag & flag) == flag)) { + link->data = single_object_users_object(bmain, scene, link->data, copy_groups); + } + } + + /* we reset filter objects because they should be regenerated after this */ + BLI_freelistN(&sc->filter_objects); + + for (SceneCollection *nsc = sc->scene_collections.first; nsc; nsc = nsc->next) { + single_object_users_scene_collection(bmain, scene, nsc, flag, copy_groups); + } +} + /* Warning, sets ID->newid pointers of objects and groups, but does not clear them. */ static void single_object_users(Main *bmain, Scene *scene, View3D *v3d, const int flag, const bool copy_groups) { - Base *base; - Object *ob, *obn; Group *group, *groupn; GroupObject *go; clear_sca_new_poins(); /* BGE logic */ - /* duplicate (must set newid) */ - for (base = FIRSTBASE; base; base = base->next) { - ob = base->object; - - if ((base->flag & flag) == flag) { - if (!ID_IS_LINKED_DATABLOCK(ob) && ob->id.us > 1) { - /* base gets copy of object */ - base->object = obn = ID_NEW_SET(ob, BKE_object_copy(bmain, ob)); + /* duplicate all the objects of the scene */ + SceneCollection *msc = BKE_collection_master(scene); + single_object_users_scene_collection(bmain, scene, msc, flag, copy_groups); - if (copy_groups) { - if (ob->flag & OB_FROMGROUP) { - obn->flag |= OB_FROMGROUP; - } - } - else { - /* copy already clears */ - } - /* remap gpencil parenting */ - - if (scene->gpd) { - bGPdata *gpd = scene->gpd; - for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) { - if (gpl->parent == ob) { - gpl->parent = obn; - } - } - } - - base->flag = obn->flag; - - id_us_min(&ob->id); - } + /* loop over SceneLayers and assign the pointers accordingly */ + for (SceneLayer *sl = scene->render_layers.first; sl; sl = sl->next) { + for (Base *base = sl->object_bases.first; base; base = base->next) { + ID_NEW_REMAP(base->object); } } @@ -1806,27 +1716,28 @@ static void single_object_users(Main *bmain, Scene *scene, View3D *v3d, const in if (v3d) ID_NEW_REMAP(v3d->camera); /* object and group pointers */ - for (base = FIRSTBASE; base; base = base->next) { - BKE_libblock_relink_to_newid(&base->object->id); - } + libblock_relink_scene_collection(msc); set_sca_new_poins(); + + /* TODO redo filter */ + TODO_LAYER_SYNC_FILTER } /* not an especially efficient function, only added so the single user * button can be functional.*/ void ED_object_single_user(Main *bmain, Scene *scene, Object *ob) { - Base *base; - const bool copy_groups = false; - - for (base = FIRSTBASE; base; base = base->next) { - if (base->object == ob) base->flag |= OB_DONE; - else base->flag &= ~OB_DONE; + FOREACH_SCENE_OBJECT(scene, ob_iter) + { + ob_iter->flag &= ~OB_DONE; } + FOREACH_SCENE_OBJECT_END - single_object_users(bmain, scene, NULL, OB_DONE, copy_groups); + /* tag only the one object */ + ob->flag |= OB_DONE; + single_object_users(bmain, scene, NULL, OB_DONE, false); BKE_main_id_clear_newpoins(bmain); } @@ -1857,15 +1768,17 @@ static void single_obdata_users(Main *bmain, Scene *scene, const int flag) Lamp *la; Curve *cu; /* Camera *cam; */ - Base *base; + BaseLegacy *base; Mesh *me; Lattice *lat; ID *id; int a; + TODO_LAYER; /* need to use scene->collection base instead of scene->bases */ + for (base = FIRSTBASE; base; base = base->next) { ob = base->object; - if (!ID_IS_LINKED_DATABLOCK(ob) && (base->flag & flag) == flag) { + if (!ID_IS_LINKED_DATABLOCK(ob) && (base->flag_legacy & flag) == flag) { id = ob->data; if (id && id->us > 1 && !ID_IS_LINKED_DATABLOCK(id)) { @@ -1939,31 +1852,24 @@ static void single_obdata_users(Main *bmain, Scene *scene, const int flag) } } -static void single_object_action_users(Scene *scene, const int flag) +static void single_object_action_users(Scene *scene, SceneLayer *sl, const int flag) { - Object *ob; - Base *base; - - for (base = FIRSTBASE; base; base = base->next) { - ob = base->object; - if (!ID_IS_LINKED_DATABLOCK(ob) && (flag == 0 || (base->flag & SELECT)) ) { + FOREACH_OBJECT_FLAG(scene, sl, flag, ob) + if (!ID_IS_LINKED_DATABLOCK(ob)) { DAG_id_tag_update(&ob->id, OB_RECALC_DATA); BKE_animdata_copy_id_action(&ob->id, false); } - } + FOREACH_OBJECT_FLAG_END } -static void single_mat_users(Main *bmain, Scene *scene, const int flag, const bool do_textures) +static void single_mat_users(Main *bmain, Scene *scene, SceneLayer *sl, const int flag, const bool do_textures) { - Object *ob; - Base *base; Material *ma, *man; Tex *tex; int a, b; - for (base = FIRSTBASE; base; base = base->next) { - ob = base->object; - if (!ID_IS_LINKED_DATABLOCK(ob) && (flag == 0 || (base->flag & SELECT)) ) { + FOREACH_OBJECT_FLAG(scene, sl, flag, ob) + if (!ID_IS_LINKED_DATABLOCK(ob)) { for (a = 1; a <= ob->totcol; a++) { ma = give_current_material(ob, a); if (ma) { @@ -1992,7 +1898,7 @@ static void single_mat_users(Main *bmain, Scene *scene, const int flag, const bo } } } - } + FOREACH_OBJECT_FLAG_END } static void do_single_tex_user(Main *bmain, Tex **from) @@ -2096,7 +2002,7 @@ void ED_object_single_users(Main *bmain, Scene *scene, const bool full, const bo if (full) { single_obdata_users(bmain, scene, 0); - single_object_action_users(scene, 0); + single_object_action_users(scene, NULL, 0); single_mat_users_expand(bmain); single_tex_users_expand(bmain); } @@ -2194,13 +2100,13 @@ static bool make_local_all__instance_indirect_unused(Main *bmain, Scene *scene) for (ob = bmain->object.first; ob; ob = ob->id.next) { if (ID_IS_LINKED_DATABLOCK(ob) && (ob->id.us == 0)) { - Base *base; + BaseLegacy *base; id_us_plus(&ob->id); base = BKE_scene_base_add(scene, ob); - base->flag |= SELECT; - base->object->flag = base->flag; + base->flag_legacy |= SELECT; + BKE_scene_base_flag_sync_from_base(base); DAG_id_tag_update(&ob->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME); changed = true; @@ -2366,13 +2272,20 @@ static int make_single_user_exec(bContext *C, wmOperator *op) { Main *bmain = CTX_data_main(C); Scene *scene = CTX_data_scene(C); + SceneLayer *sl = CTX_data_scene_layer(C); View3D *v3d = CTX_wm_view3d(C); /* ok if this is NULL */ const int flag = (RNA_enum_get(op->ptr, "type") == MAKE_SINGLE_USER_SELECTED) ? SELECT : 0; const bool copy_groups = false; bool update_deps = false; if (RNA_boolean_get(op->ptr, "object")) { - single_object_users(bmain, scene, v3d, flag, copy_groups); + if (flag == SELECT) { + BKE_scene_layer_selected_objects_tag(sl, OB_DONE); + single_object_users(bmain, scene, v3d, OB_DONE, copy_groups); + } + else { + single_object_users(bmain, scene, v3d, 0, copy_groups); + } /* needed since object relationships may have changed */ update_deps = true; @@ -2383,7 +2296,7 @@ static int make_single_user_exec(bContext *C, wmOperator *op) } if (RNA_boolean_get(op->ptr, "material")) { - single_mat_users(bmain, scene, flag, RNA_boolean_get(op->ptr, "texture")); + single_mat_users(bmain, scene, sl, flag, RNA_boolean_get(op->ptr, "texture")); } #if 0 /* can't do this separate from materials */ @@ -2391,7 +2304,7 @@ static int make_single_user_exec(bContext *C, wmOperator *op) single_mat_users(scene, flag, true); #endif if (RNA_boolean_get(op->ptr, "animation")) { - single_object_action_users(scene, flag); + single_object_action_users(scene, sl, flag); } BKE_main_id_clear_newpoins(bmain); @@ -2438,7 +2351,7 @@ void OBJECT_OT_make_single_user(wmOperatorType *ot) static int drop_named_material_invoke(bContext *C, wmOperator *op, const wmEvent *event) { - Base *base = ED_view3d_give_base_under_cursor(C, event->mval); + BaseLegacy *base = ED_view3d_give_base_under_cursor(C, event->mval); Material *ma; char name[MAX_ID_NAME - 2]; diff --git a/source/blender/editors/object/object_select.c b/source/blender/editors/object/object_select.c index b5131df3eaa..37232456f48 100644 --- a/source/blender/editors/object/object_select.c +++ b/source/blender/editors/object/object_select.c @@ -52,6 +52,7 @@ #include "BKE_context.h" #include "BKE_group.h" +#include "BKE_layer.h" #include "BKE_main.h" #include "BKE_material.h" #include "BKE_particle.h" @@ -86,22 +87,22 @@ /* Note: send a NC_SCENE|ND_OB_SELECT notifier yourself! (or * or a NC_SCENE|ND_OB_VISIBLE in case of visibility toggling */ -void ED_base_object_select(Base *base, short mode) +void ED_base_object_select(BaseLegacy *base, short mode) { if (base) { if (mode == BA_SELECT) { if (!(base->object->restrictflag & OB_RESTRICT_SELECT)) - base->flag |= SELECT; + base->flag_legacy |= SELECT; } else if (mode == BA_DESELECT) { - base->flag &= ~SELECT; + base->flag_legacy &= ~SELECT; } - base->object->flag = base->flag; + BKE_scene_base_flag_sync_from_base(base); } } /* also to set active NULL */ -void ED_base_object_activate(bContext *C, Base *base) +void ED_base_object_activate(bContext *C, BaseLegacy *base) { Scene *scene = CTX_data_scene(C); @@ -119,6 +120,33 @@ void ED_base_object_activate(bContext *C, Base *base) WM_event_add_notifier(C, NC_SCENE | ND_OB_ACTIVE, NULL); } +void ED_object_base_select(Base *base, short mode) +{ + if (base) { + if (mode == BA_SELECT) { + if ((base->flag & BASE_SELECTABLED) != 0) { + base->flag |= BASE_SELECTED; + } + } + else if (mode == BA_DESELECT) { + base->flag &= ~BASE_SELECTED; + } + } +} + +void ED_object_base_activate(bContext *C, Base *base) +{ + SceneLayer *sl = CTX_data_scene_layer(C); + sl->basact = base; + + if (base) { + WM_event_add_notifier(C, NC_SCENE | ND_OB_ACTIVE, sl); + } + else { + WM_event_add_notifier(C, NC_SCENE | ND_OB_ACTIVE, NULL); + } +} + /********************** Selection Operators **********************/ static int objects_selectable_poll(bContext *C) @@ -147,7 +175,7 @@ static int object_select_by_type_exec(bContext *C, wmOperator *op) if (extend == 0) { CTX_DATA_BEGIN (C, Base *, base, visible_bases) { - ED_base_object_select(base, BA_DESELECT); + ED_object_base_select(base, BA_DESELECT); } CTX_DATA_END; } @@ -155,7 +183,7 @@ static int object_select_by_type_exec(bContext *C, wmOperator *op) CTX_DATA_BEGIN (C, Base *, base, visible_bases) { if (base->object->type == obtype) { - ED_base_object_select(base, BA_SELECT); + ED_object_base_select(base, BA_SELECT); } } CTX_DATA_END; @@ -210,38 +238,15 @@ static EnumPropertyItem prop_select_linked_types[] = { {0, NULL, 0, NULL, NULL} }; -// XXX old animation system -#if 0 -static int object_select_all_by_ipo(bContext *C, Ipo *ipo) -{ - bool changed = false; - - CTX_DATA_BEGIN (C, Base *, base, visible_bases) - { - if (base->object->ipo == ipo) { - base->flag |= SELECT; - base->object->flag = base->flag; - - changed = true; - } - } - CTX_DATA_END; - - return changed; -} -#endif - static bool object_select_all_by_obdata(bContext *C, void *obdata) { bool changed = false; CTX_DATA_BEGIN (C, Base *, base, visible_bases) { - if ((base->flag & SELECT) == 0) { + if (((base->flag & BASE_SELECTED) == 0) && ((base->flag & BASE_SELECTABLED) != 0)) { if (base->object->data == obdata) { - base->flag |= SELECT; - base->object->flag = base->flag; - + ED_object_base_select(base, BA_SELECT); changed = true; } } @@ -257,7 +262,7 @@ static bool object_select_all_by_material_texture(bContext *C, int use_texture, CTX_DATA_BEGIN (C, Base *, base, visible_bases) { - if ((base->flag & SELECT) == 0) { + if (((base->flag & BASE_SELECTED) == 0) && ((base->flag & BASE_SELECTABLED) != 0)) { Object *ob = base->object; Material *mat1; int a, b; @@ -267,7 +272,7 @@ static bool object_select_all_by_material_texture(bContext *C, int use_texture, if (!use_texture) { if (mat1 == mat) { - base->flag |= SELECT; + ED_object_base_select(base, BA_SELECT); changed = true; } } @@ -275,7 +280,7 @@ static bool object_select_all_by_material_texture(bContext *C, int use_texture, for (b = 0; b < MAX_MTEX; b++) { if (mat1->mtex[b]) { if (tex == mat1->mtex[b]->tex) { - base->flag |= SELECT; + ED_object_base_select(base, BA_SELECT); changed = true; break; } @@ -283,8 +288,6 @@ static bool object_select_all_by_material_texture(bContext *C, int use_texture, } } } - - base->object->flag = base->flag; } } CTX_DATA_END; @@ -299,12 +302,10 @@ static bool object_select_all_by_dup_group(bContext *C, Object *ob) CTX_DATA_BEGIN (C, Base *, base, visible_bases) { - if ((base->flag & SELECT) == 0) { + if (((base->flag & BASE_SELECTED) == 0) && ((base->flag & BASE_SELECTABLED) != 0)) { Group *dup_group_other = (base->object->transflag & OB_DUPLIGROUP) ? base->object->dup_group : NULL; if (dup_group == dup_group_other) { - base->flag |= SELECT; - base->object->flag = base->flag; - + ED_object_base_select(base, BA_SELECT); changed = true; } } @@ -321,23 +322,21 @@ static bool object_select_all_by_particle(bContext *C, Object *ob) CTX_DATA_BEGIN (C, Base *, base, visible_bases) { - if ((base->flag & SELECT) == 0) { + if (((base->flag & BASE_SELECTED) == 0) && ((base->flag & BASE_SELECTABLED) != 0)) { /* loop through other particles*/ ParticleSystem *psys; for (psys = base->object->particlesystem.first; psys; psys = psys->next) { if (psys->part == psys_act->part) { - base->flag |= SELECT; + ED_object_base_select(base, BA_SELECT); changed = true; break; } - if (base->flag & SELECT) { + if (base->flag & BASE_SELECTED) { break; } } - - base->object->flag = base->flag; } } CTX_DATA_END; @@ -351,11 +350,9 @@ static bool object_select_all_by_library(bContext *C, Library *lib) CTX_DATA_BEGIN (C, Base *, base, visible_bases) { - if ((base->flag & SELECT) == 0) { + if (((base->flag & BASE_SELECTED) == 0) && ((base->flag & BASE_SELECTABLED) != 0)) { if (lib == base->object->id.lib) { - base->flag |= SELECT; - base->object->flag = base->flag; - + ED_object_base_select(base, BA_SELECT); changed = true; } } @@ -371,11 +368,9 @@ static bool object_select_all_by_library_obdata(bContext *C, Library *lib) CTX_DATA_BEGIN (C, Base *, base, visible_bases) { - if ((base->flag & SELECT) == 0) { + if (((base->flag & BASE_SELECTED) == 0) && ((base->flag & BASE_SELECTABLED) != 0)) { if (base->object->data && lib == ((ID *)base->object->data)->lib) { - base->flag |= SELECT; - base->object->flag = base->flag; - + ED_object_base_select(base, BA_SELECT); changed = true; } } @@ -408,6 +403,7 @@ void ED_object_select_linked_by_id(bContext *C, ID *id) static int object_select_linked_exec(bContext *C, wmOperator *op) { Scene *scene = CTX_data_scene(C); + SceneLayer *sl = CTX_data_scene_layer(C); Object *ob; int nr = RNA_enum_get(op->ptr, "type"); bool changed = false, extend; @@ -417,12 +413,12 @@ static int object_select_linked_exec(bContext *C, wmOperator *op) if (extend == 0) { CTX_DATA_BEGIN (C, Base *, base, visible_bases) { - ED_base_object_select(base, BA_DESELECT); + ED_object_base_select(base, BA_DESELECT); } CTX_DATA_END; } - ob = OBACT; + ob = OBACT_NEW; if (ob == NULL) { BKE_report(op->reports, RPT_ERROR, "No active object"); return OPERATOR_CANCELLED; @@ -517,7 +513,7 @@ enum { OBJECT_GRPSEL_PARENT = 2, OBJECT_GRPSEL_SIBLINGS = 3, OBJECT_GRPSEL_TYPE = 4, - OBJECT_GRPSEL_LAYER = 5, + /*OBJECT_GRPSEL_LAYER = 5,*/ OBJECT_GRPSEL_GROUP = 6, OBJECT_GRPSEL_HOOK = 7, OBJECT_GRPSEL_PASS = 8, @@ -533,7 +529,6 @@ static EnumPropertyItem prop_select_grouped_types[] = { {OBJECT_GRPSEL_PARENT, "PARENT", 0, "Parent", ""}, {OBJECT_GRPSEL_SIBLINGS, "SIBLINGS", 0, "Siblings", "Shared Parent"}, {OBJECT_GRPSEL_TYPE, "TYPE", 0, "Type", "Shared object type"}, - {OBJECT_GRPSEL_LAYER, "LAYER", 0, "Layer", "Shared layers"}, {OBJECT_GRPSEL_GROUP, "GROUP", 0, "Group", "Shared group"}, {OBJECT_GRPSEL_HOOK, "HOOK", 0, "Hook", ""}, {OBJECT_GRPSEL_PASS, "PASS", 0, "Pass", "Render pass Index"}, @@ -551,13 +546,14 @@ static bool select_grouped_children(bContext *C, Object *ob, const bool recursiv CTX_DATA_BEGIN (C, Base *, base, selectable_bases) { if (ob == base->object->parent) { - if (!(base->flag & SELECT)) { - ED_base_object_select(base, BA_SELECT); + if ((base->flag & BASE_SELECTED) == 0) { + ED_object_base_select(base, BA_SELECT); changed = true; } - if (recursive) + if (recursive) { changed |= select_grouped_children(C, base->object, 1); + } } } CTX_DATA_END; @@ -566,20 +562,21 @@ static bool select_grouped_children(bContext *C, Object *ob, const bool recursiv static bool select_grouped_parent(bContext *C) /* Makes parent active and de-selected OBACT */ { - Scene *scene = CTX_data_scene(C); + SceneLayer *sl = CTX_data_scene_layer(C); View3D *v3d = CTX_wm_view3d(C); - - bool changed = false; Base *baspar, *basact = CTX_data_active_base(C); + bool changed = false; - if (!basact || !(basact->object->parent)) return 0; /* we know OBACT is valid */ + if (!basact || !(basact->object->parent)) { + return 0; /* we know OBACT is valid */ + } - baspar = BKE_scene_base_find(scene, basact->object->parent); + baspar = BKE_scene_layer_base_find(sl, basact->object->parent); /* can be NULL if parent in other scene */ if (baspar && BASE_SELECTABLE(v3d, baspar)) { - ED_base_object_select(baspar, BA_SELECT); - ED_base_object_activate(C, baspar); + ED_object_base_select(baspar, BA_SELECT); + ED_object_base_activate(C, baspar); changed = true; } return changed; @@ -608,9 +605,11 @@ static bool select_grouped_group(bContext *C, Object *ob) /* Select objects in group = ob_groups[0]; CTX_DATA_BEGIN (C, Base *, base, visible_bases) { - if (!(base->flag & SELECT) && BKE_group_object_exists(group, base->object)) { - ED_base_object_select(base, BA_SELECT); - changed = true; + if (((base->flag & BASE_SELECTED) == 0) && ((base->flag & BASE_SELECTABLED) != 0)) { + if (BKE_group_object_exists(group, base->object)) { + ED_object_base_select(base, BA_SELECT); + changed = true; + } } } CTX_DATA_END; @@ -636,7 +635,7 @@ static bool select_grouped_object_hooks(bContext *C, Object *ob) View3D *v3d = CTX_wm_view3d(C); bool changed = false; - Base *base; + BaseLegacy *base; ModifierData *md; HookModifierData *hmd; @@ -663,8 +662,8 @@ static bool select_grouped_siblings(bContext *C, Object *ob) CTX_DATA_BEGIN (C, Base *, base, selectable_bases) { - if ((base->object->parent == ob->parent) && !(base->flag & SELECT)) { - ED_base_object_select(base, BA_SELECT); + if ((base->object->parent == ob->parent) && ((base->flag & BASE_SELECTED) == 0)) { + ED_object_base_select(base, BA_SELECT); changed = true; } } @@ -681,8 +680,8 @@ static bool select_grouped_lamptype(bContext *C, Object *ob) { if (base->object->type == OB_LAMP) { Lamp *la_test = base->object->data; - if ((la->type == la_test->type) && !(base->flag & SELECT)) { - ED_base_object_select(base, BA_SELECT); + if ((la->type == la_test->type) && ((base->flag & BASE_SELECTED) == 0)) { + ED_object_base_select(base, BA_SELECT); changed = true; } } @@ -696,23 +695,8 @@ static bool select_grouped_type(bContext *C, Object *ob) CTX_DATA_BEGIN (C, Base *, base, selectable_bases) { - if ((base->object->type == ob->type) && !(base->flag & SELECT)) { - ED_base_object_select(base, BA_SELECT); - changed = true; - } - } - CTX_DATA_END; - return changed; -} - -static bool select_grouped_layer(bContext *C, Object *ob) -{ - bool changed = false; - - CTX_DATA_BEGIN (C, Base *, base, selectable_bases) - { - if ((base->lay & ob->lay) && !(base->flag & SELECT)) { - ED_base_object_select(base, BA_SELECT); + if ((base->object->type == ob->type) && ((base->flag & BASE_SELECTED) == 0)) { + ED_object_base_select(base, BA_SELECT); changed = true; } } @@ -726,8 +710,8 @@ static bool select_grouped_index_object(bContext *C, Object *ob) CTX_DATA_BEGIN (C, Base *, base, selectable_bases) { - if ((base->object->index == ob->index) && !(base->flag & SELECT)) { - ED_base_object_select(base, BA_SELECT); + if ((base->object->index == ob->index) && ((base->flag & BASE_SELECTED) == 0)) { + ED_object_base_select(base, BA_SELECT); changed = true; } } @@ -741,8 +725,8 @@ static bool select_grouped_color(bContext *C, Object *ob) CTX_DATA_BEGIN (C, Base *, base, selectable_bases) { - if (!(base->flag & SELECT) && (compare_v3v3(base->object->col, ob->col, 0.005f))) { - ED_base_object_select(base, BA_SELECT); + if (((base->flag & BASE_SELECTED) == 0) && (compare_v3v3(base->object->col, ob->col, 0.005f))) { + ED_object_base_select(base, BA_SELECT); changed = true; } } @@ -768,8 +752,8 @@ static bool select_grouped_gameprops(bContext *C, Object *ob) CTX_DATA_BEGIN (C, Base *, base, selectable_bases) { - if (!(base->flag & SELECT) && (objects_share_gameprop(base->object, ob))) { - ED_base_object_select(base, BA_SELECT); + if (((base->flag & BASE_SELECTED) == 0) && (objects_share_gameprop(base->object, ob))) { + ED_object_base_select(base, BA_SELECT); changed = true; } } @@ -807,7 +791,7 @@ static bool select_grouped_keyingset(bContext *C, Object *UNUSED(ob), ReportList CTX_DATA_BEGIN (C, Base *, base, selectable_bases) { /* only check for this object if it isn't selected already, to limit time wasted */ - if ((base->flag & SELECT) == 0) { + if ((base->flag & BASE_SELECTED) == 0) { KS_Path *ksp; /* this is the slow way... we could end up with > 500 items here, @@ -816,7 +800,7 @@ static bool select_grouped_keyingset(bContext *C, Object *UNUSED(ob), ReportList for (ksp = ks->paths.first; ksp; ksp = ksp->next) { /* if id matches, select then stop looping (match found) */ if (ksp->id == (ID *)base->object) { - ED_base_object_select(base, BA_SELECT); + ED_object_base_select(base, BA_SELECT); changed = true; break; } @@ -831,6 +815,7 @@ static bool select_grouped_keyingset(bContext *C, Object *UNUSED(ob), ReportList static int object_select_grouped_exec(bContext *C, wmOperator *op) { Scene *scene = CTX_data_scene(C); + SceneLayer *sl = CTX_data_scene_layer(C); Object *ob; const int type = RNA_enum_get(op->ptr, "type"); bool changed = false, extend; @@ -840,13 +825,13 @@ static int object_select_grouped_exec(bContext *C, wmOperator *op) if (extend == 0) { CTX_DATA_BEGIN (C, Base *, base, visible_bases) { - ED_base_object_select(base, BA_DESELECT); + ED_object_base_select(base, BA_DESELECT); changed = true; } CTX_DATA_END; } - ob = OBACT; + ob = OBACT_NEW; if (ob == NULL) { BKE_report(op->reports, RPT_ERROR, "No active object"); return OPERATOR_CANCELLED; @@ -868,9 +853,6 @@ static int object_select_grouped_exec(bContext *C, wmOperator *op) case OBJECT_GRPSEL_TYPE: changed |= select_grouped_type(C, ob); break; - case OBJECT_GRPSEL_LAYER: - changed |= select_grouped_layer(C, ob); - break; case OBJECT_GRPSEL_GROUP: changed |= select_grouped_group(C, ob); break; @@ -928,85 +910,6 @@ void OBJECT_OT_select_grouped(wmOperatorType *ot) ot->prop = RNA_def_enum(ot->srna, "type", prop_select_grouped_types, 0, "Type", ""); } -/************************* Select by Layer **********************/ -enum { - OB_SEL_LAYERMATCH_EXACT = 1, - OB_SEL_LAYERMATCH_SHARED = 2, -}; - -static int object_select_by_layer_exec(bContext *C, wmOperator *op) -{ - unsigned int layernum; - bool extend; - int match; - - extend = RNA_boolean_get(op->ptr, "extend"); - layernum = RNA_int_get(op->ptr, "layers"); - match = RNA_enum_get(op->ptr, "match"); - - if (extend == false) { - CTX_DATA_BEGIN (C, Base *, base, visible_bases) - { - ED_base_object_select(base, BA_DESELECT); - } - CTX_DATA_END; - } - - CTX_DATA_BEGIN (C, Base *, base, visible_bases) - { - bool ok = false; - - switch (match) { - case OB_SEL_LAYERMATCH_EXACT: - /* Mask out bits used for local view, only work on real layer ones, see T45783. */ - ok = ((base->lay & ((1 << 20) - 1)) == (1 << (layernum - 1))); - break; - case OB_SEL_LAYERMATCH_SHARED: - ok = (base->lay & (1 << (layernum - 1))) != 0; - break; - default: - break; - } - - if (ok) { - ED_base_object_select(base, BA_SELECT); - } - } - CTX_DATA_END; - - /* undo? */ - WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, CTX_data_scene(C)); - - return OPERATOR_FINISHED; -} - -void OBJECT_OT_select_by_layer(wmOperatorType *ot) -{ - static EnumPropertyItem match_items[] = { - {OB_SEL_LAYERMATCH_EXACT, "EXACT", 0, "Exact Match", ""}, - {OB_SEL_LAYERMATCH_SHARED, "SHARED", 0, "Shared Layers", ""}, - {0, NULL, 0, NULL, NULL} - }; - - /* identifiers */ - ot->name = "Select by Layer"; - ot->description = "Select all visible objects on a layer"; - ot->idname = "OBJECT_OT_select_by_layer"; - - /* api callbacks */ - /*ot->invoke = XXX - need a int grid popup*/ - ot->exec = object_select_by_layer_exec; - ot->poll = objects_selectable_poll; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - - /* properties */ - RNA_def_enum(ot->srna, "match", match_items, OB_SEL_LAYERMATCH_EXACT, "Match", ""); - RNA_def_boolean(ot->srna, "extend", false, "Extend", "Extend selection instead of deselecting everything first"); - RNA_def_int(ot->srna, "layers", 1, 1, 20, "Layer", "", 1, 20); -} - /**************************** (De)select All ****************************/ static int object_select_all_exec(bContext *C, wmOperator *op) @@ -1020,7 +923,7 @@ static int object_select_all_exec(bContext *C, wmOperator *op) action = SEL_SELECT; CTX_DATA_BEGIN (C, Base *, base, visible_bases) { - if (base->flag & SELECT) { + if ((base->flag & BASE_SELECTED) != 0) { action = SEL_DESELECT; break; } @@ -1032,17 +935,17 @@ static int object_select_all_exec(bContext *C, wmOperator *op) { switch (action) { case SEL_SELECT: - ED_base_object_select(base, BA_SELECT); + ED_object_base_select(base, BA_SELECT); break; case SEL_DESELECT: - ED_base_object_select(base, BA_DESELECT); + ED_object_base_select(base, BA_DESELECT); break; case SEL_INVERT: - if (base->flag & SELECT) { - ED_base_object_select(base, BA_DESELECT); + if ((base->flag & BASE_SELECTED) != 0) { + ED_object_base_select(base, BA_DESELECT); } else { - ED_base_object_select(base, BA_SELECT); + ED_object_base_select(base, BA_SELECT); } break; } @@ -1092,8 +995,11 @@ static int object_select_same_group_exec(bContext *C, wmOperator *op) CTX_DATA_BEGIN (C, Base *, base, visible_bases) { - if (!(base->flag & SELECT) && BKE_group_object_exists(group, base->object)) - ED_base_object_select(base, BA_SELECT); + if (((base->flag & BASE_SELECTED) == 0) && ((base->flag & BASE_SELECTABLED) != 0)) { + if (BKE_group_object_exists(group, base->object)) { + ED_object_base_select(base, BA_SELECT); + } + } } CTX_DATA_END; @@ -1124,6 +1030,7 @@ void OBJECT_OT_select_same_group(wmOperatorType *ot) static int object_select_mirror_exec(bContext *C, wmOperator *op) { Scene *scene = CTX_data_scene(C); + SceneLayer *sl = CTX_data_scene_layer(C); bool extend; extend = RNA_boolean_get(op->ptr, "extend"); @@ -1137,15 +1044,15 @@ static int object_select_mirror_exec(bContext *C, wmOperator *op) if (!STREQ(name_flip, primbase->object->id.name + 2)) { Object *ob = (Object *)BKE_libblock_find_name(ID_OB, name_flip); if (ob) { - Base *secbase = BKE_scene_base_find(scene, ob); + Base *secbase = BKE_scene_layer_base_find(sl, ob); if (secbase) { - ED_base_object_select(secbase, BA_SELECT); + ED_object_base_select(secbase, BA_SELECT); } } } - if (extend == false) ED_base_object_select(primbase, BA_DESELECT); + if (extend == false) ED_object_base_select(primbase, BA_DESELECT); } CTX_DATA_END; @@ -1180,9 +1087,9 @@ void OBJECT_OT_select_mirror(wmOperatorType *ot) static bool object_select_more_less(bContext *C, const bool select) { - Scene *scene = CTX_data_scene(C); + SceneLayer *sl = CTX_data_scene_layer(C); - for (Base *base = scene->base.first; base; base = base->next) { + for (BaseLegacy *base = sl->object_bases.first; base; base = base->next) { Object *ob = base->object; ob->flag &= ~OB_DONE; ob->id.tag &= ~LIB_TAG_DOIT; @@ -1223,7 +1130,7 @@ static bool object_select_more_less(bContext *C, const bool select) Base *base = ctx_base->ptr.data; Object *ob = base->object; if ((ob->id.tag & LIB_TAG_DOIT) && ((ob->flag & SELECT) != select_flag)) { - ED_base_object_select(base, select_mode); + ED_object_base_select(base, select_mode); changed = true; } } @@ -1305,7 +1212,7 @@ static int object_select_random_exec(bContext *C, wmOperator *op) CTX_DATA_BEGIN (C, Base *, base, selectable_bases) { if (BLI_rng_get_float(rng) < randfac) { - ED_base_object_select(base, select); + ED_object_base_select(base, select); } } CTX_DATA_END; diff --git a/source/blender/editors/object/object_vgroup.c b/source/blender/editors/object/object_vgroup.c index 3c406764157..d93275a353e 100644 --- a/source/blender/editors/object/object_vgroup.c +++ b/source/blender/editors/object/object_vgroup.c @@ -59,6 +59,7 @@ #include "BKE_depsgraph.h" #include "BKE_mesh_mapping.h" #include "BKE_editmesh.h" +#include "BKE_layer.h" #include "BKE_modifier.h" #include "BKE_report.h" #include "BKE_DerivedMesh.h" @@ -3300,25 +3301,26 @@ void OBJECT_OT_vertex_group_mirror(wmOperatorType *ot) static int vertex_group_copy_to_linked_exec(bContext *C, wmOperator *UNUSED(op)) { Scene *scene = CTX_data_scene(C); - Object *ob = ED_object_context(C); - Base *base; + Object *ob_active = ED_object_context(C); int retval = OPERATOR_CANCELLED; - for (base = scene->base.first; base; base = base->next) { - if (base->object->type == ob->type) { - if (base->object != ob && base->object->data == ob->data) { - BLI_freelistN(&base->object->defbase); - BLI_duplicatelist(&base->object->defbase, &ob->defbase); - base->object->actdef = ob->actdef; + FOREACH_SCENE_OBJECT(scene, ob_iter) + { + if (ob_iter->type == ob_active->type) { + if (ob_iter != ob_active && ob_iter->data == ob_active->data) { + BLI_freelistN(&ob_iter->defbase); + BLI_duplicatelist(&ob_iter->defbase, &ob_active->defbase); + ob_iter->actdef = ob_active->actdef; - DAG_id_tag_update(&base->object->id, OB_RECALC_DATA); - WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, base->object); - WM_event_add_notifier(C, NC_GEOM | ND_VERTEX_GROUP, base->object->data); + DAG_id_tag_update(&ob_iter->id, OB_RECALC_DATA); + WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob_iter); + WM_event_add_notifier(C, NC_GEOM | ND_VERTEX_GROUP, ob_iter->data); retval = OPERATOR_FINISHED; } } } + FOREACH_SCENE_OBJECT_END return retval; } diff --git a/source/blender/editors/physics/particle_edit.c b/source/blender/editors/physics/particle_edit.c index e22a145b3a6..b305c33c3fa 100644 --- a/source/blender/editors/physics/particle_edit.c +++ b/source/blender/editors/physics/particle_edit.c @@ -73,6 +73,8 @@ #include "ED_particle.h" #include "ED_view3d.h" +#include "GPU_immediate.h" + #include "UI_resources.h" #include "WM_api.h" @@ -2690,24 +2692,27 @@ static void brush_drawcursor(bContext *C, int x, int y, void *UNUSED(customdata) ParticleEditSettings *pset= PE_settings(scene); ParticleBrushData *brush; - if (pset->brushtype < 0) + if (pset->brushtype < 0) { return; + } - brush= &pset->brush[pset->brushtype]; + brush = &pset->brush[pset->brushtype]; if (brush) { - glPushMatrix(); + unsigned int pos = add_attrib(immVertexFormat(), "pos", GL_FLOAT, 2, KEEP_FLOAT); + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); - glTranslatef((float)x, (float)y, 0.0f); + immUniformColor4ub(255, 255, 255, 128); - glColor4ub(255, 255, 255, 128); glEnable(GL_LINE_SMOOTH); glEnable(GL_BLEND); - glutil_draw_lined_arc(0.0, M_PI*2.0, pe_brush_size_get(scene, brush), 40); + + imm_draw_lined_circle(pos, (float)x, (float)y, pe_brush_size_get(scene, brush), 40); + glDisable(GL_BLEND); glDisable(GL_LINE_SMOOTH); - - glPopMatrix(); + + immUnbindProgram(); } } diff --git a/source/blender/editors/physics/physics_fluid.c b/source/blender/editors/physics/physics_fluid.c index b5adf38527b..bb3375b91a6 100644 --- a/source/blender/editors/physics/physics_fluid.c +++ b/source/blender/editors/physics/physics_fluid.c @@ -329,7 +329,7 @@ static void free_all_fluidobject_channels(ListBase *fobjects) static void fluid_init_all_channels(bContext *C, Object *UNUSED(fsDomain), FluidsimSettings *domainSettings, FluidAnimChannels *channels, ListBase *fobjects) { Scene *scene = CTX_data_scene(C); - Base *base; + BaseLegacy *base; int i; int length = channels->length; float eval_time; @@ -572,7 +572,7 @@ static void export_fluid_objects(ListBase *fobjects, Scene *scene, int length) static int fluid_validate_scene(ReportList *reports, Scene *scene, Object *fsDomain) { - Base *base; + BaseLegacy *base; Object *newdomain = NULL; int channelObjCount = 0; int fluidInputCount = 0; diff --git a/source/blender/editors/physics/physics_pointcache.c b/source/blender/editors/physics/physics_pointcache.c index e81aa584586..5a2bb1e74c7 100644 --- a/source/blender/editors/physics/physics_pointcache.c +++ b/source/blender/editors/physics/physics_pointcache.c @@ -42,6 +42,7 @@ #include "BKE_context.h" #include "BKE_screen.h" #include "BKE_global.h" +#include "BKE_layer.h" #include "BKE_main.h" #include "BKE_particle.h" #include "BKE_pointcache.h" @@ -253,22 +254,23 @@ static void ptcache_bake_cancel(bContext *C, wmOperator *op) static int ptcache_free_bake_all_exec(bContext *C, wmOperator *UNUSED(op)) { - Scene *scene= CTX_data_scene(C); - Base *base; + Scene *scene = CTX_data_scene(C); PTCacheID *pid; ListBase pidlist; - for (base=scene->base.first; base; base= base->next) { - BKE_ptcache_ids_from_object(&pidlist, base->object, scene, MAX_DUPLI_RECUR); + FOREACH_SCENE_OBJECT(scene, ob) + { + BKE_ptcache_ids_from_object(&pidlist, ob, scene, MAX_DUPLI_RECUR); - for (pid=pidlist.first; pid; pid=pid->next) { + for (pid = pidlist.first; pid; pid = pid->next) { ptcache_free_bake(pid->cache); } BLI_freelistN(&pidlist); - WM_event_add_notifier(C, NC_OBJECT|ND_POINTCACHE, base->object); + WM_event_add_notifier(C, NC_OBJECT|ND_POINTCACHE, ob); } + FOREACH_SCENE_OBJECT_END WM_event_add_notifier(C, NC_SCENE|ND_FRAME, scene); diff --git a/source/blender/editors/physics/rigidbody_constraint.c b/source/blender/editors/physics/rigidbody_constraint.c index 1bfc162a331..b7be31602d9 100644 --- a/source/blender/editors/physics/rigidbody_constraint.c +++ b/source/blender/editors/physics/rigidbody_constraint.c @@ -89,7 +89,7 @@ bool ED_rigidbody_constraint_add(Main *bmain, Scene *scene, Object *ob, int type ob->rigidbody_constraint->flag |= RBC_FLAG_NEEDS_VALIDATE; /* add constraint to rigid body constraint group */ - BKE_group_object_add(rbw->constraints, ob, scene, NULL); + BKE_group_object_add(rbw->constraints, ob); DAG_relations_tag_update(bmain); DAG_id_tag_update(&ob->id, OB_RECALC_OB); @@ -102,7 +102,7 @@ void ED_rigidbody_constraint_remove(Main *bmain, Scene *scene, Object *ob) BKE_rigidbody_remove_constraint(scene, ob); if (rbw) - BKE_group_object_unlink(rbw->constraints, ob, scene, NULL); + BKE_group_object_unlink(rbw->constraints, ob); DAG_relations_tag_update(bmain); DAG_id_tag_update(&ob->id, OB_RECALC_OB); diff --git a/source/blender/editors/physics/rigidbody_object.c b/source/blender/editors/physics/rigidbody_object.c index 30597d95497..c9e32fa5194 100644 --- a/source/blender/editors/physics/rigidbody_object.c +++ b/source/blender/editors/physics/rigidbody_object.c @@ -119,7 +119,7 @@ bool ED_rigidbody_object_add(Main *bmain, Scene *scene, Object *ob, int type, Re ob->rigidbody_object->flag |= RBO_FLAG_NEEDS_VALIDATE; /* add object to rigid body group */ - BKE_group_object_add(rbw->group, ob, scene, NULL); + BKE_group_object_add(rbw->group, ob); DAG_relations_tag_update(bmain); DAG_id_tag_update(&ob->id, OB_RECALC_OB); @@ -133,7 +133,7 @@ void ED_rigidbody_object_remove(Main *bmain, Scene *scene, Object *ob) BKE_rigidbody_remove_object(scene, ob); if (rbw) - BKE_group_object_unlink(rbw->group, ob, scene, NULL); + BKE_group_object_unlink(rbw->group, ob); DAG_relations_tag_update(bmain); DAG_id_tag_update(&ob->id, OB_RECALC_OB); diff --git a/source/blender/editors/render/render_internal.c b/source/blender/editors/render/render_internal.c index 8c5d25ad44d..950214b895a 100644 --- a/source/blender/editors/render/render_internal.c +++ b/source/blender/editors/render/render_internal.c @@ -780,7 +780,7 @@ static void screen_render_cancel(bContext *C, wmOperator *op) WM_jobs_kill_type(wm, scene, WM_JOB_TYPE_RENDER); } -static void clean_viewport_memory(Main *bmain, Scene *scene, int renderlay) +static void clean_viewport_memory(Main *bmain, Scene *scene) { Object *object; Scene *sce_iter; @@ -791,7 +791,7 @@ static void clean_viewport_memory(Main *bmain, Scene *scene, int renderlay) } for (SETLOOPER(scene, sce_iter, base)) { - if ((base->lay & renderlay) == 0) { + if ((base->flag & BASE_VISIBLED) == 0) { continue; } if (RE_allow_render_generic_object(base->object)) { @@ -927,8 +927,6 @@ static int screen_render_invoke(bContext *C, wmOperator *op, const wmEvent *even /* Lock the user interface depending on render settings. */ if (scene->r.use_lock_interface) { - int renderlay = rj->lay_override ? rj->lay_override : scene->lay; - WM_set_locked_interface(CTX_wm_manager(C), true); /* Set flag interface need to be unlocked. @@ -942,7 +940,7 @@ static int screen_render_invoke(bContext *C, wmOperator *op, const wmEvent *even rj->interface_locked = true; /* Clean memory used by viewport? */ - clean_viewport_memory(rj->main, scene, renderlay); + clean_viewport_memory(rj->main, scene); } /* setup job */ diff --git a/source/blender/editors/render/render_preview.c b/source/blender/editors/render/render_preview.c index 87c08dc6583..b4c92ef0f9a 100644 --- a/source/blender/editors/render/render_preview.c +++ b/source/blender/editors/render/render_preview.c @@ -69,6 +69,7 @@ #include "BKE_image.h" #include "BKE_icons.h" #include "BKE_lamp.h" +#include "BKE_layer.h" #include "BKE_library.h" #include "BKE_library_remap.h" #include "BKE_main.h" @@ -94,6 +95,7 @@ #include "ED_datafiles.h" #include "ED_render.h" +#include "ED_screen.h" #ifndef NDEBUG /* Used for database init assert(). */ @@ -275,7 +277,7 @@ static Scene *preview_get_scene(Main *pr_main) static Scene *preview_prepare_scene(Main *bmain, Scene *scene, ID *id, int id_type, ShaderPreview *sp) { Scene *sce; - Base *base; + BaseLegacy *base; Main *pr_main = sp->pr_main; memcpy(pr_main->name, bmain->name, sizeof(pr_main->name)); @@ -357,29 +359,33 @@ static Scene *preview_prepare_scene(Main *bmain, Scene *scene, ID *id, int id_ty /* this only works in a specific case where the preview.blend contains * an object starting with 'c' which has a material linked to it (not the obdata) * and that material has a fake shadow texture in the active texture slot */ - for (base = sce->base.first; base; base = base->next) { - if (base->object->id.name[2] == 'c') { - Material *shadmat = give_current_material(base->object, base->object->actcol); + FOREACH_SCENE_OBJECT(sce, ob) + { + if (ob->id.name[2] == 'c') { + Material *shadmat = give_current_material(ob, ob->actcol); if (shadmat) { if (mat->mode2 & MA_CASTSHADOW) shadmat->septex = 0; else shadmat->septex |= 1; } } } + FOREACH_SCENE_OBJECT_END /* turn off bounce lights for volume, * doesn't make much visual difference and slows it down too */ - for (base = sce->base.first; base; base = base->next) { - if (base->object->type == OB_LAMP) { + FOREACH_SCENE_OBJECT(sce, ob) + { + if (ob->type == OB_LAMP) { /* if doesn't match 'Lamp.002' --> main key light */ - if (!STREQ(base->object->id.name + 2, "Lamp.002")) { + if (!STREQ(ob->id.name + 2, "Lamp.002")) { if (mat->material_type == MA_TYPE_VOLUME) - base->object->restrictflag |= OB_RESTRICT_RENDER; + ob->restrictflag |= OB_RESTRICT_RENDER; else - base->object->restrictflag &= ~OB_RESTRICT_RENDER; + ob->restrictflag &= ~OB_RESTRICT_RENDER; } } } + FOREACH_SCENE_OBJECT_END } else { /* use current scene world to light sphere */ @@ -1022,6 +1028,12 @@ static void icon_preview_startjob(void *customdata, short *stop, short *do_updat *do_update = true; } + else if (idtype == ID_SCR) { + bScreen *screen = (bScreen *)id; + + ED_screen_preview_render(screen, sp->sizex, sp->sizey, sp->pr_rect); + *do_update = true; + } else { /* re-use shader job */ shader_preview_startjob(customdata, stop, do_update); diff --git a/source/blender/editors/render/render_shading.c b/source/blender/editors/render/render_shading.c index 837573ad175..490182b17ed 100644 --- a/source/blender/editors/render/render_shading.c +++ b/source/blender/editors/render/render_shading.c @@ -54,6 +54,7 @@ #include "BKE_font.h" #include "BKE_global.h" #include "BKE_image.h" +#include "BKE_layer.h" #include "BKE_library.h" #include "BKE_linestyle.h" #include "BKE_main.h" @@ -626,11 +627,11 @@ static int render_layer_add_exec(bContext *C, wmOperator *UNUSED(op)) { Scene *scene = CTX_data_scene(C); - BKE_scene_add_render_layer(scene, NULL); - scene->r.actlay = BLI_listbase_count(&scene->r.layers) - 1; + BKE_scene_layer_add(scene, NULL); + scene->active_layer = BLI_listbase_count(&scene->render_layers) - 1; DAG_id_tag_update(&scene->id, 0); - WM_event_add_notifier(C, NC_SCENE | ND_RENDER_OPTIONS, scene); + WM_event_add_notifier(C, NC_SCENE | ND_LAYER, scene); return OPERATOR_FINISHED; } @@ -652,10 +653,11 @@ void SCENE_OT_render_layer_add(wmOperatorType *ot) static int render_layer_remove_exec(bContext *C, wmOperator *UNUSED(op)) { Scene *scene = CTX_data_scene(C); - SceneRenderLayer *rl = BLI_findlink(&scene->r.layers, scene->r.actlay); + SceneLayer *sl = BKE_scene_layer_context_active(scene); - if (!BKE_scene_remove_render_layer(CTX_data_main(C), scene, rl)) + if (!BKE_scene_layer_remove(CTX_data_main(C), scene, sl)) { return OPERATOR_CANCELLED; + } DAG_id_tag_update(&scene->id, 0); WM_event_add_notifier(C, NC_SCENE | ND_RENDER_OPTIONS, scene); diff --git a/source/blender/editors/screen/CMakeLists.txt b/source/blender/editors/screen/CMakeLists.txt index ed86ffa5e16..43e044b613a 100644 --- a/source/blender/editors/screen/CMakeLists.txt +++ b/source/blender/editors/screen/CMakeLists.txt @@ -42,6 +42,7 @@ set(SRC area.c glutil.c screen_context.c + screen_draw.c screen_edit.c screen_ops.c screendump.c diff --git a/source/blender/editors/screen/area.c b/source/blender/editors/screen/area.c index e6bb604d387..46864f6c549 100644 --- a/source/blender/editors/screen/area.c +++ b/source/blender/editors/screen/area.c @@ -57,6 +57,9 @@ #include "ED_screen_types.h" #include "ED_space_api.h" +#include "GPU_immediate.h" +#include "GPU_draw.h" + #include "BIF_gl.h" #include "BIF_glutil.h" #include "BLF_api.h" @@ -71,7 +74,7 @@ #include "screen_intern.h" -extern void ui_draw_anti_tria(float x1, float y1, float x2, float y2, float x3, float y3); /* xxx temp */ +extern void ui_draw_anti_tria(float x1, float y1, float x2, float y2, float x3, float y3, const float color[4]); /* xxx temp */ /* general area and region code */ @@ -89,21 +92,30 @@ static void region_draw_emboss(const ARegion *ar, const rcti *scirct) glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + VertexFormat *format = immVertexFormat(); + unsigned int pos = add_attrib(format, "pos", GL_FLOAT, 2, KEEP_FLOAT); + unsigned int color = add_attrib(format, "color", GL_UNSIGNED_BYTE, 4, NORMALIZE_INT_TO_FLOAT); + + immBindBuiltinProgram(GPU_SHADER_2D_FLAT_COLOR); + immBegin(GL_LINE_STRIP, 5); + /* right */ - glColor4ub(0, 0, 0, 30); - sdrawline(rect.xmax, rect.ymin, rect.xmax, rect.ymax); + immAttrib4ub(color, 0, 0, 0, 30); + immVertex2f(pos, rect.xmax, rect.ymax); + immVertex2f(pos, rect.xmax, rect.ymin); /* bottom */ - glColor4ub(0, 0, 0, 30); - sdrawline(rect.xmin, rect.ymin, rect.xmax, rect.ymin); + immVertex2f(pos, rect.xmin, rect.ymin); - /* top */ - glColor4ub(255, 255, 255, 30); - sdrawline(rect.xmin, rect.ymax, rect.xmax, rect.ymax); - /* left */ - glColor4ub(255, 255, 255, 30); - sdrawline(rect.xmin, rect.ymin, rect.xmin, rect.ymax); + immAttrib4ub(color, 255, 255, 255, 30); + immVertex2f(pos, rect.xmin, rect.ymax); + + /* top */ + immVertex2f(pos, rect.xmax, rect.ymax); + + immEnd(); + immUnbindProgram(); glDisable(GL_BLEND); } @@ -206,15 +218,27 @@ static void area_draw_azone_fullscreen(short x1, short y1, short x2, short y2, f if (G.debug_value == 1) { rcti click_rect; float icon_size = UI_DPI_ICON_SIZE + 7 * UI_DPI_FAC; - char alpha_debug = 255 * alpha; + unsigned char alpha_debug = 255 * alpha; BLI_rcti_init(&click_rect, x, x + icon_size, y, y + icon_size); - glColor4ub(255, 0, 0, alpha_debug); - fdrawbox(click_rect.xmin, click_rect.ymin, click_rect.xmax, click_rect.ymax); - glColor4ub(0, 255, 255, alpha_debug); - fdrawline(click_rect.xmin, click_rect.ymin, click_rect.xmax, click_rect.ymax); - fdrawline(click_rect.xmin, click_rect.ymax, click_rect.xmax, click_rect.ymin); + VertexFormat *format = immVertexFormat(); + unsigned int pos = add_attrib(format, "pos", GL_FLOAT, 2, KEEP_FLOAT); + unsigned int color = add_attrib(format, "color", GL_UNSIGNED_BYTE, 4, NORMALIZE_INT_TO_FLOAT); + + immAttrib4ub(color, 255, 0, 0, alpha_debug); + immBindBuiltinProgram(GPU_SHADER_2D_FLAT_COLOR); + imm_draw_line_box(pos, click_rect.xmin, click_rect.ymin, click_rect.xmax, click_rect.ymax); + + immAttrib4ub(color, 0, 255, 255, alpha_debug); + immBegin(GL_LINES, 4); + immVertex2f(pos, click_rect.xmin, click_rect.ymin); + immVertex2f(pos, click_rect.xmax, click_rect.ymax); + immVertex2f(pos, click_rect.xmin, click_rect.ymax); + immVertex2f(pos, click_rect.xmax, click_rect.ymin); + immEnd(); + + immUnbindProgram(); } } @@ -229,69 +253,96 @@ static void area_draw_azone(short x1, short y1, short x2, short y2) dx = copysign(ceilf(0.3f * abs(dx)), dx); dy = copysign(ceilf(0.3f * abs(dy)), dy); - glEnable(GL_BLEND); glEnable(GL_LINE_SMOOTH); + + VertexFormat *format = immVertexFormat(); + unsigned int pos = add_attrib(format, "pos", GL_FLOAT, 2, KEEP_FLOAT); + unsigned int col = add_attrib(format, "color", GL_UNSIGNED_BYTE, 4, NORMALIZE_INT_TO_FLOAT); + + immBindBuiltinProgram(GPU_SHADER_2D_FLAT_COLOR); + immBegin(GL_LINES, 12); + + immAttrib4ub(col, 255, 255, 255, 180); + immVertex2f(pos, x1, y2); + immVertex2f(pos, x2, y1); + + immAttrib4ub(col, 255, 255, 255, 130); + immVertex2f(pos, x1, y2 - dy); + immVertex2f(pos, x2 - dx, y1); + + immAttrib4ub(col, 255, 255, 255, 80); + immVertex2f(pos, x1, y2 - 2 * dy); + immVertex2f(pos, x2 - 2 * dx, y1); - glColor4ub(255, 255, 255, 180); - fdrawline(x1, y2, x2, y1); - glColor4ub(255, 255, 255, 130); - fdrawline(x1, y2 - dy, x2 - dx, y1); - glColor4ub(255, 255, 255, 80); - fdrawline(x1, y2 - 2 * dy, x2 - 2 * dx, y1); - - glColor4ub(0, 0, 0, 210); - fdrawline(x1, y2 + 1, x2 + 1, y1); - glColor4ub(0, 0, 0, 180); - fdrawline(x1, y2 - dy + 1, x2 - dx + 1, y1); - glColor4ub(0, 0, 0, 150); - fdrawline(x1, y2 - 2 * dy + 1, x2 - 2 * dx + 1, y1); + immAttrib4ub(col, 0, 0, 0, 210); + immVertex2f(pos, x1, y2 + 1); + immVertex2f(pos, x2 + 1, y1); + + immAttrib4ub(col, 0, 0, 0, 180); + immVertex2f(pos, x1, y2 - dy + 1); + immVertex2f(pos, x2 - dx + 1, y1); + + immAttrib4ub(col, 0, 0, 0, 150); + immVertex2f(pos, x1, y2 - 2 * dy + 1); + immVertex2f(pos, x2 - 2 * dx + 1, y1); + + immEnd(); + immUnbindProgram(); glDisable(GL_LINE_SMOOTH); - glDisable(GL_BLEND); } static void region_draw_azone_icon(AZone *az) { - GLUquadricObj *qobj = NULL; - short midx = az->x1 + (az->x2 - az->x1) / 2; - short midy = az->y1 + (az->y2 - az->y1) / 2; - - qobj = gluNewQuadric(); - - glPushMatrix(); - glTranslatef(midx, midy, 0.0); - - /* outlined circle */ - glEnable(GL_LINE_SMOOTH); + float midx = az->x1 + (az->x2 - az->x1) * 0.5f; + float midy = az->y1 + (az->y2 - az->y1) * 0.5f; - glColor4f(1.f, 1.f, 1.f, 0.8f); + VertexFormat *format = immVertexFormat(); + unsigned int pos = add_attrib(format, "pos", GL_FLOAT, 2, KEEP_FLOAT); - gluQuadricDrawStyle(qobj, GLU_FILL); - gluDisk(qobj, 0.0, 4.25f, 16, 1); + /* outlined circle */ + GPU_enable_program_point_size(); /* TODO: make a fixed-size shader to avoid this */ + immBindBuiltinProgram(GPU_SHADER_2D_POINT_UNIFORM_SIZE_UNIFORM_COLOR_OUTLINE_SMOOTH); + immUniform4f("color", 1.0f, 1.0f, 1.0f, 0.8f); + immUniform4f("outlineColor", 0.2f, 0.2f, 0.2f, 0.9f); + immUniform1f("outlineWidth", 1.0f); + immUniform1f("size", 9.5f); + immBegin(GL_POINTS, 1); + immVertex2f(pos, midx, midy); + immEnd(); + immUnbindProgram(); + GPU_disable_program_point_size(); - glColor4f(0.2f, 0.2f, 0.2f, 0.9f); - - gluQuadricDrawStyle(qobj, GLU_SILHOUETTE); - gluDisk(qobj, 0.0, 4.25f, 16, 1); - - glDisable(GL_LINE_SMOOTH); - - glPopMatrix(); - gluDeleteQuadric(qobj); - /* + */ - sdrawline(midx, midy - 2, midx, midy + 3); - sdrawline(midx - 2, midy, midx + 3, midy); + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + immUniform4f("color", 0.2f, 0.2f, 0.2f, 0.9f); + immBegin(GL_LINES, 4); + immVertex2f(pos, midx, midy - 2); + immVertex2f(pos, midx, midy + 3); + immVertex2f(pos, midx - 2, midy); + immVertex2f(pos, midx + 3, midy); + immEnd(); + immUnbindProgram(); } static void draw_azone_plus(float x1, float y1, float x2, float y2) { float width = 0.1f * U.widget_unit; float pad = 0.2f * U.widget_unit; - - glRectf((x1 + x2 - width) * 0.5f, y1 + pad, (x1 + x2 + width) * 0.5f, y2 - pad); - glRectf(x1 + pad, (y1 + y2 - width) * 0.5f, (x1 + x2 - width) * 0.5f, (y1 + y2 + width) * 0.5f); - glRectf((x1 + x2 + width) * 0.5f, (y1 + y2 - width) * 0.5f, x2 - pad, (y1 + y2 + width) * 0.5f); + + VertexFormat *format = immVertexFormat(); + unsigned int pos = add_attrib(format, "pos", GL_FLOAT, 2, KEEP_FLOAT); + + glEnable(GL_BLEND); + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + immUniformColor4f(0.8f, 0.8f, 0.8f, 0.4f); + + immRectf(pos, (x1 + x2 - width) * 0.5f, y1 + pad, (x1 + x2 + width) * 0.5f, y2 - pad); + immRectf(pos, x1 + pad, (y1 + y2 - width) * 0.5f, (x1 + x2 - width) * 0.5f, (y1 + y2 + width) * 0.5f); + immRectf(pos, (x1 + x2 + width) * 0.5f, (y1 + y2 - width) * 0.5f, x2 - pad, (y1 + y2 + width) * 0.5f); + + immUnbindProgram(); + glDisable(GL_BLEND); } static void region_draw_azone_tab_plus(AZone *az) @@ -314,54 +365,45 @@ static void region_draw_azone_tab_plus(AZone *az) break; } - glColor4f(0.05f, 0.05f, 0.05f, 0.4f); - UI_draw_roundbox((float)az->x1, (float)az->y1, (float)az->x2, (float)az->y2, 4.0f); - - glEnable(GL_BLEND); + float color[4] = {0.05f, 0.05f, 0.05f, 0.4f}; + UI_draw_roundbox((float)az->x1, (float)az->y1, (float)az->x2, (float)az->y2, 4.0f, color); - glColor4f(0.8f, 0.8f, 0.8f, 0.4f); draw_azone_plus((float)az->x1, (float)az->y1, (float)az->x2, (float)az->y2); - - glDisable(GL_BLEND); } static void region_draw_azone_tab(AZone *az) { - float col[3]; + float col[4], black[4] = {0.0f, 0.0f, 0.0f, 1.0f}; glEnable(GL_BLEND); UI_GetThemeColor3fv(TH_HEADER, col); - glColor4f(col[0], col[1], col[2], 0.5f); - + col[3] = 0.5f; + /* add code to draw region hidden as 'too small' */ switch (az->edge) { case AE_TOP_TO_BOTTOMRIGHT: UI_draw_roundbox_corner_set(UI_CNR_TOP_LEFT | UI_CNR_TOP_RIGHT | UI_RB_ALPHA); - UI_draw_roundbox_shade_x(GL_POLYGON, (float)az->x1, (float)az->y1, (float)az->x2, (float)az->y2, 4.0f, -0.3f, 0.05f); - glColor4ub(0, 0, 0, 255); - UI_draw_roundbox_unfilled((float)az->x1, 0.3f + (float)az->y1, (float)az->x2, 0.3f + (float)az->y2, 4.0f); + UI_draw_roundbox_shade_x(GL_TRIANGLE_FAN, (float)az->x1, (float)az->y1, (float)az->x2, (float)az->y2, 4.0f, -0.3f, 0.05f, col); + UI_draw_roundbox_unfilled((float)az->x1, 0.3f + (float)az->y1, (float)az->x2, 0.3f + (float)az->y2, 4.0f, black); break; case AE_BOTTOM_TO_TOPLEFT: UI_draw_roundbox_corner_set(UI_CNR_BOTTOM_RIGHT | UI_CNR_BOTTOM_LEFT | UI_RB_ALPHA); - UI_draw_roundbox_shade_x(GL_POLYGON, (float)az->x1, (float)az->y1, (float)az->x2, (float)az->y2, 4.0f, -0.3f, 0.05f); - glColor4ub(0, 0, 0, 255); - UI_draw_roundbox_unfilled((float)az->x1, 0.3f + (float)az->y1, (float)az->x2, 0.3f + (float)az->y2, 4.0f); + UI_draw_roundbox_shade_x(GL_TRIANGLE_FAN, (float)az->x1, (float)az->y1, (float)az->x2, (float)az->y2, 4.0f, -0.3f, 0.05f, col); + UI_draw_roundbox_unfilled((float)az->x1, 0.3f + (float)az->y1, (float)az->x2, 0.3f + (float)az->y2, 4.0f, black); break; case AE_LEFT_TO_TOPRIGHT: UI_draw_roundbox_corner_set(UI_CNR_TOP_LEFT | UI_CNR_BOTTOM_LEFT | UI_RB_ALPHA); - UI_draw_roundbox_shade_x(GL_POLYGON, (float)az->x1, (float)az->y1, (float)az->x2, (float)az->y2, 4.0f, -0.3f, 0.05f); - glColor4ub(0, 0, 0, 255); - UI_draw_roundbox_unfilled((float)az->x1, (float)az->y1, (float)az->x2, (float)az->y2, 4.0f); + UI_draw_roundbox_shade_x(GL_TRIANGLE_FAN, (float)az->x1, (float)az->y1, (float)az->x2, (float)az->y2, 4.0f, -0.3f, 0.05f, col); + UI_draw_roundbox_unfilled((float)az->x1, (float)az->y1, (float)az->x2, (float)az->y2, 4.0f, black); break; case AE_RIGHT_TO_TOPLEFT: UI_draw_roundbox_corner_set(UI_CNR_TOP_RIGHT | UI_CNR_BOTTOM_RIGHT | UI_RB_ALPHA); - UI_draw_roundbox_shade_x(GL_POLYGON, (float)az->x1, (float)az->y1, (float)az->x2, (float)az->y2, 4.0f, -0.3f, 0.05f); - glColor4ub(0, 0, 0, 255); - UI_draw_roundbox_unfilled((float)az->x1, (float)az->y1, (float)az->x2, (float)az->y2, 4.0f); + UI_draw_roundbox_shade_x(GL_TRIANGLE_FAN, (float)az->x1, (float)az->y1, (float)az->x2, (float)az->y2, 4.0f, -0.3f, 0.05f, col); + UI_draw_roundbox_unfilled((float)az->x1, (float)az->y1, (float)az->x2, (float)az->y2, 4.0f, black); break; } @@ -372,24 +414,24 @@ static void region_draw_azone_tria(AZone *az) { glEnable(GL_BLEND); //UI_GetThemeColor3fv(TH_HEADER, col); - glColor4f(0.0f, 0.0f, 0.0f, 0.35f); + float color[4] = {0.0f, 0.0f, 0.0f, 0.35f}; /* add code to draw region hidden as 'too small' */ switch (az->edge) { case AE_TOP_TO_BOTTOMRIGHT: - ui_draw_anti_tria((float)az->x1, (float)az->y1, (float)az->x2, (float)az->y1, (float)(az->x1 + az->x2) / 2, (float)az->y2); + ui_draw_anti_tria((float)az->x1, (float)az->y1, (float)az->x2, (float)az->y1, (float)(az->x1 + az->x2) / 2, (float)az->y2, color); break; case AE_BOTTOM_TO_TOPLEFT: - ui_draw_anti_tria((float)az->x1, (float)az->y2, (float)az->x2, (float)az->y2, (float)(az->x1 + az->x2) / 2, (float)az->y1); + ui_draw_anti_tria((float)az->x1, (float)az->y2, (float)az->x2, (float)az->y2, (float)(az->x1 + az->x2) / 2, (float)az->y1, color); break; case AE_LEFT_TO_TOPRIGHT: - ui_draw_anti_tria((float)az->x2, (float)az->y1, (float)az->x2, (float)az->y2, (float)az->x1, (float)(az->y1 + az->y2) / 2); + ui_draw_anti_tria((float)az->x2, (float)az->y1, (float)az->x2, (float)az->y2, (float)az->x1, (float)(az->y1 + az->y2) / 2, color); break; case AE_RIGHT_TO_TOPLEFT: - ui_draw_anti_tria((float)az->x1, (float)az->y1, (float)az->x1, (float)az->y2, (float)az->x2, (float)(az->y1 + az->y2) / 2); + ui_draw_anti_tria((float)az->x1, (float)az->y1, (float)az->x1, (float)az->y2, (float)az->x2, (float)(az->y1 + az->y2) / 2, color); break; } @@ -511,7 +553,7 @@ void ED_region_do_draw(bContext *C, ARegion *ar) UI_ThemeClearColor(TH_HEADER); glClear(GL_COLOR_BUFFER_BIT); - UI_ThemeColor(TH_TEXT); + UI_FontThemeColor(BLF_default(), TH_TEXT); BLF_draw_default(UI_UNIT_X, 0.4f * UI_UNIT_Y, 0.0f, ar->headerstr, BLF_DRAW_STR_DUMMY_MAX); } else if (at->draw) { @@ -528,9 +570,13 @@ void ED_region_do_draw(bContext *C, ARegion *ar) /* for debugging unneeded area redraws and partial redraw */ #if 0 glEnable(GL_BLEND); - glColor4f(drand48(), drand48(), drand48(), 0.1f); - glRectf(ar->drawrct.xmin - ar->winrct.xmin, ar->drawrct.ymin - ar->winrct.ymin, + VertexFormat *format = immVertexFormat(); + unsigned int pos = add_attrib(format, "pos", GL_FLOAT, 2, KEEP_FLOAT); + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + immUniformColor4f(drand48(), drand48(), drand48(), 0.1f); + immRectf(pos, ar->drawrct.xmin - ar->winrct.xmin, ar->drawrct.ymin - ar->winrct.ymin, ar->drawrct.xmax - ar->winrct.xmin, ar->drawrct.ymax - ar->winrct.ymin); + immUnbindProgram(); glDisable(GL_BLEND); #endif @@ -1968,8 +2014,12 @@ void ED_region_panels(const bContext *C, ARegion *ar, const char *context, int c /* view should be in pixelspace */ UI_view2d_view_restore(C); glEnable(GL_BLEND); - UI_ThemeColor4((ar->type->regionid == RGN_TYPE_PREVIEW) ? TH_PREVIEW_BACK : TH_BACK); - glRecti(0, 0, BLI_rcti_size_x(&ar->winrct), BLI_rcti_size_y(&ar->winrct) + 1); + VertexFormat *format = immVertexFormat(); + unsigned int pos = add_attrib(format, "pos", COMP_I32, 2, CONVERT_INT_TO_FLOAT); + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + immUniformThemeColor((ar->type->regionid == RGN_TYPE_PREVIEW) ? TH_PREVIEW_BACK : TH_BACK); + immRecti(pos, 0, 0, BLI_rcti_size_x(&ar->winrct), BLI_rcti_size_y(&ar->winrct) + 1); + immUnbindProgram(); glDisable(GL_BLEND); } else { @@ -2098,12 +2148,16 @@ void ED_region_info_draw(ARegion *ar, const char *text, float fill_color[4], con glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - glColor4fv(fill_color); - glRecti(rect.xmin, rect.ymin, rect.xmax + 1, rect.ymax + 1); + VertexFormat *format = immVertexFormat(); + unsigned int pos = add_attrib(format, "pos", GL_INT, 2, CONVERT_INT_TO_FLOAT); + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + immUniformColor4fv(fill_color); + immRecti(pos, rect.xmin, rect.ymin, rect.xmax + 1, rect.ymax + 1); + immUnbindProgram(); glDisable(GL_BLEND); /* text */ - UI_ThemeColor(TH_TEXT_HI); + UI_FontThemeColor(fontid, TH_TEXT_HI); BLF_clipping(fontid, rect.xmin, rect.ymin, rect.xmax, rect.ymax); BLF_enable(fontid, BLF_CLIPPING); BLF_position(fontid, rect.xmin + 0.6f * U.widget_unit, rect.ymin + 0.3f * U.widget_unit, 0.0f); @@ -2298,17 +2352,20 @@ void ED_region_image_metadata_draw(int x, int y, ImBuf *ibuf, const rctf *frame, box_y = metadata_box_height_get(ibuf, blf_mono_font, true); if (box_y) { - UI_ThemeColor(TH_METADATA_BG); - /* set up rect */ BLI_rctf_init(&rect, frame->xmin, frame->xmax, frame->ymax, frame->ymax + box_y); /* draw top box */ - glRectf(rect.xmin, rect.ymin, rect.xmax, rect.ymax); + VertexFormat *format = immVertexFormat(); + unsigned int pos = add_attrib(format, "pos", GL_FLOAT, 2, KEEP_FLOAT); + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + immUniformThemeColor(TH_METADATA_BG); + immRectf(pos, rect.xmin, rect.ymin, rect.xmax, rect.ymax); + immUnbindProgram(); BLF_clipping(blf_mono_font, rect.xmin, rect.ymin, rect.xmax, rect.ymax); BLF_enable(blf_mono_font, BLF_CLIPPING); - UI_ThemeColor(TH_METADATA_TEXT); + UI_FontThemeColor(blf_mono_font, TH_METADATA_TEXT); metadata_draw_imbuf(ibuf, &rect, blf_mono_font, true); BLF_disable(blf_mono_font, BLF_CLIPPING); @@ -2320,17 +2377,20 @@ void ED_region_image_metadata_draw(int x, int y, ImBuf *ibuf, const rctf *frame, box_y = metadata_box_height_get(ibuf, blf_mono_font, false); if (box_y) { - UI_ThemeColor(TH_METADATA_BG); - /* set up box rect */ BLI_rctf_init(&rect, frame->xmin, frame->xmax, frame->ymin - box_y, frame->ymin); /* draw top box */ - glRectf(rect.xmin, rect.ymin, rect.xmax, rect.ymax); + VertexFormat *format = immVertexFormat(); + unsigned int pos = add_attrib(format, "pos", GL_FLOAT, 2, KEEP_FLOAT); + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + immUniformThemeColor(TH_METADATA_BG); + immRectf(pos, rect.xmin, rect.ymin, rect.xmax, rect.ymax); + immUnbindProgram(); BLF_clipping(blf_mono_font, rect.xmin, rect.ymin, rect.xmax, rect.ymax); BLF_enable(blf_mono_font, BLF_CLIPPING); - UI_ThemeColor(TH_METADATA_TEXT); + UI_FontThemeColor(blf_mono_font, TH_METADATA_TEXT); metadata_draw_imbuf(ibuf, &rect, blf_mono_font, false); BLF_disable(blf_mono_font, BLF_CLIPPING); @@ -2346,11 +2406,16 @@ void ED_region_grid_draw(ARegion *ar, float zoomx, float zoomy) int x1, y1, x2, y2; /* the image is located inside (0, 0), (1, 1) as set by view2d */ - UI_ThemeColorShade(TH_BACK, 20); - UI_view2d_view_to_region(&ar->v2d, 0.0f, 0.0f, &x1, &y1); UI_view2d_view_to_region(&ar->v2d, 1.0f, 1.0f, &x2, &y2); - glRectf(x1, y1, x2, y2); + + VertexFormat *format = immVertexFormat(); + unsigned int pos = add_attrib(format, "pos", GL_FLOAT, 2, KEEP_FLOAT); + + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + immUniformThemeColorShade(TH_BACK, 20); + immRectf(pos, x1, y1, x2, y2); + immUnbindProgram(); /* gridsize adapted to zoom level */ gridsize = 0.5f * (zoomx + zoomy); @@ -2370,33 +2435,52 @@ void ED_region_grid_draw(ARegion *ar, float zoomx, float zoomy) } } - /* the fine resolution level */ blendfac = 0.25f * gridsize - floorf(0.25f * gridsize); CLAMP(blendfac, 0.0f, 1.0f); - UI_ThemeColorShade(TH_BACK, (int)(20.0f * (1.0f - blendfac))); - fac = 0.0f; - glBegin(GL_LINES); - while (fac < 1.0f) { - glVertex2f(x1, y1 * (1.0f - fac) + y2 * fac); - glVertex2f(x2, y1 * (1.0f - fac) + y2 * fac); - glVertex2f(x1 * (1.0f - fac) + x2 * fac, y1); - glVertex2f(x1 * (1.0f - fac) + x2 * fac, y2); - fac += gridstep; - } + int count_fine = 1.0f / gridstep; + int count_large = 1.0f / (4.0f * gridstep); + + if (count_fine > 0) { + VertexFormat_clear(format); + pos = add_attrib(format, "pos", GL_FLOAT, 2, KEEP_FLOAT); + unsigned color = add_attrib(format, "color", GL_FLOAT, 3, KEEP_FLOAT); + + immBindBuiltinProgram(GPU_SHADER_2D_FLAT_COLOR); + immBegin(GL_LINES, 4 * count_fine + 4 * count_large); + + float theme_color[3]; + UI_GetThemeColorShade3fv(TH_BACK, (int)(20.0f * (1.0f - blendfac)), theme_color); + immAttrib3fv(color, theme_color); + fac = 0.0f; + + /* the fine resolution level */ + for (int i = 0; i < count_fine; i++) { + immVertex2f(pos, x1, y1 * (1.0f - fac) + y2 * fac); + immVertex2f(pos, x2, y1 * (1.0f - fac) + y2 * fac); + immVertex2f(pos, x1 * (1.0f - fac) + x2 * fac, y1); + immVertex2f(pos, x1 * (1.0f - fac) + x2 * fac, y2); + fac += gridstep; + } - /* the large resolution level */ - UI_ThemeColor(TH_BACK); + if (count_large > 0) { + UI_GetThemeColor3fv(TH_BACK, theme_color); + immAttrib3fv(color, theme_color); + fac = 0.0f; + + /* the large resolution level */ + for (int i = 0; i < count_large; i++) { + immVertex2f(pos, x1, y1 * (1.0f - fac) + y2 * fac); + immVertex2f(pos, x2, y1 * (1.0f - fac) + y2 * fac); + immVertex2f(pos, x1 * (1.0f - fac) + x2 * fac, y1); + immVertex2f(pos, x1 * (1.0f - fac) + x2 * fac, y2); + fac += 4.0f * gridstep; + } + } - fac = 0.0f; - while (fac < 1.0f) { - glVertex2f(x1, y1 * (1.0f - fac) + y2 * fac); - glVertex2f(x2, y1 * (1.0f - fac) + y2 * fac); - glVertex2f(x1 * (1.0f - fac) + x2 * fac, y1); - glVertex2f(x1 * (1.0f - fac) + x2 * fac, y2); - fac += 4.0f * gridstep; + immEnd(); + immUnbindProgram(); } - glEnd(); } /* If the area has overlapping regions, it returns visible rect for Region *ar */ @@ -2433,8 +2517,11 @@ void ED_region_visible_rect(ARegion *ar, rcti *rect) void ED_region_cache_draw_background(const ARegion *ar) { - glColor4ub(128, 128, 255, 64); - glRecti(0, 0, ar->winx, 8 * UI_DPI_FAC); + unsigned pos = add_attrib(immVertexFormat(), "pos", COMP_I32, 2, CONVERT_INT_TO_FLOAT); + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + immUniformColor4ub(128, 128, 255, 64); + immRecti(pos, 0, 0, ar->winx, 8 * UI_DPI_FAC); + immUnbindProgram(); } void ED_region_cache_draw_curfra_label(const int framenr, const float x, const float y) @@ -2450,9 +2537,13 @@ void ED_region_cache_draw_curfra_label(const int framenr, const float x, const f BLF_width_and_height(fontid, numstr, sizeof(numstr), &font_dims[0], &font_dims[1]); - glRecti(x, y, x + font_dims[0] + 6.0f, y + font_dims[1] + 4.0f); + unsigned pos = add_attrib(immVertexFormat(), "pos", COMP_I32, 2, CONVERT_INT_TO_FLOAT); + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + immUniformThemeColor(TH_CFRAME); + immRecti(pos, x, y, x + font_dims[0] + 6.0f, y + font_dims[1] + 4.0f); + immUnbindProgram(); - UI_ThemeColor(TH_TEXT); + UI_FontThemeColor(fontid, TH_TEXT); BLF_position(fontid, x + 2.0f, y + 2.0f, 0.0f); BLF_draw(fontid, numstr, sizeof(numstr)); } @@ -2460,17 +2551,18 @@ void ED_region_cache_draw_curfra_label(const int framenr, const float x, const f void ED_region_cache_draw_cached_segments(const ARegion *ar, const int num_segments, const int *points, const int sfra, const int efra) { if (num_segments) { - int a; - - glColor4ub(128, 128, 255, 128); + unsigned pos = add_attrib(immVertexFormat(), "pos", COMP_I32, 2, CONVERT_INT_TO_FLOAT); + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + immUniformColor4ub(128, 128, 255, 128); - for (a = 0; a < num_segments; a++) { - float x1, x2; + for (int a = 0; a < num_segments; a++) { + float x1 = (float)(points[a * 2] - sfra) / (efra - sfra + 1) * ar->winx; + float x2 = (float)(points[a * 2 + 1] - sfra + 1) / (efra - sfra + 1) * ar->winx; - x1 = (float)(points[a * 2] - sfra) / (efra - sfra + 1) * ar->winx; - x2 = (float)(points[a * 2 + 1] - sfra + 1) / (efra - sfra + 1) * ar->winx; - - glRecti(x1, 0, x2, 8 * UI_DPI_FAC); + immRecti(pos, x1, 0, x2, 8 * UI_DPI_FAC); + /* TODO(merwin): use primitive restart to draw multiple rects more efficiently */ } + + immUnbindProgram(); } } diff --git a/source/blender/editors/screen/glutil.c b/source/blender/editors/screen/glutil.c index 93bac3f6660..de24b8ec507 100644 --- a/source/blender/editors/screen/glutil.c +++ b/source/blender/editors/screen/glutil.c @@ -49,46 +49,11 @@ #include "IMB_imbuf_types.h" #include "GPU_basic_shader.h" +#include "GPU_immediate.h" #include "UI_interface.h" -#ifndef GL_CLAMP_TO_EDGE -#define GL_CLAMP_TO_EDGE 0x812F -#endif - -/* UNUSED */ -#if 0 -void fdrawbezier(float vec[4][3]) -{ - float dist; - float curve_res = 24, spline_step = 0.0f; - - dist = 0.5f * fabsf(vec[0][0] - vec[3][0]); - - /* check direction later, for top sockets */ - vec[1][0] = vec[0][0] + dist; - vec[1][1] = vec[0][1]; - - vec[2][0] = vec[3][0] - dist; - vec[2][1] = vec[3][1]; - /* we can reuse the dist variable here to increment the GL curve eval amount */ - dist = 1.0f / curve_res; - - cpack(0x0); - glMap1f(GL_MAP1_VERTEX_3, 0.0, 1.0, 3, 4, vec[0]); - glBegin(GL_LINE_STRIP); - while (spline_step < 1.000001f) { -#if 0 - if (do_shaded) - UI_ThemeColorBlend(th_col1, th_col2, spline_step); -#endif - glEvalCoord1f(spline_step); - spline_step += dist; - } - glEnd(); -} -#endif - +/* DEPRECATED: use imm_draw_line instead */ void fdrawline(float x1, float y1, float x2, float y2) { glBegin(GL_LINES); @@ -99,6 +64,7 @@ void fdrawline(float x1, float y1, float x2, float y2) void fdrawbox(float x1, float y1, float x2, float y2) { + /* DEPRECATED: use imm_draw_line_box instead */ glBegin(GL_LINE_LOOP); glVertex2f(x1, y1); @@ -111,6 +77,7 @@ void fdrawbox(float x1, float y1, float x2, float y2) void fdrawcheckerboard(float x1, float y1, float x2, float y2) { + /* DEPRECATED: use imm_draw_checker_box instead */ unsigned char col1[4] = {40, 40, 40}, col2[4] = {50, 50, 50}; glColor3ubv(col1); @@ -123,7 +90,7 @@ void fdrawcheckerboard(float x1, float y1, float x2, float y2) GPU_basic_shader_bind(GPU_SHADER_USE_COLOR); } -void sdrawline(int x1, int y1, int x2, int y2) +void sdrawline(int x1, int y1, int x2, int y2) /* DEPRECATED */ { glBegin(GL_LINES); glVertex2i(x1, y1); @@ -131,40 +98,9 @@ void sdrawline(int x1, int y1, int x2, int y2) glEnd(); } -/* UNUSED */ -#if 0 -/* - * x1,y2 - * | \ - * | \ - * | \ - * x1,y1-- x2,y1 - */ - -static void sdrawtripoints(int x1, int y1, int x2, int y2) -{ - glVertex2i(x1, y1); - glVertex2i(x1, y2); - glVertex2i(x2, y1); -} - -void sdrawtri(int x1, int y1, int x2, int y2) -{ - glBegin(GL_LINE_STRIP); - sdrawtripoints(x1, y1, x2, y2); - glEnd(); -} - -void sdrawtrifill(int x1, int y1, int x2, int y2) -{ - glBegin(GL_TRIANGLES); - sdrawtripoints(x1, y1, x2, y2); - glEnd(); -} -#endif - void sdrawbox(int x1, int y1, int x2, int y2) { + /* DEPRECATED: use imm_draw_line_box instead */ glBegin(GL_LINE_LOOP); glVertex2i(x1, y1); @@ -204,120 +140,161 @@ void set_inverted_drawing(int enable) GL_TOGGLE(GL_DITHER, !enable); } -/* UNUSED */ -#if 0 -void sdrawXORline(int x0, int y0, int x1, int y1) -{ - if (x0 == x1 && y0 == y1) return; - set_inverted_drawing(1); +void glutil_draw_filled_arc(float start, float angle, float radius, int nsegments) +{ + /* DEPRECATED */ + int i; - glBegin(GL_LINES); - glVertex2i(x0, y0); - glVertex2i(x1, y1); + glBegin(GL_TRIANGLE_FAN); + glVertex2f(0.0, 0.0); + for (i = 0; i < nsegments; i++) { + float t = (float) i / (nsegments - 1); + float cur = start + t * angle; + + glVertex2f(cosf(cur) * radius, sinf(cur) * radius); + } glEnd(); - - set_inverted_drawing(0); } -void sdrawXORline4(int nr, int x0, int y0, int x1, int y1) +void glutil_draw_lined_arc(float start, float angle, float radius, int nsegments) { - static int old[4][2][2]; - static char flags[4] = {0, 0, 0, 0}; + /* DEPRECATED */ + int i; - /* with builtin memory, max 4 lines */ - - set_inverted_drawing(1); + glBegin(GL_LINE_STRIP); + for (i = 0; i < nsegments; i++) { + float t = (float) i / (nsegments - 1); + float cur = start + t * angle; - glBegin(GL_LINES); - if (nr == -1) { /* flush */ - for (nr = 0; nr < 4; nr++) { - if (flags[nr]) { - glVertex2iv(old[nr][0]); - glVertex2iv(old[nr][1]); - flags[nr] = 0; - } - } + glVertex2f(cosf(cur) * radius, sinf(cur) * radius); } - else { - if (nr >= 0 && nr < 4) { - if (flags[nr]) { - glVertex2iv(old[nr][0]); - glVertex2iv(old[nr][1]); - } + glEnd(); +} - old[nr][0][0] = x0; - old[nr][0][1] = y0; - old[nr][1][0] = x1; - old[nr][1][1] = y1; - - flags[nr] = 1; - } - - glVertex2i(x0, y0); - glVertex2i(x1, y1); +static void imm_draw_circle(PrimitiveType prim_type, unsigned pos, float x, float y, float rad, int nsegments) +{ + immBegin(prim_type, nsegments); + for (int i = 0; i < nsegments; ++i) { + float angle = 2 * M_PI * ((float)i / (float)nsegments); + immVertex2f(pos, x + rad * cosf(angle), + y + rad * sinf(angle)); } - glEnd(); - - set_inverted_drawing(0); + immEnd(); } -void fdrawXORellipse(float xofs, float yofs, float hw, float hh) +void imm_draw_lined_circle(unsigned pos, float x, float y, float rad, int nsegments) { - if (hw == 0) return; + imm_draw_circle(PRIM_LINE_LOOP, pos, x, y, rad, nsegments); +} - set_inverted_drawing(1); +void imm_draw_filled_circle(unsigned pos, float x, float y, float rad, int nsegments) +{ + imm_draw_circle(PRIM_TRIANGLE_FAN, pos, x, y, rad, nsegments); +} - glPushMatrix(); - glTranslatef(xofs, yofs, 0.0f); - glScalef(1.0f, hh / hw, 1.0f); - glutil_draw_lined_arc(0.0, M_PI * 2.0, hw, 20); - glPopMatrix(); +void imm_draw_lined_circle_3D(unsigned pos, float x, float y, float rad, int nsegments) +{ + immBegin(PRIM_LINE_LOOP, nsegments); + for (int i = 0; i < nsegments; ++i) { + float angle = 2 * M_PI * ((float)i / (float)nsegments); + immVertex3f(pos, x + rad * cosf(angle), + y + rad * sinf(angle), 0.0f); + } + immEnd(); +} - set_inverted_drawing(0); +void imm_draw_line_box(unsigned pos, float x1, float y1, float x2, float y2) +{ + immBegin(PRIM_LINE_LOOP, 4); + immVertex2f(pos, x1, y1); + immVertex2f(pos, x1, y2); + immVertex2f(pos, x2, y2); + immVertex2f(pos, x2, y1); + immEnd(); } -#endif +void imm_draw_line_box_3D(unsigned pos, float x1, float y1, float x2, float y2) +{ + /* use this version when VertexFormat has a vec3 position */ + immBegin(PRIM_LINE_LOOP, 4); + immVertex3f(pos, x1, y1, 0.0f); + immVertex3f(pos, x1, y2, 0.0f); + immVertex3f(pos, x2, y2, 0.0f); + immVertex3f(pos, x2, y1, 0.0f); + immEnd(); +} -void fdrawXORcirc(float xofs, float yofs, float rad) +void imm_draw_checker_box(float x1, float y1, float x2, float y2) { - set_inverted_drawing(1); + unsigned int pos = add_attrib(immVertexFormat(), "pos", GL_FLOAT, 2, KEEP_FLOAT); + immBindBuiltinProgram(GPU_SHADER_2D_CHECKER); - glPushMatrix(); - glTranslatef(xofs, yofs, 0.0); - glutil_draw_lined_arc(0.0, M_PI * 2.0, rad, 20); - glPopMatrix(); + immUniform4f("color1", 0.15f, 0.15f, 0.15f, 1.0f); + immUniform4f("color2", 0.2f, 0.2f, 0.2f, 1.0f); + immUniform1i("size", 8); - set_inverted_drawing(0); + immRectf(pos, x1, y1, x2, y2); + + immUnbindProgram(); } -void glutil_draw_filled_arc(float start, float angle, float radius, int nsegments) +void imm_cpack(unsigned int x) { - int i; - - glBegin(GL_TRIANGLE_FAN); - glVertex2f(0.0, 0.0); - for (i = 0; i < nsegments; i++) { - float t = (float) i / (nsegments - 1); - float cur = start + t * angle; - - glVertex2f(cosf(cur) * radius, sinf(cur) * radius); - } - glEnd(); + immUniformColor3ub(((x)& 0xFF), + (((x) >> 8) & 0xFF), + (((x) >> 16) & 0xFF)); } -void glutil_draw_lined_arc(float start, float angle, float radius, int nsegments) +void imm_cylinder(unsigned int pos, unsigned int nor, float base, float top, float height, int slices, int stacks) { - int i; - - glBegin(GL_LINE_STRIP); - for (i = 0; i < nsegments; i++) { - float t = (float) i / (nsegments - 1); - float cur = start + t * angle; - - glVertex2f(cosf(cur) * radius, sinf(cur) * radius); + immBegin(GL_TRIANGLES, 6 * slices * stacks); + for (int i = 0; i < slices; ++i) { + const float angle1 = 2 * M_PI * ((float)i / (float)slices); + const float angle2 = 2 * M_PI * ((float)(i+1) / (float)slices); + const float cos1 = cosf(angle1); + const float sin1 = sinf(angle1); + const float cos2 = cosf(angle2); + const float sin2 = sinf(angle2); + + for (int j = 0; j < stacks; ++j) { + float fac1 = (float)j / (float)stacks; + float fac2 = (float)(j+1) / (float)stacks; + float r1 = base * (1.f - fac1) + top * fac1; + float r2 = base * (1.f - fac2) + top * fac2; + float h1 = height * ((float)j / (float)stacks); + float h2 = height * ((float)(j+1) / (float)stacks); + + float v1[3] = {r1 * cos2, r1 * sin2, h1}; + float v2[3] = {r2 * cos2, r2 * sin2, h2}; + float v3[3] = {r2 * cos1, r2 * sin1, h2}; + float v4[3] = {r1 * cos1, r1 * sin1, h1}; + float n1[3], n2[3]; + + /* calc normals */ + sub_v3_v3v3(n1, v2, v1); + normalize_v3(n1); + n1[0] = cos1; n1[1] = sin1; n1[2] = 1-n1[2]; + + sub_v3_v3v3(n2, v3, v4); + normalize_v3(n2); + n2[0] = cos2; n2[1] = sin2; n2[2] = 1-n2[2]; + + /* first tri */ + immAttrib3fv(nor, n2); + immVertex3fv(pos, v1); + immVertex3fv(pos, v2); + immAttrib3fv(nor, n1); + immVertex3fv(pos, v3); + + /* second tri */ + immVertex3fv(pos, v3); + immVertex3fv(pos, v4); + immAttrib3fv(nor, n2); + immVertex3fv(pos, v1); + } } - glEnd(); + immEnd(); } float glaGetOneFloat(int param) @@ -375,6 +352,7 @@ static int get_cached_work_texture(int *r_w, int *r_h) return texid; } +/* DEPRECATED: use immDrawPixelsTexScaled_clipping instead */ void glaDrawPixelsTexScaled_clipping(float x, float y, int img_w, int img_h, int format, int type, int zoomfilter, void *rect, float scaleX, float scaleY, @@ -401,12 +379,6 @@ void glaDrawPixelsTexScaled_clipping(float x, float y, int img_w, int img_h, glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, zoomfilter); -#if defined(__APPLE__) && 0 - /* [merwin] disable this workaround and see if anyone is affected. If not scrap it! Also at end of this function */ - /* workaround for os x 10.5/10.6 driver bug: http://lists.apple.com/archives/Mac-opengl/2008/Jul/msg00117.html */ - glPixelZoom(1.0f, 1.0f); -#endif - /* setup seamless 2=on, 0=off */ seamless = ((tex_w < img_w || tex_h < img_h) && tex_w > 2 && tex_h > 2) ? 2 : 0; @@ -514,13 +486,9 @@ void glaDrawPixelsTexScaled_clipping(float x, float y, int img_w, int img_h, glBindTexture(GL_TEXTURE_2D, 0); glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); - -#if defined(__APPLE__) && 0 - /* workaround for os x 10.5/10.6 driver bug (above) */ - glPixelZoom(xzoom, yzoom); -#endif } +/* DEPRECATED: use immDrawPixelsTexScaled instead */ void glaDrawPixelsTexScaled(float x, float y, int img_w, int img_h, int format, int type, int zoomfilter, void *rect, float scaleX, float scaleY) @@ -529,12 +497,14 @@ void glaDrawPixelsTexScaled(float x, float y, int img_w, int img_h, scaleX, scaleY, 0.0f, 0.0f, 0.0f, 0.0f); } +/* DEPRECATED: use immDrawPixelsTex instead */ void glaDrawPixelsTex(float x, float y, int img_w, int img_h, int format, int type, int zoomfilter, void *rect) { glaDrawPixelsTexScaled_clipping(x, y, img_w, img_h, format, type, zoomfilter, rect, 1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f); } +/* DEPRECATED: use immDrawPixelsTex_clipping instead */ void glaDrawPixelsTex_clipping(float x, float y, int img_w, int img_h, int format, int type, int zoomfilter, void *rect, float clip_min_x, float clip_min_y, float clip_max_x, float clip_max_y) @@ -648,6 +618,176 @@ void glaDrawPixelsAuto(float x, float y, int img_w, int img_h, int format, int t 0.0f, 0.0f, 0.0f, 0.0f); } +/* TODO this is utterly slow and need some love + * but in the meantime it's not using deprecated api */ +void immDrawPixelsTexScaled_clipping(float x, float y, int img_w, int img_h, + int format, int type, int zoomfilter, void *rect, + float scaleX, float scaleY, + float clip_min_x, float clip_min_y, + float clip_max_x, float clip_max_y, + float xzoom, float yzoom, float color[4]) +{ + unsigned char *uc_rect = (unsigned char *) rect; + const float *f_rect = (float *)rect; + int subpart_x, subpart_y, tex_w, tex_h; + int seamless, offset_x, offset_y, nsubparts_x, nsubparts_y; + int texid = get_cached_work_texture(&tex_w, &tex_h); + int components; + const bool use_clipping = ((clip_min_x < clip_max_x) && (clip_min_y < clip_max_y)); + + /* Specify the color outside this function, and tex will modulate it. + * This is useful for changing alpha without using glPixelTransferf() + */ + glPixelStorei(GL_UNPACK_ROW_LENGTH, img_w); + glBindTexture(GL_TEXTURE_2D, texid); + + /* don't want nasty border artifacts */ + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, zoomfilter); + + /* setup seamless 2=on, 0=off */ + seamless = ((tex_w < img_w || tex_h < img_h) && tex_w > 2 && tex_h > 2) ? 2 : 0; + + offset_x = tex_w - seamless; + offset_y = tex_h - seamless; + + nsubparts_x = (img_w + (offset_x - 1)) / (offset_x); + nsubparts_y = (img_h + (offset_y - 1)) / (offset_y); + + if (format == GL_RGBA) + components = 4; + else if (format == GL_RGB) + components = 3; + else if (format == GL_RED) + components = 1; + else { + BLI_assert(!"Incompatible format passed to glaDrawPixelsTexScaled"); + return; + } + + if (type == GL_FLOAT) { + /* need to set internal format to higher range float */ + + /* NOTE: this could fail on some drivers, like mesa, + * but currently this code is only used by color + * management stuff which already checks on whether + * it's possible to use GL_RGBA16F_ARB + */ + + /* TODO viewport : remove extension */ + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F_ARB, tex_w, tex_h, 0, format, GL_FLOAT, NULL); + } + else { + /* switch to 8bit RGBA for byte buffer */ + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, tex_w, tex_h, 0, format, GL_UNSIGNED_BYTE, NULL); + } + + VertexFormat *vert_format = immVertexFormat(); + unsigned int pos = add_attrib(vert_format, "pos", GL_FLOAT, 2, KEEP_FLOAT); + unsigned int texco = add_attrib(vert_format, "texCoord", GL_FLOAT, 2, KEEP_FLOAT); + + immBindBuiltinProgram(GPU_SHADER_2D_IMAGE_COLOR); + immUniform4fv("color", color); + immUniform1i("image", 0); + + for (subpart_y = 0; subpart_y < nsubparts_y; subpart_y++) { + for (subpart_x = 0; subpart_x < nsubparts_x; subpart_x++) { + int remainder_x = img_w - subpart_x * offset_x; + int remainder_y = img_h - subpart_y * offset_y; + int subpart_w = (remainder_x < tex_w) ? remainder_x : tex_w; + int subpart_h = (remainder_y < tex_h) ? remainder_y : tex_h; + int offset_left = (seamless && subpart_x != 0) ? 1 : 0; + int offset_bot = (seamless && subpart_y != 0) ? 1 : 0; + int offset_right = (seamless && remainder_x > tex_w) ? 1 : 0; + int offset_top = (seamless && remainder_y > tex_h) ? 1 : 0; + float rast_x = x + subpart_x * offset_x * xzoom; + float rast_y = y + subpart_y * offset_y * yzoom; + /* check if we already got these because we always get 2 more when doing seamless */ + if (subpart_w <= seamless || subpart_h <= seamless) + continue; + + if (use_clipping) { + if (rast_x + (float)(subpart_w - offset_right) * xzoom * scaleX < clip_min_x || + rast_y + (float)(subpart_h - offset_top) * yzoom * scaleY < clip_min_y) + { + continue; + } + if (rast_x + (float)offset_left * xzoom > clip_max_x || + rast_y + (float)offset_bot * yzoom > clip_max_y) + { + continue; + } + } + + if (type == GL_FLOAT) { + glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, subpart_w, subpart_h, format, GL_FLOAT, &f_rect[((size_t)subpart_y) * offset_y * img_w * components + subpart_x * offset_x * components]); + + /* add an extra border of pixels so linear looks ok at edges of full image */ + if (subpart_w < tex_w) + glTexSubImage2D(GL_TEXTURE_2D, 0, subpart_w, 0, 1, subpart_h, format, GL_FLOAT, &f_rect[((size_t)subpart_y) * offset_y * img_w * components + (subpart_x * offset_x + subpart_w - 1) * components]); + if (subpart_h < tex_h) + glTexSubImage2D(GL_TEXTURE_2D, 0, 0, subpart_h, subpart_w, 1, format, GL_FLOAT, &f_rect[(((size_t)subpart_y) * offset_y + subpart_h - 1) * img_w * components + subpart_x * offset_x * components]); + if (subpart_w < tex_w && subpart_h < tex_h) + glTexSubImage2D(GL_TEXTURE_2D, 0, subpart_w, subpart_h, 1, 1, format, GL_FLOAT, &f_rect[(((size_t)subpart_y) * offset_y + subpart_h - 1) * img_w * components + (subpart_x * offset_x + subpart_w - 1) * components]); + } + else { + glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, subpart_w, subpart_h, format, GL_UNSIGNED_BYTE, &uc_rect[((size_t)subpart_y) * offset_y * img_w * components + subpart_x * offset_x * components]); + + if (subpart_w < tex_w) + glTexSubImage2D(GL_TEXTURE_2D, 0, subpart_w, 0, 1, subpart_h, format, GL_UNSIGNED_BYTE, &uc_rect[((size_t)subpart_y) * offset_y * img_w * components + (subpart_x * offset_x + subpart_w - 1) * components]); + if (subpart_h < tex_h) + glTexSubImage2D(GL_TEXTURE_2D, 0, 0, subpart_h, subpart_w, 1, format, GL_UNSIGNED_BYTE, &uc_rect[(((size_t)subpart_y) * offset_y + subpart_h - 1) * img_w * components + subpart_x * offset_x * components]); + if (subpart_w < tex_w && subpart_h < tex_h) + glTexSubImage2D(GL_TEXTURE_2D, 0, subpart_w, subpart_h, 1, 1, format, GL_UNSIGNED_BYTE, &uc_rect[(((size_t)subpart_y) * offset_y + subpart_h - 1) * img_w * components + (subpart_x * offset_x + subpart_w - 1) * components]); + } + + immBegin(GL_TRIANGLE_FAN, 4); + immAttrib2f(texco, (float)(0 + offset_left) / tex_w, (float)(0 + offset_bot) / tex_h); + immVertex2f(pos, rast_x + (float)offset_left * xzoom, rast_y + (float)offset_bot * yzoom); + + immAttrib2f(texco, (float)(subpart_w - offset_right) / tex_w, (float)(0 + offset_bot) / tex_h); + immVertex2f(pos, rast_x + (float)(subpart_w - offset_right) * xzoom * scaleX, rast_y + (float)offset_bot * yzoom); + + immAttrib2f(texco, (float)(subpart_w - offset_right) / tex_w, (float)(subpart_h - offset_top) / tex_h); + immVertex2f(pos, rast_x + (float)(subpart_w - offset_right) * xzoom * scaleX, rast_y + (float)(subpart_h - offset_top) * yzoom * scaleY); + + immAttrib2f(texco, (float)(0 + offset_left) / tex_w, (float)(subpart_h - offset_top) / tex_h); + immVertex2f(pos, rast_x + (float)offset_left * xzoom, rast_y + (float)(subpart_h - offset_top) * yzoom * scaleY); + immEnd(); + } + } + + immUnbindProgram(); + + glBindTexture(GL_TEXTURE_2D, 0); + glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); +} + +void immDrawPixelsTexScaled(float x, float y, int img_w, int img_h, + int format, int type, int zoomfilter, void *rect, + float scaleX, float scaleY, float xzoom, float yzoom, float color[4]) +{ + immDrawPixelsTexScaled_clipping(x, y, img_w, img_h, format, type, zoomfilter, rect, + scaleX, scaleY, 0.0f, 0.0f, 0.0f, 0.0f, xzoom, yzoom, color); +} + +void immDrawPixelsTex(float x, float y, int img_w, int img_h, int format, int type, int zoomfilter, void *rect, + float xzoom, float yzoom, float color[4]) +{ + immDrawPixelsTexScaled_clipping(x, y, img_w, img_h, format, type, zoomfilter, rect, 1.0f, 1.0f, + 0.0f, 0.0f, 0.0f, 0.0f, xzoom, yzoom, color); +} + +void immDrawPixelsTex_clipping(float x, float y, int img_w, int img_h, + int format, int type, int zoomfilter, void *rect, + float clip_min_x, float clip_min_y, float clip_max_x, float clip_max_y, + float xzoom, float yzoom, float color[4]) +{ + immDrawPixelsTexScaled_clipping(x, y, img_w, img_h, format, type, zoomfilter, rect, 1.0f, 1.0f, + clip_min_x, clip_min_y, clip_max_x, clip_max_y, xzoom, yzoom, color); +} + /* 2D Drawing Assistance */ void glaDefine2DArea(rcti *screen_rect) @@ -673,6 +813,8 @@ void glaDefine2DArea(rcti *screen_rect) glLoadIdentity(); } +/* TODO(merwin): put the following 2D code to use, or build new 2D code inspired & informd by it */ + #if 0 /* UNUSED */ struct gla2DDrawInfo { @@ -785,7 +927,8 @@ void glaEnd2DDraw(gla2DDrawInfo *di) MEM_freeN(di); } -#endif + +#endif /* UNUSED */ /* Uses current OpenGL state to get view matrices for gluProject/gluUnProject */ @@ -999,6 +1142,7 @@ void glaDrawImBuf_glsl_ctx(const bContext *C, ImBuf *ibuf, float x, float y, int void cpack(unsigned int x) { + /* DEPRECATED: use imm_cpack */ glColor3ub(( (x) & 0xFF), (((x) >> 8) & 0xFF), (((x) >> 16) & 0xFF)); diff --git a/source/blender/editors/screen/screen_context.c b/source/blender/editors/screen/screen_context.c index c165bbfd301..0448fba78e6 100644 --- a/source/blender/editors/screen/screen_context.c +++ b/source/blender/editors/screen/screen_context.c @@ -47,6 +47,7 @@ #include "BKE_action.h" #include "BKE_armature.h" #include "BKE_gpencil.h" +#include "BKE_layer.h" #include "BKE_screen.h" #include "BKE_sequencer.h" @@ -60,20 +61,8 @@ #include "screen_intern.h" -static unsigned int context_layers(bScreen *sc, Scene *scene, ScrArea *sa_ctx) -{ - /* needed for 'USE_ALLSELECT' define, otherwise we end up editing off-screen layers. */ - if (sc && sa_ctx && (sa_ctx->spacetype == SPACE_BUTS)) { - const unsigned int lay = BKE_screen_view3d_layer_all(sc); - if (lay) { - return lay; - } - } - return scene->lay; -} - const char *screen_context_dir[] = { - "scene", "visible_objects", "visible_bases", "selectable_objects", "selectable_bases", + "scene", "render_layer", "visible_objects", "visible_bases", "selectable_objects", "selectable_bases", "selected_objects", "selected_bases", "editable_objects", "editable_bases", "selected_editable_objects", "selected_editable_bases", @@ -95,17 +84,9 @@ int ed_screen_context(const bContext *C, const char *member, bContextDataResult bScreen *sc = CTX_wm_screen(C); ScrArea *sa = CTX_wm_area(C); Scene *scene = sc->scene; - Base *base; - -#if 0 /* Using the context breaks adding objects in the UI. Need to find out why - campbell */ - Object *obact = CTX_data_active_object(C); - Object *obedit = CTX_data_edit_object(C); - base = CTX_data_active_base(C); -#else + SceneLayer *sl = CTX_data_scene_layer(C); Object *obedit = scene->obedit; - Object *obact = OBACT; - base = BASACT; -#endif + Object *obact = sl->basact ? sl->basact->object : NULL; if (CTX_data_dir(member)) { CTX_data_dir_set(result, screen_context_dir); @@ -115,84 +96,100 @@ int ed_screen_context(const bContext *C, const char *member, bContextDataResult CTX_data_id_pointer_set(result, &scene->id); return 1; } - else if (CTX_data_equals(member, "visible_objects") || CTX_data_equals(member, "visible_bases")) { - const unsigned int lay = context_layers(sc, scene, sa); - const bool visible_objects = CTX_data_equals(member, "visible_objects"); - - for (base = scene->base.first; base; base = base->next) { - if (((base->object->restrictflag & OB_RESTRICT_VIEW) == 0) && (base->lay & lay)) { - if (visible_objects) - CTX_data_id_list_add(result, &base->object->id); - else - CTX_data_list_add(result, &scene->id, &RNA_ObjectBase, base); + else if (CTX_data_equals(member, "visible_objects")) { + FOREACH_VISIBLE_OBJECT(sl, ob) + { + CTX_data_id_list_add(result, &ob->id); + } + FOREACH_VISIBLE_BASE_END + CTX_data_type_set(result, CTX_DATA_TYPE_COLLECTION); + return 1; + } + else if (CTX_data_equals(member, "selectable_objects")) { + for (Base *base = sl->object_bases.first; base; base = base->next) { + if (((base->flag & BASE_VISIBLED) != 0) && ((base->flag & BASE_SELECTABLED) != 0)) { + CTX_data_id_list_add(result, &base->object->id); } } CTX_data_type_set(result, CTX_DATA_TYPE_COLLECTION); return 1; } - else if (CTX_data_equals(member, "selectable_objects") || CTX_data_equals(member, "selectable_bases")) { - const unsigned int lay = context_layers(sc, scene, sa); - const bool selectable_objects = CTX_data_equals(member, "selectable_objects"); - - for (base = scene->base.first; base; base = base->next) { - if (base->lay & lay) { - if ((base->object->restrictflag & OB_RESTRICT_VIEW) == 0 && (base->object->restrictflag & OB_RESTRICT_SELECT) == 0) { - if (selectable_objects) - CTX_data_id_list_add(result, &base->object->id); - else - CTX_data_list_add(result, &scene->id, &RNA_ObjectBase, base); - } + else if (CTX_data_equals(member, "selected_objects")) { + FOREACH_SELECTED_OBJECT(sl, ob) + { + CTX_data_id_list_add(result, &ob->id); + } + FOREACH_SELECTED_OBJECT_END + CTX_data_type_set(result, CTX_DATA_TYPE_COLLECTION); + return 1; + } + else if (CTX_data_equals(member, "selected_editable_objects")) { + FOREACH_SELECTED_OBJECT(sl, ob) + { + if (0 == BKE_object_is_libdata(ob)) { + CTX_data_id_list_add(result, &ob->id); } } + FOREACH_SELECTED_OBJECT_END CTX_data_type_set(result, CTX_DATA_TYPE_COLLECTION); return 1; } - else if (CTX_data_equals(member, "selected_objects") || CTX_data_equals(member, "selected_bases")) { - const unsigned int lay = context_layers(sc, scene, sa); - const bool selected_objects = CTX_data_equals(member, "selected_objects"); - - for (base = scene->base.first; base; base = base->next) { - if ((base->flag & SELECT) && (base->lay & lay)) { - if (selected_objects) - CTX_data_id_list_add(result, &base->object->id); - else - CTX_data_list_add(result, &scene->id, &RNA_ObjectBase, base); + else if (CTX_data_equals(member, "editable_objects")) { + /* Visible + Editable, but not necessarily selected */ + FOREACH_VISIBLE_OBJECT(sl, ob) + { + if (0 == BKE_object_is_libdata(ob)) { + CTX_data_id_list_add(result, &ob->id); } } + FOREACH_VISIBLE_OBJECT_END CTX_data_type_set(result, CTX_DATA_TYPE_COLLECTION); return 1; } - else if (CTX_data_equals(member, "selected_editable_objects") || CTX_data_equals(member, "selected_editable_bases")) { - const unsigned int lay = context_layers(sc, scene, sa); - const bool selected_editable_objects = CTX_data_equals(member, "selected_editable_objects"); - - for (base = scene->base.first; base; base = base->next) { - if ((base->flag & SELECT) && (base->lay & lay)) { - if ((base->object->restrictflag & OB_RESTRICT_VIEW) == 0) { - if (0 == BKE_object_is_libdata(base->object)) { - if (selected_editable_objects) - CTX_data_id_list_add(result, &base->object->id); - else - CTX_data_list_add(result, &scene->id, &RNA_ObjectBase, base); - } + else if ( CTX_data_equals(member, "visible_bases")) { + FOREACH_VISIBLE_BASE(sl, base) + { + CTX_data_list_add(result, &scene->id, &RNA_ObjectBase, base); + } + FOREACH_VISIBLE_BASE_END + CTX_data_type_set(result, CTX_DATA_TYPE_COLLECTION); + return 1; + } + else if (CTX_data_equals(member, "selectable_bases")) { + for (Base *base = sl->object_bases.first; base; base = base->next) { + if ((base->flag & BASE_SELECTABLED) != 0) { + CTX_data_list_add(result, &scene->id, &RNA_ObjectBase, base); + } + } + CTX_data_type_set(result, CTX_DATA_TYPE_COLLECTION); + return 1; + } + else if (CTX_data_equals(member, "selected_bases")) { + for (Base *base = sl->object_bases.first; base; base = base->next) { + if ((base->flag & BASE_SELECTED) != 0) { + CTX_data_list_add(result, &scene->id, &RNA_ObjectBase, base); + } + } + CTX_data_type_set(result, CTX_DATA_TYPE_COLLECTION); + return 1; + } + else if (CTX_data_equals(member, "selected_editable_bases")) { + for (Base *base = sl->object_bases.first; base; base = base->next) { + if ((base->flag & BASE_SELECTED) != 0) { + if (0 == BKE_object_is_libdata(base->object)) { + CTX_data_list_add(result, &scene->id, &RNA_ObjectBase, base); } } } CTX_data_type_set(result, CTX_DATA_TYPE_COLLECTION); return 1; } - else if (CTX_data_equals(member, "editable_objects") || CTX_data_equals(member, "editable_bases")) { - const unsigned int lay = context_layers(sc, scene, sa); - const bool editable_objects = CTX_data_equals(member, "editable_objects"); - + else if (CTX_data_equals(member, "editable_bases")) { /* Visible + Editable, but not necessarily selected */ - for (base = scene->base.first; base; base = base->next) { - if (((base->object->restrictflag & OB_RESTRICT_VIEW) == 0) && (base->lay & lay)) { + for (Base *base = sl->object_bases.first; base; base = base->next) { + if ((base->flag & BASE_VISIBLED) != 0) { if (0 == BKE_object_is_libdata(base->object)) { - if (editable_objects) - CTX_data_id_list_add(result, &base->object->id); - else - CTX_data_list_add(result, &scene->id, &RNA_ObjectBase, base); + CTX_data_list_add(result, &scene->id, &RNA_ObjectBase, base); } } } @@ -344,8 +341,8 @@ int ed_screen_context(const bContext *C, const char *member, bContextDataResult } } else if (CTX_data_equals(member, "active_base")) { - if (base) - CTX_data_pointer_set(result, &scene->id, &RNA_ObjectBase, base); + if (sl->basact) + CTX_data_pointer_set(result, &scene->id, &RNA_ObjectBase, sl->basact); return 1; } diff --git a/source/blender/editors/screen/screen_draw.c b/source/blender/editors/screen/screen_draw.c new file mode 100644 index 00000000000..7ba3c4b82b7 --- /dev/null +++ b/source/blender/editors/screen/screen_draw.c @@ -0,0 +1,486 @@ +/* + * ***** 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. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/editors/screen/screen_draw.c + * \ingroup edscr + */ + +#include "ED_screen.h" + +#include "GPU_framebuffer.h" +#include "GPU_immediate.h" + +#include "WM_api.h" +#include "WM_types.h" + +#include "screen_intern.h" + + +/** + * Draw horizontal shape visualizing future joining (left as well right direction of future joining). + */ +static void draw_horizontal_join_shape(ScrArea *sa, char dir, unsigned int pos) +{ + vec2f points[10]; + short i; + float w, h; + float width = sa->v3->vec.x - sa->v1->vec.x; + float height = sa->v3->vec.y - sa->v1->vec.y; + + if (height < width) { + h = height / 8; + w = height / 4; + } + else { + h = width / 8; + w = width / 4; + } + + points[0].x = sa->v1->vec.x; + points[0].y = sa->v1->vec.y + height / 2; + + points[1].x = sa->v1->vec.x; + points[1].y = sa->v1->vec.y; + + points[2].x = sa->v4->vec.x - w; + points[2].y = sa->v4->vec.y; + + points[3].x = sa->v4->vec.x - w; + points[3].y = sa->v4->vec.y + height / 2 - 2 * h; + + points[4].x = sa->v4->vec.x - 2 * w; + points[4].y = sa->v4->vec.y + height / 2; + + points[5].x = sa->v4->vec.x - w; + points[5].y = sa->v4->vec.y + height / 2 + 2 * h; + + points[6].x = sa->v3->vec.x - w; + points[6].y = sa->v3->vec.y; + + points[7].x = sa->v2->vec.x; + points[7].y = sa->v2->vec.y; + + points[8].x = sa->v4->vec.x; + points[8].y = sa->v4->vec.y + height / 2 - h; + + points[9].x = sa->v4->vec.x; + points[9].y = sa->v4->vec.y + height / 2 + h; + + if (dir == 'l') { + /* when direction is left, then we flip direction of arrow */ + float cx = sa->v1->vec.x + width; + for (i = 0; i < 10; i++) { + points[i].x -= cx; + points[i].x = -points[i].x; + points[i].x += sa->v1->vec.x; + } + } + + immBegin(GL_TRIANGLE_FAN, 5); + + for (i = 0; i < 5; i++) { + immVertex2f(pos, points[i].x, points[i].y); + } + + immEnd(); + + immBegin(GL_TRIANGLE_FAN, 5); + + for (i = 4; i < 8; i++) { + immVertex2f(pos, points[i].x, points[i].y); + } + + immVertex2f(pos, points[0].x, points[0].y); + immEnd(); + + immRectf(pos, points[2].x, points[2].y, points[8].x, points[8].y); + immRectf(pos, points[6].x, points[6].y, points[9].x, points[9].y); +} + +/** + * Draw vertical shape visualizing future joining (up/down direction). + */ +static void draw_vertical_join_shape(ScrArea *sa, char dir, unsigned int pos) +{ + vec2f points[10]; + short i; + float w, h; + float width = sa->v3->vec.x - sa->v1->vec.x; + float height = sa->v3->vec.y - sa->v1->vec.y; + + if (height < width) { + h = height / 4; + w = height / 8; + } + else { + h = width / 4; + w = width / 8; + } + + points[0].x = sa->v1->vec.x + width / 2; + points[0].y = sa->v3->vec.y; + + points[1].x = sa->v2->vec.x; + points[1].y = sa->v2->vec.y; + + points[2].x = sa->v1->vec.x; + points[2].y = sa->v1->vec.y + h; + + points[3].x = sa->v1->vec.x + width / 2 - 2 * w; + points[3].y = sa->v1->vec.y + h; + + points[4].x = sa->v1->vec.x + width / 2; + points[4].y = sa->v1->vec.y + 2 * h; + + points[5].x = sa->v1->vec.x + width / 2 + 2 * w; + points[5].y = sa->v1->vec.y + h; + + points[6].x = sa->v4->vec.x; + points[6].y = sa->v4->vec.y + h; + + points[7].x = sa->v3->vec.x; + points[7].y = sa->v3->vec.y; + + points[8].x = sa->v1->vec.x + width / 2 - w; + points[8].y = sa->v1->vec.y; + + points[9].x = sa->v1->vec.x + width / 2 + w; + points[9].y = sa->v1->vec.y; + + if (dir == 'u') { + /* when direction is up, then we flip direction of arrow */ + float cy = sa->v1->vec.y + height; + for (i = 0; i < 10; i++) { + points[i].y -= cy; + points[i].y = -points[i].y; + points[i].y += sa->v1->vec.y; + } + } + + immBegin(GL_TRIANGLE_FAN, 5); + + for (i = 0; i < 5; i++) { + immVertex2f(pos, points[i].x, points[i].y); + } + + immEnd(); + + immBegin(GL_TRIANGLE_FAN, 5); + + for (i = 4; i < 8; i++) { + immVertex2f(pos, points[i].x, points[i].y); + } + + immVertex2f(pos, points[0].x, points[0].y); + immEnd(); + + immRectf(pos, points[2].x, points[2].y, points[8].x, points[8].y); + immRectf(pos, points[6].x, points[6].y, points[9].x, points[9].y); +} + +/** + * Draw join shape due to direction of joining. + */ +static void draw_join_shape(ScrArea *sa, char dir, unsigned int pos) +{ + if (dir == 'u' || dir == 'd') { + draw_vertical_join_shape(sa, dir, pos); + } + else { + draw_horizontal_join_shape(sa, dir, pos); + } +} + +/** + * Draw screen area darker with arrow (visualization of future joining). + */ +static void scrarea_draw_shape_dark(ScrArea *sa, char dir, unsigned int pos) +{ + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + immUniformColor4ub(0, 0, 0, 50); + + draw_join_shape(sa, dir, pos); +} + +/** + * Draw screen area ligher with arrow shape ("eraser" of previous dark shape). + */ +static void scrarea_draw_shape_light(ScrArea *sa, char UNUSED(dir), unsigned int pos) +{ + glBlendFunc(GL_DST_COLOR, GL_SRC_ALPHA); + /* value 181 was hardly computed: 181~105 */ + immUniformColor4ub(255, 255, 255, 50); + /* draw_join_shape(sa, dir); */ + + immRectf(pos, sa->v1->vec.x, sa->v1->vec.y, sa->v3->vec.x, sa->v3->vec.y); +} + +static void drawscredge_area_draw(int sizex, int sizey, short x1, short y1, short x2, short y2, unsigned int pos) +{ + int count = 0; + + if (x2 < sizex - 1) count += 2; + if (x1 > 0) count += 2; + if (y2 < sizey - 1) count += 2; + if (y1 > 0) count += 2; + + immBegin(GL_LINES, count); + + /* right border area */ + if (x2 < sizex - 1) { + immVertex2f(pos, x2, y1); + immVertex2f(pos, x2, y2); + } + + /* left border area */ + if (x1 > 0) { /* otherwise it draws the emboss of window over */ + immVertex2f(pos, x1, y1); + immVertex2f(pos, x1, y2); + } + + /* top border area */ + if (y2 < sizey - 1) { + immVertex2f(pos, x1, y2); + immVertex2f(pos, x2, y2); + } + + /* bottom border area */ + if (y1 > 0) { + immVertex2f(pos, x1, y1); + immVertex2f(pos, x2, y1); + } + + immEnd(); +} + +/** + * \brief Screen edges drawing. + */ +static void drawscredge_area(ScrArea *sa, int sizex, int sizey, unsigned int pos) +{ + short x1 = sa->v1->vec.x; + short y1 = sa->v1->vec.y; + short x2 = sa->v3->vec.x; + short y2 = sa->v3->vec.y; + + drawscredge_area_draw(sizex, sizey, x1, y1, x2, y2, pos); +} + +/** + * Only for edge lines between areas, and the blended join arrows. + */ +void ED_screen_draw(wmWindow *win) +{ + const int winsize_x = WM_window_pixels_x(win); + const int winsize_y = WM_window_pixels_y(win); + + ScrArea *sa; + ScrArea *sa1 = NULL; + ScrArea *sa2 = NULL; + ScrArea *sa3 = NULL; + + wmSubWindowSet(win, win->screen->mainwin); + + unsigned int pos = add_attrib(immVertexFormat(), "pos", GL_FLOAT, 2, KEEP_FLOAT); + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + + /* Note: first loop only draws if U.pixelsize > 1, skip otherwise */ + if (U.pixelsize > 1.0f) { + /* FIXME: doesn't our glLineWidth already scale by U.pixelsize? */ + glLineWidth((2.0f * U.pixelsize) - 1); + immUniformColor3ub(0x50, 0x50, 0x50); + + for (sa = win->screen->areabase.first; sa; sa = sa->next) { + drawscredge_area(sa, winsize_x, winsize_y, pos); + } + } + + glLineWidth(1); + immUniformColor3ub(0, 0, 0); + + for (sa = win->screen->areabase.first; sa; sa = sa->next) { + drawscredge_area(sa, winsize_x, winsize_y, pos); + + /* gather area split/join info */ + if (sa->flag & AREA_FLAG_DRAWJOINFROM) sa1 = sa; + if (sa->flag & AREA_FLAG_DRAWJOINTO) sa2 = sa; + if (sa->flag & (AREA_FLAG_DRAWSPLIT_H | AREA_FLAG_DRAWSPLIT_V)) sa3 = sa; + } + + /* blended join arrow */ + if (sa1 && sa2) { + int dir = area_getorientation(sa1, sa2); + int dira = -1; + if (dir != -1) { + switch (dir) { + case 0: /* W */ + dir = 'r'; + dira = 'l'; + break; + case 1: /* N */ + dir = 'd'; + dira = 'u'; + break; + case 2: /* E */ + dir = 'l'; + dira = 'r'; + break; + case 3: /* S */ + dir = 'u'; + dira = 'd'; + break; + } + } + + glEnable(GL_BLEND); + + scrarea_draw_shape_dark(sa2, dir, pos); + scrarea_draw_shape_light(sa1, dira, pos); + + glDisable(GL_BLEND); + } + + /* splitpoint */ + if (sa3) { + glEnable(GL_BLEND); + immUniformColor4ub(255, 255, 255, 100); + + immBegin(GL_LINES, 2); + + if (sa3->flag & AREA_FLAG_DRAWSPLIT_H) { + immVertex2f(pos, sa3->totrct.xmin, win->eventstate->y); + immVertex2f(pos, sa3->totrct.xmax, win->eventstate->y); + + immEnd(); + + immUniformColor4ub(0, 0, 0, 100); + + immBegin(GL_LINES, 2); + + immVertex2f(pos, sa3->totrct.xmin, win->eventstate->y + 1); + immVertex2f(pos, sa3->totrct.xmax, win->eventstate->y + 1); + } + else { + immVertex2f(pos, win->eventstate->x, sa3->totrct.ymin); + immVertex2f(pos, win->eventstate->x, sa3->totrct.ymax); + + immEnd(); + + immUniformColor4ub(0, 0, 0, 100); + + immBegin(GL_LINES, 2); + + immVertex2f(pos, win->eventstate->x + 1, sa3->totrct.ymin); + immVertex2f(pos, win->eventstate->x + 1, sa3->totrct.ymax); + } + + immEnd(); + + glDisable(GL_BLEND); + } + + immUnbindProgram(); + + win->screen->do_draw = false; +} + + +/* -------------------------------------------------------------------- */ +/* Screen Thumbnail Preview */ + +/** + * Calculates a scale factor to squash the preview for \a screen into a rectangle of given size and aspect. + */ +static void screen_preview_scale_get( + const bScreen *screen, float size_x, float size_y, + const float asp[2], + float r_scale[2]) +{ + float max_x = 0, max_y = 0; + + for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) { + max_x = MAX2(max_x, sa->totrct.xmax); + max_y = MAX2(max_y, sa->totrct.ymax); + } + r_scale[0] = (size_x * asp[0]) / max_x; + r_scale[1] = (size_y * asp[1]) / max_y; +} + +static void screen_preview_draw_areas(const bScreen *screen, const float scale[2], const float col[4], + const float ofs_between_areas) +{ + const float ofs_h = ofs_between_areas * 0.5f; + unsigned int pos = add_attrib(immVertexFormat(), "pos", GL_FLOAT, 2, KEEP_FLOAT); + rctf rect; + + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + immUniformColor4fv(col); + + for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) { + rect.xmin = sa->totrct.xmin * scale[0] + ofs_h; + rect.xmax = sa->totrct.xmax * scale[0] - ofs_h; + rect.ymin = sa->totrct.ymin * scale[1] + ofs_h; + rect.ymax = sa->totrct.ymax * scale[1] - ofs_h; + + immBegin(PRIM_TRIANGLE_FAN, 4); + immVertex2f(pos, rect.xmin, rect.ymin); + immVertex2f(pos, rect.xmax, rect.ymin); + immVertex2f(pos, rect.xmax, rect.ymax); + immVertex2f(pos, rect.xmin, rect.ymax); + immEnd(); + } + + immUnbindProgram(); +} + +static void screen_preview_draw(const bScreen *screen, int size_x, int size_y) +{ + const float asp[2] = {1.0f, 0.8f}; /* square previews look a bit ugly */ + /* could use theme color (tui.wcol_menu_item.text), but then we'd need to regenerate all previews when changing */ + const float col[4] = {1.0f, 1.0f, 1.0f, 1.0f}; + float scale[2]; + + wmOrtho2(0.0f, size_x, 0.0f, size_y); + /* center */ + glTranslatef(size_x * (1.0f - asp[0]) * 0.5f, size_y * (1.0f - asp[1]) * 0.5f, 0.0f); + + screen_preview_scale_get(screen, size_x, size_y, asp, scale); + screen_preview_draw_areas(screen, scale, col, 1.5f); +} + +/** + * Render the preview for a screen layout in \a screen. + */ +void ED_screen_preview_render(const bScreen *screen, int size_x, int size_y, unsigned int *r_rect) +{ + char err_out[256] = "unknown"; + GPUOffScreen *offscreen = GPU_offscreen_create(size_x, size_y, 0, err_out); + + GPU_offscreen_bind(offscreen, true); + glClearColor(0.0, 0.0, 0.0, 0.0); + glClear(GL_COLOR_BUFFER_BIT); + + screen_preview_draw(screen, size_x, size_y); + + GPU_offscreen_read_pixels(offscreen, GL_UNSIGNED_BYTE, r_rect); + GPU_offscreen_unbind(offscreen, true); + + GPU_offscreen_free(offscreen); +} diff --git a/source/blender/editors/screen/screen_edit.c b/source/blender/editors/screen/screen_edit.c index 5cd0d33c365..239577a9fc4 100644 --- a/source/blender/editors/screen/screen_edit.c +++ b/source/blender/editors/screen/screen_edit.c @@ -42,6 +42,7 @@ #include "BKE_context.h" #include "BKE_depsgraph.h" +#include "BKE_icons.h" #include "BKE_image.h" #include "BKE_global.h" #include "BKE_library.h" @@ -51,9 +52,6 @@ #include "BKE_screen.h" #include "BKE_scene.h" -#include "BIF_gl.h" -#include "BIF_glutil.h" - #include "WM_api.h" #include "WM_types.h" @@ -615,7 +613,9 @@ int screen_area_join(bContext *C, bScreen *scr, ScrArea *sa1, ScrArea *sa2) screen_delarea(C, scr, sa2); removedouble_scrverts(scr); sa1->flag &= ~AREA_FLAG_DRAWJOINFROM; - + /* Update preview thumbnail */ + BKE_icon_changed(scr->id.icon_id); + return 1; } @@ -834,217 +834,6 @@ static void screen_test_scale(bScreen *sc, int winsize_x, int winsize_y) } -/* *********************** DRAWING **************************************** */ - -/* draw vertical shape visualizing future joining (left as well - * right direction of future joining) */ -static void draw_horizontal_join_shape(ScrArea *sa, char dir) -{ - vec2f points[10]; - short i; - float w, h; - float width = sa->v3->vec.x - sa->v1->vec.x; - float height = sa->v3->vec.y - sa->v1->vec.y; - - if (height < width) { - h = height / 8; - w = height / 4; - } - else { - h = width / 8; - w = width / 4; - } - - points[0].x = sa->v1->vec.x; - points[0].y = sa->v1->vec.y + height / 2; - - points[1].x = sa->v1->vec.x; - points[1].y = sa->v1->vec.y; - - points[2].x = sa->v4->vec.x - w; - points[2].y = sa->v4->vec.y; - - points[3].x = sa->v4->vec.x - w; - points[3].y = sa->v4->vec.y + height / 2 - 2 * h; - - points[4].x = sa->v4->vec.x - 2 * w; - points[4].y = sa->v4->vec.y + height / 2; - - points[5].x = sa->v4->vec.x - w; - points[5].y = sa->v4->vec.y + height / 2 + 2 * h; - - points[6].x = sa->v3->vec.x - w; - points[6].y = sa->v3->vec.y; - - points[7].x = sa->v2->vec.x; - points[7].y = sa->v2->vec.y; - - points[8].x = sa->v4->vec.x; - points[8].y = sa->v4->vec.y + height / 2 - h; - - points[9].x = sa->v4->vec.x; - points[9].y = sa->v4->vec.y + height / 2 + h; - - if (dir == 'l') { - /* when direction is left, then we flip direction of arrow */ - float cx = sa->v1->vec.x + width; - for (i = 0; i < 10; i++) { - points[i].x -= cx; - points[i].x = -points[i].x; - points[i].x += sa->v1->vec.x; - } - } - - glBegin(GL_POLYGON); - for (i = 0; i < 5; i++) - glVertex2f(points[i].x, points[i].y); - glEnd(); - glBegin(GL_POLYGON); - for (i = 4; i < 8; i++) - glVertex2f(points[i].x, points[i].y); - glVertex2f(points[0].x, points[0].y); - glEnd(); - - glRectf(points[2].x, points[2].y, points[8].x, points[8].y); - glRectf(points[6].x, points[6].y, points[9].x, points[9].y); -} - -/* draw vertical shape visualizing future joining (up/down direction) */ -static void draw_vertical_join_shape(ScrArea *sa, char dir) -{ - vec2f points[10]; - short i; - float w, h; - float width = sa->v3->vec.x - sa->v1->vec.x; - float height = sa->v3->vec.y - sa->v1->vec.y; - - if (height < width) { - h = height / 4; - w = height / 8; - } - else { - h = width / 4; - w = width / 8; - } - - points[0].x = sa->v1->vec.x + width / 2; - points[0].y = sa->v3->vec.y; - - points[1].x = sa->v2->vec.x; - points[1].y = sa->v2->vec.y; - - points[2].x = sa->v1->vec.x; - points[2].y = sa->v1->vec.y + h; - - points[3].x = sa->v1->vec.x + width / 2 - 2 * w; - points[3].y = sa->v1->vec.y + h; - - points[4].x = sa->v1->vec.x + width / 2; - points[4].y = sa->v1->vec.y + 2 * h; - - points[5].x = sa->v1->vec.x + width / 2 + 2 * w; - points[5].y = sa->v1->vec.y + h; - - points[6].x = sa->v4->vec.x; - points[6].y = sa->v4->vec.y + h; - - points[7].x = sa->v3->vec.x; - points[7].y = sa->v3->vec.y; - - points[8].x = sa->v1->vec.x + width / 2 - w; - points[8].y = sa->v1->vec.y; - - points[9].x = sa->v1->vec.x + width / 2 + w; - points[9].y = sa->v1->vec.y; - - if (dir == 'u') { - /* when direction is up, then we flip direction of arrow */ - float cy = sa->v1->vec.y + height; - for (i = 0; i < 10; i++) { - points[i].y -= cy; - points[i].y = -points[i].y; - points[i].y += sa->v1->vec.y; - } - } - - glBegin(GL_POLYGON); - for (i = 0; i < 5; i++) - glVertex2f(points[i].x, points[i].y); - glEnd(); - glBegin(GL_POLYGON); - for (i = 4; i < 8; i++) - glVertex2f(points[i].x, points[i].y); - glVertex2f(points[0].x, points[0].y); - glEnd(); - - glRectf(points[2].x, points[2].y, points[8].x, points[8].y); - glRectf(points[6].x, points[6].y, points[9].x, points[9].y); -} - -/* draw join shape due to direction of joining */ -static void draw_join_shape(ScrArea *sa, char dir) -{ - if (dir == 'u' || dir == 'd') - draw_vertical_join_shape(sa, dir); - else - draw_horizontal_join_shape(sa, dir); -} - -/* draw screen area darker with arrow (visualization of future joining) */ -static void scrarea_draw_shape_dark(ScrArea *sa, char dir) -{ - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - glColor4ub(0, 0, 0, 50); - draw_join_shape(sa, dir); -} - -/* draw screen area ligher with arrow shape ("eraser" of previous dark shape) */ -static void scrarea_draw_shape_light(ScrArea *sa, char UNUSED(dir)) -{ - glBlendFunc(GL_DST_COLOR, GL_SRC_ALPHA); - /* value 181 was hardly computed: 181~105 */ - glColor4ub(255, 255, 255, 50); - /* draw_join_shape(sa, dir); */ - glRecti(sa->v1->vec.x, sa->v1->vec.y, sa->v3->vec.x, sa->v3->vec.y); -} - -static void drawscredge_area_draw(int sizex, int sizey, short x1, short y1, short x2, short y2) -{ - /* right border area */ - if (x2 < sizex - 1) { - glVertex2s(x2, y1); - glVertex2s(x2, y2); - } - - /* left border area */ - if (x1 > 0) { /* otherwise it draws the emboss of window over */ - glVertex2s(x1, y1); - glVertex2s(x1, y2); - } - - /* top border area */ - if (y2 < sizey - 1) { - glVertex2s(x1, y2); - glVertex2s(x2, y2); - } - - /* bottom border area */ - if (y1 > 0) { - glVertex2s(x1, y1); - glVertex2s(x2, y1); - } -} - -/** screen edges drawing **/ -static void drawscredge_area(ScrArea *sa, int sizex, int sizey) -{ - short x1 = sa->v1->vec.x; - short y1 = sa->v1->vec.y; - short x2 = sa->v3->vec.x; - short y2 = sa->v3->vec.y; - - drawscredge_area_draw(sizex, sizey, x1, y1, x2, y2); -} /* ****************** EXPORTED API TO OTHER MODULES *************************** */ @@ -1069,6 +858,9 @@ static void region_cursor_set(wmWindow *win, int swinid, int swin_changed) for (ARegion *ar = sa->regionbase.first; ar; ar = ar->next) { if (ar->swinid == swinid) { if (swin_changed || (ar->type && ar->type->event_cursor)) { + if (WM_manipulatormap_cursor_set(ar->manipulator_map, win)) { + return; + } ED_region_cursor_set(win, sa, ar); } return; @@ -1101,100 +893,6 @@ void ED_screen_do_listen(bContext *C, wmNotifier *note) } } -/* only for edge lines between areas, and the blended join arrows */ -void ED_screen_draw(wmWindow *win) -{ - const int winsize_x = WM_window_pixels_x(win); - const int winsize_y = WM_window_pixels_y(win); - - ScrArea *sa; - ScrArea *sa1 = NULL; - ScrArea *sa2 = NULL; - ScrArea *sa3 = NULL; - - wmSubWindowSet(win, win->screen->mainwin); - - /* Note: first loop only draws if U.pixelsize > 1, skip otherwise */ - if (U.pixelsize > 1.0f) { - /* FIXME: doesn't our glLineWidth already scale by U.pixelsize? */ - glLineWidth((2.0f * U.pixelsize) - 1); - glColor3ub(0x50, 0x50, 0x50); - glBegin(GL_LINES); - for (sa = win->screen->areabase.first; sa; sa = sa->next) - drawscredge_area(sa, winsize_x, winsize_y); - glEnd(); - } - - glLineWidth(1); - glColor3ub(0, 0, 0); - glBegin(GL_LINES); - for (sa = win->screen->areabase.first; sa; sa = sa->next) { - drawscredge_area(sa, winsize_x, winsize_y); - - /* gather area split/join info */ - if (sa->flag & AREA_FLAG_DRAWJOINFROM) sa1 = sa; - if (sa->flag & AREA_FLAG_DRAWJOINTO) sa2 = sa; - if (sa->flag & (AREA_FLAG_DRAWSPLIT_H | AREA_FLAG_DRAWSPLIT_V)) sa3 = sa; - } - glEnd(); - - /* blended join arrow */ - if (sa1 && sa2) { - int dir = area_getorientation(sa1, sa2); - int dira = -1; - if (dir != -1) { - switch (dir) { - case 0: /* W */ - dir = 'r'; - dira = 'l'; - break; - case 1: /* N */ - dir = 'd'; - dira = 'u'; - break; - case 2: /* E */ - dir = 'l'; - dira = 'r'; - break; - case 3: /* S */ - dir = 'u'; - dira = 'd'; - break; - } - } - glEnable(GL_BLEND); - scrarea_draw_shape_dark(sa2, dir); - scrarea_draw_shape_light(sa1, dira); - glDisable(GL_BLEND); - } - - /* splitpoint */ - if (sa3) { - glEnable(GL_BLEND); - glBegin(GL_LINES); - glColor4ub(255, 255, 255, 100); - - if (sa3->flag & AREA_FLAG_DRAWSPLIT_H) { - glVertex2s(sa3->totrct.xmin, win->eventstate->y); - glVertex2s(sa3->totrct.xmax, win->eventstate->y); - glColor4ub(0, 0, 0, 100); - glVertex2s(sa3->totrct.xmin, win->eventstate->y + 1); - glVertex2s(sa3->totrct.xmax, win->eventstate->y + 1); - } - else { - glVertex2s(win->eventstate->x, sa3->totrct.ymin); - glVertex2s(win->eventstate->x, sa3->totrct.ymax); - glColor4ub(0, 0, 0, 100); - glVertex2s(win->eventstate->x + 1, sa3->totrct.ymin); - glVertex2s(win->eventstate->x + 1, sa3->totrct.ymax); - } - glEnd(); - glDisable(GL_BLEND); - } - - win->screen->do_draw = false; -} - /* helper call for below, dpi changes headers */ static void screen_refresh_headersizes(void) { @@ -1274,25 +972,28 @@ void ED_screens_initialize(wmWindowManager *wm) void ED_region_exit(bContext *C, ARegion *ar) { wmWindowManager *wm = CTX_wm_manager(C); + wmWindow *win = CTX_wm_window(C); ARegion *prevar = CTX_wm_region(C); if (ar->type && ar->type->exit) ar->type->exit(wm, ar); CTX_wm_region_set(C, ar); + WM_event_remove_handlers(C, &ar->handlers); + WM_event_modal_handler_region_replace(win, ar, NULL); if (ar->swinid) { - wm_subwindow_close(CTX_wm_window(C), ar->swinid); + wm_subwindow_close(win, ar->swinid); ar->swinid = 0; } - + if (ar->headerstr) { MEM_freeN(ar->headerstr); ar->headerstr = NULL; } if (ar->regiontimer) { - WM_event_remove_timer(CTX_wm_manager(C), CTX_wm_window(C), ar->regiontimer); + WM_event_remove_timer(wm, win, ar->regiontimer); ar->regiontimer = NULL; } @@ -1302,6 +1003,7 @@ void ED_region_exit(bContext *C, ARegion *ar) void ED_area_exit(bContext *C, ScrArea *sa) { wmWindowManager *wm = CTX_wm_manager(C); + wmWindow *win = CTX_wm_window(C); ScrArea *prevsa = CTX_wm_area(C); ARegion *ar; @@ -1309,10 +1011,13 @@ void ED_area_exit(bContext *C, ScrArea *sa) sa->type->exit(wm, sa); CTX_wm_area_set(C, sa); + for (ar = sa->regionbase.first; ar; ar = ar->next) ED_region_exit(C, ar); WM_event_remove_handlers(C, &sa->handlers); + WM_event_modal_handler_area_replace(win, sa, NULL); + CTX_wm_area_set(C, prevsa); } diff --git a/source/blender/editors/screen/screen_intern.h b/source/blender/editors/screen/screen_intern.h index ccb6d5a6dca..49c0869fcfb 100644 --- a/source/blender/editors/screen/screen_intern.h +++ b/source/blender/editors/screen/screen_intern.h @@ -31,6 +31,8 @@ #ifndef __SCREEN_INTERN_H__ #define __SCREEN_INTERN_H__ +struct bContextDataResult; + /* internal exports only */ #define AZONESPOT (0.6f * U.widget_unit) @@ -40,12 +42,12 @@ /* area.c */ void ED_area_data_copy(ScrArea *sa_dst, ScrArea *sa_src, const bool do_free); void ED_area_data_swap(ScrArea *sa1, ScrArea *sa2); -void region_toggle_hidden(bContext *C, ARegion *ar, const bool do_fade); +void region_toggle_hidden(struct bContext *C, ARegion *ar, const bool do_fade); /* screen_edit.c */ ScrEdge *screen_findedge(bScreen *sc, ScrVert *v1, ScrVert *v2); ScrArea *area_split(bScreen *sc, ScrArea *sa, char dir, float fac, int merge); -int screen_area_join(bContext *C, bScreen *scr, ScrArea *sa1, ScrArea *sa2); +int screen_area_join(struct bContext *C, bScreen *scr, ScrArea *sa1, ScrArea *sa2); int area_getorientation(ScrArea *sa, ScrArea *sb); void select_connected_scredge(bScreen *sc, ScrEdge *edge); @@ -61,7 +63,7 @@ ScrEdge *screen_find_active_scredge(bScreen *sc, struct AZone *is_in_area_actionzone(ScrArea *sa, const int xy[2]); /* screen_context.c */ -int ed_screen_context(const bContext *C, const char *member, bContextDataResult *result); +int ed_screen_context(const struct bContext *C, const char *member, struct bContextDataResult *result); extern const char *screen_context_dir[]; /* doc access */ diff --git a/source/blender/editors/screen/screen_ops.c b/source/blender/editors/screen/screen_ops.c index a7a0a240259..32b63aca34c 100644 --- a/source/blender/editors/screen/screen_ops.c +++ b/source/blender/editors/screen/screen_ops.c @@ -53,6 +53,7 @@ #include "BKE_context.h" #include "BKE_customdata.h" #include "BKE_global.h" +#include "BKE_icons.h" #include "BKE_main.h" #include "BKE_object.h" #include "BKE_report.h" @@ -1220,6 +1221,8 @@ static void area_move_apply_do(bContext *C, int origval, int delta, int dir, int } WM_event_add_notifier(C, NC_SCREEN | NA_EDITED, NULL); /* redraw everything */ + /* Update preview thumbnail */ + BKE_icon_changed(sc->id.icon_id); } } @@ -1508,7 +1511,9 @@ static int area_split_apply(bContext *C, wmOperator *op) ED_area_tag_redraw(sd->narea); WM_event_add_notifier(C, NC_SCREEN | NA_EDITED, NULL); - + /* Update preview thumbnail */ + BKE_icon_changed(sc->id.icon_id); + return 1; } diff --git a/source/blender/editors/screen/screendump.c b/source/blender/editors/screen/screendump.c index 2dd7400bc37..5a8ea10cb0a 100644 --- a/source/blender/editors/screen/screendump.c +++ b/source/blender/editors/screen/screendump.c @@ -56,6 +56,8 @@ #include "BIF_gl.h" #include "BIF_glutil.h" +#include "GPU_immediate.h" + #include "RNA_access.h" #include "RNA_define.h" @@ -451,25 +453,24 @@ static void screenshot_startjob(void *sjv, short *stop, short *do_update, float /* Helper callback for drawing the cursor itself */ static void screencast_draw_cursor(bContext *UNUSED(C), int x, int y, void *UNUSED(p_ptr)) { - - glPushMatrix(); - - glTranslatef((float)x, (float)y, 0.0f); - - glEnable(GL_LINE_SMOOTH); glEnable(GL_BLEND); - - glColor4ub(0, 0, 0, 32); - glutil_draw_filled_arc(0.0, M_PI * 2.0, 20, 40); - - glColor4ub(255, 255, 255, 128); - glutil_draw_lined_arc(0.0, M_PI * 2.0, 20, 40); + + VertexFormat *format = immVertexFormat(); + unsigned int pos = add_attrib(format, "pos", GL_FLOAT, 2, KEEP_FLOAT); + + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + + immUniformColor4ub(0, 0, 0, 32); + imm_draw_filled_circle(pos, (float)x, (float)y, 20, 40); + + immUniformColor4ub(255, 255, 255, 128); + imm_draw_lined_circle(pos, (float)x, (float)y, 20, 40); + + immUnbindProgram(); glDisable(GL_BLEND); glDisable(GL_LINE_SMOOTH); - - glPopMatrix(); } /* Turn brush cursor in 3D view on/off */ diff --git a/source/blender/editors/sculpt_paint/paint_image.c b/source/blender/editors/sculpt_paint/paint_image.c index bf344e1f721..9850b2c93f0 100644 --- a/source/blender/editors/sculpt_paint/paint_image.c +++ b/source/blender/editors/sculpt_paint/paint_image.c @@ -78,6 +78,7 @@ #include "GPU_draw.h" #include "GPU_buffers.h" +#include "GPU_immediate.h" #include "BIF_gl.h" #include "BIF_glutil.h" @@ -721,12 +722,28 @@ static void gradient_draw_line(bContext *UNUSED(C), int x, int y, void *customda glEnable(GL_LINE_SMOOTH); glEnable(GL_BLEND); + VertexFormat *format = immVertexFormat(); + unsigned int pos = add_attrib(format, "pos", GL_INT, 2, CONVERT_INT_TO_FLOAT); + + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + glLineWidth(4.0); - glColor4ub(0, 0, 0, 255); - sdrawline(x, y, pop->startmouse[0], pop->startmouse[1]); + immUniformColor4ub(0, 0, 0, 255); + + immBegin(GL_LINES, 2); + immVertex2i(pos, x, y); + immVertex2i(pos, pop->startmouse[0], pop->startmouse[1]); + immEnd(); + glLineWidth(2.0); - glColor4ub(255, 255, 255, 255); - sdrawline(x, y, pop->startmouse[0], pop->startmouse[1]); + immUniformColor4ub(255, 255, 255, 255); + + immBegin(GL_LINES, 2); + immVertex2i(pos, x, y); + immVertex2i(pos, pop->startmouse[0], pop->startmouse[1]); + immEnd(); + + immUnbindProgram(); glDisable(GL_BLEND); glDisable(GL_LINE_SMOOTH); diff --git a/source/blender/editors/sculpt_paint/paint_stroke.c b/source/blender/editors/sculpt_paint/paint_stroke.c index 05270dbfa09..e6113f2c2c3 100644 --- a/source/blender/editors/sculpt_paint/paint_stroke.c +++ b/source/blender/editors/sculpt_paint/paint_stroke.c @@ -58,7 +58,7 @@ #include "BIF_gl.h" #include "BIF_glutil.h" -#include "GPU_basic_shader.h" +#include "GPU_immediate.h" #include "ED_screen.h" #include "ED_view3d.h" @@ -145,9 +145,18 @@ static void paint_draw_smooth_cursor(bContext *C, int x, int y, void *customdata if (stroke && brush) { glEnable(GL_LINE_SMOOTH); glEnable(GL_BLEND); - glColor4ubv(paint->paint_cursor_col); - sdrawline(x, y, (int)stroke->last_mouse_position[0], - (int)stroke->last_mouse_position[1]); + + unsigned int pos = add_attrib(immVertexFormat(), "pos", GL_FLOAT, 2, KEEP_FLOAT); + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + immUniformColor4ubv(paint->paint_cursor_col); + + immBegin(GL_LINES, 2); + immVertex2f(pos, x, y); + immVertex2f(pos, stroke->last_mouse_position[0], stroke->last_mouse_position[1]); + immEnd(); + + immUnbindProgram(); + glDisable(GL_BLEND); glDisable(GL_LINE_SMOOTH); } @@ -161,32 +170,46 @@ static void paint_draw_line_cursor(bContext *C, int x, int y, void *customdata) glEnable(GL_LINE_SMOOTH); glEnable(GL_BLEND); - GPU_basic_shader_bind_enable(GPU_SHADER_LINE | GPU_SHADER_STIPPLE); - GPU_basic_shader_line_stipple(3, 0xAAAA); - GPU_basic_shader_line_width(3.0); + setlinestyle(3); + glLineWidth(3.0f); + + unsigned int pos = add_attrib(immVertexFormat(), "pos", GL_FLOAT, 2, KEEP_FLOAT); + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + + immUniformColor4ub(0, 0, 0, paint->paint_cursor_col[3]); + + immBegin(GL_LINES, 2); - glColor4ub(0, 0, 0, paint->paint_cursor_col[3]); if (stroke->constrain_line) { - sdrawline((int)stroke->last_mouse_position[0], (int)stroke->last_mouse_position[1], - stroke->constrained_pos[0], stroke->constrained_pos[1]); + immVertex2f(pos, stroke->last_mouse_position[0], stroke->last_mouse_position[1]); + immVertex2f(pos, stroke->constrained_pos[0], stroke->constrained_pos[1]); } else { - sdrawline((int)stroke->last_mouse_position[0], (int)stroke->last_mouse_position[1], - x, y); + immVertex2f(pos, stroke->last_mouse_position[0], stroke->last_mouse_position[1]); + immVertex2f(pos, x, y); } - glColor4ub(255, 255, 255, paint->paint_cursor_col[3]); - GPU_basic_shader_line_width(1.0); + immEnd(); + + glLineWidth(1.0f); + immUniformColor4ub(255, 255, 255, paint->paint_cursor_col[3]); + + immBegin(GL_LINES, 2); + if (stroke->constrain_line) { - sdrawline((int)stroke->last_mouse_position[0], (int)stroke->last_mouse_position[1], - stroke->constrained_pos[0], stroke->constrained_pos[1]); + immVertex2f(pos, stroke->last_mouse_position[0], stroke->last_mouse_position[1]); + immVertex2f(pos, stroke->constrained_pos[0], stroke->constrained_pos[1]); } else { - sdrawline((int)stroke->last_mouse_position[0], (int)stroke->last_mouse_position[1], - x, y); + immVertex2f(pos, stroke->last_mouse_position[0], stroke->last_mouse_position[1]); + immVertex2f(pos, x, y); } - GPU_basic_shader_bind_disable(GPU_SHADER_LINE | GPU_SHADER_STIPPLE); + immEnd(); + + immUnbindProgram(); + + setlinestyle(0); glDisable(GL_BLEND); glDisable(GL_LINE_SMOOTH); diff --git a/source/blender/editors/sculpt_paint/sculpt.c b/source/blender/editors/sculpt_paint/sculpt.c index 84e98181dfb..3cdbe1e5c3c 100644 --- a/source/blender/editors/sculpt_paint/sculpt.c +++ b/source/blender/editors/sculpt_paint/sculpt.c @@ -2044,6 +2044,10 @@ static void do_draw_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode) mul_v3_v3(offset, ss->cache->scale); mul_v3_fl(offset, bstrength); + /* XXX - this shouldn't be necessary, but sculpting crashes in blender2.8 otherwise + * initialize before threads so they can do curve mapping */ + curvemapping_initialize(brush->curve); + /* threaded loop over nodes */ SculptThreadedTaskData data = { .sd = sd, .ob = ob, .brush = brush, .nodes = nodes, diff --git a/source/blender/editors/sculpt_paint/sculpt_uv.c b/source/blender/editors/sculpt_paint/sculpt_uv.c index fd2a0b15cb9..d7a4ea9c950 100644 --- a/source/blender/editors/sculpt_paint/sculpt_uv.c +++ b/source/blender/editors/sculpt_paint/sculpt_uv.c @@ -55,6 +55,8 @@ #include "ED_image.h" #include "ED_mesh.h" +#include "GPU_immediate.h" + #include "WM_api.h" #include "WM_types.h" @@ -64,7 +66,6 @@ #include "paint_intern.h" #include "uvedit_intern.h" -#include "BIF_gl.h" #include "BIF_glutil.h" #include "UI_view2d.h" @@ -212,18 +213,17 @@ static void brush_drawcursor_uvsculpt(bContext *C, int x, int y, void *UNUSED(cu alpha *= (size - PX_SIZE_FADE_MIN) / (PX_SIZE_FADE_MAX - PX_SIZE_FADE_MIN); } - glPushMatrix(); - - glTranslatef((float)x, (float)y, 0.0f); + unsigned int pos = add_attrib(immVertexFormat(), "pos", GL_FLOAT, 2, KEEP_FLOAT); + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + immUniformColor3fvAlpha(brush->add_col, alpha); - glColor4f(brush->add_col[0], brush->add_col[1], brush->add_col[2], alpha); glEnable(GL_LINE_SMOOTH); glEnable(GL_BLEND); - glutil_draw_lined_arc(0, (float)(M_PI * 2.0), size, 40); + imm_draw_lined_circle(pos, (float)x, (float)y, size, 40); glDisable(GL_BLEND); glDisable(GL_LINE_SMOOTH); - glPopMatrix(); + immUnbindProgram(); } #undef PX_SIZE_FADE_MAX #undef PX_SIZE_FADE_MIN diff --git a/source/blender/editors/space_action/action_draw.c b/source/blender/editors/space_action/action_draw.c index 0764f586de9..4c65207d9a0 100644 --- a/source/blender/editors/space_action/action_draw.c +++ b/source/blender/editors/space_action/action_draw.c @@ -61,6 +61,7 @@ #include "ED_keyframes_draw.h" #include "action_intern.h" +#include "GPU_immediate.h" /* ************************************************************************* */ /* Channel List */ @@ -156,15 +157,12 @@ void draw_channel_strips(bAnimContext *ac, SpaceAction *saction, ARegion *ar) { ListBase anim_data = {NULL, NULL}; bAnimListElem *ale; - int filter; View2D *v2d = &ar->v2d; bDopeSheet *ads = &saction->ads; AnimData *adt = NULL; float act_start, act_end, y; - size_t items; - int height; unsigned char col1[3], col2[3]; unsigned char col1a[3], col2a[3]; @@ -194,10 +192,10 @@ void draw_channel_strips(bAnimContext *ac, SpaceAction *saction, ARegion *ar) } /* build list of channels to draw */ - filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_LIST_CHANNELS); - items = ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); + int filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_LIST_CHANNELS); + size_t items = ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); - height = ((items * ACHANNEL_STEP(ac)) + (ACHANNEL_HEIGHT(ac))); + int height = ((items * ACHANNEL_STEP(ac)) + (ACHANNEL_HEIGHT(ac))); /* don't use totrect set, as the width stays the same * (NOTE: this is ok here, the configuration is pretty straightforward) */ @@ -205,6 +203,12 @@ void draw_channel_strips(bAnimContext *ac, SpaceAction *saction, ARegion *ar) /* first backdrop strips */ y = (float)(-ACHANNEL_HEIGHT(ac)); + + VertexFormat *format = immVertexFormat(); + unsigned int pos = add_attrib(format, "pos", GL_FLOAT, 2, KEEP_FLOAT); + + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + glEnable(GL_BLEND); for (ale = anim_data.first; ale; ale = ale->next) { @@ -223,28 +227,28 @@ void draw_channel_strips(bAnimContext *ac, SpaceAction *saction, ARegion *ar) /* determine if channel is selected */ if (acf->has_setting(ac, ale, ACHANNEL_SETTING_SELECT)) sel = ANIM_channel_setting_get(ac, ale, ACHANNEL_SETTING_SELECT); - + if (ELEM(ac->datatype, ANIMCONT_ACTION, ANIMCONT_DOPESHEET, ANIMCONT_SHAPEKEY)) { switch (ale->type) { case ANIMTYPE_SUMMARY: { /* reddish color from NLA */ - UI_ThemeColor4(TH_ANIM_ACTIVE); + immUniformThemeColor(TH_ANIM_ACTIVE); break; } case ANIMTYPE_SCENE: case ANIMTYPE_OBJECT: { - if (sel) glColor4ub(col1b[0], col1b[1], col1b[2], 0x45); - else glColor4ub(col1b[0], col1b[1], col1b[2], 0x22); + if (sel) immUniformColor4ub(col1b[0], col1b[1], col1b[2], 0x45); + else immUniformColor4ub(col1b[0], col1b[1], col1b[2], 0x22); break; } case ANIMTYPE_FILLACTD: case ANIMTYPE_DSSKEY: case ANIMTYPE_DSWOR: { - if (sel) glColor4ub(col2b[0], col2b[1], col2b[2], 0x45); - else glColor4ub(col2b[0], col2b[1], col2b[2], 0x22); + if (sel) immUniformColor4ub(col2b[0], col2b[1], col2b[2], 0x45); + else immUniformColor4ub(col2b[0], col2b[1], col2b[2], 0x22); break; } case ANIMTYPE_GROUP: @@ -252,17 +256,17 @@ void draw_channel_strips(bAnimContext *ac, SpaceAction *saction, ARegion *ar) bActionGroup *agrp = ale->data; if (show_group_colors && agrp->customCol) { if (sel) { - unsigned char *cp = (unsigned char *)agrp->cs.select; - glColor4ub(cp[0], cp[1], cp[2], 0x45); + char *cp = agrp->cs.select; + immUniformColor4ub(cp[0], cp[1], cp[2], 0x45); } else { - unsigned char *cp = (unsigned char *)agrp->cs.solid; - glColor4ub(cp[0], cp[1], cp[2], 0x1D); + char *cp = agrp->cs.solid; + immUniformColor4ub(cp[0], cp[1], cp[2], 0x1D); } } else { - if (sel) glColor4ub(col1a[0], col1a[1], col1a[2], 0x22); - else glColor4ub(col2a[0], col2a[1], col2a[2], 0x22); + if (sel) immUniformColor4ub(col1a[0], col1a[1], col1a[2], 0x22); + else immUniformColor4ub(col2a[0], col2a[1], col2a[2], 0x22); } break; } @@ -272,51 +276,51 @@ void draw_channel_strips(bAnimContext *ac, SpaceAction *saction, ARegion *ar) if (show_group_colors && fcu->grp && fcu->grp->customCol) { unsigned char *cp = (unsigned char *)fcu->grp->cs.active; - if (sel) glColor4ub(cp[0], cp[1], cp[2], 0x65); - else glColor4ub(cp[0], cp[1], cp[2], 0x0B); + if (sel) immUniformColor4ub(cp[0], cp[1], cp[2], 0x65); + else immUniformColor4ub(cp[0], cp[1], cp[2], 0x0B); } else { - if (sel) glColor4ub(col1[0], col1[1], col1[2], 0x22); - else glColor4ub(col2[0], col2[1], col2[2], 0x22); + if (sel) immUniformColor4ub(col1[0], col1[1], col1[2], 0x22); + else immUniformColor4ub(col2[0], col2[1], col2[2], 0x22); } break; } default: { - if (sel) glColor4ub(col1[0], col1[1], col1[2], 0x22); - else glColor4ub(col2[0], col2[1], col2[2], 0x22); + if (sel) immUniformColor4ub(col1[0], col1[1], col1[2], 0x22); + else immUniformColor4ub(col2[0], col2[1], col2[2], 0x22); break; } } /* draw region twice: firstly backdrop, then the current range */ - glRectf(v2d->cur.xmin, (float)y - ACHANNEL_HEIGHT_HALF(ac), v2d->cur.xmax + EXTRA_SCROLL_PAD, (float)y + ACHANNEL_HEIGHT_HALF(ac)); + immRectf(pos, v2d->cur.xmin, (float)y - ACHANNEL_HEIGHT_HALF(ac), v2d->cur.xmax + EXTRA_SCROLL_PAD, (float)y + ACHANNEL_HEIGHT_HALF(ac)); if (ac->datatype == ANIMCONT_ACTION) - glRectf(act_start, (float)y - ACHANNEL_HEIGHT_HALF(ac), act_end, (float)y + ACHANNEL_HEIGHT_HALF(ac)); + immRectf(pos, act_start, (float)y - ACHANNEL_HEIGHT_HALF(ac), act_end, (float)y + ACHANNEL_HEIGHT_HALF(ac)); } else if (ac->datatype == ANIMCONT_GPENCIL) { /* frames less than one get less saturated background */ - if (sel) glColor4ub(col1[0], col1[1], col1[2], 0x22); - else glColor4ub(col2[0], col2[1], col2[2], 0x22); - glRectf(0.0f, (float)y - ACHANNEL_HEIGHT_HALF(ac), v2d->cur.xmin, (float)y + ACHANNEL_HEIGHT_HALF(ac)); + if (sel) immUniformColor4ub(col1[0], col1[1], col1[2], 0x22); + else immUniformColor4ub(col2[0], col2[1], col2[2], 0x22); + immRectf(pos, 0.0f, (float)y - ACHANNEL_HEIGHT_HALF(ac), v2d->cur.xmin, (float)y + ACHANNEL_HEIGHT_HALF(ac)); /* frames one and higher get a saturated background */ - if (sel) glColor4ub(col1[0], col1[1], col1[2], 0x44); - else glColor4ub(col2[0], col2[1], col2[2], 0x44); - glRectf(v2d->cur.xmin, (float)y - ACHANNEL_HEIGHT_HALF(ac), v2d->cur.xmax + EXTRA_SCROLL_PAD, (float)y + ACHANNEL_HEIGHT_HALF(ac)); + if (sel) immUniformColor4ub(col1[0], col1[1], col1[2], 0x44); + else immUniformColor4ub(col2[0], col2[1], col2[2], 0x44); + immRectf(pos, v2d->cur.xmin, (float)y - ACHANNEL_HEIGHT_HALF(ac), v2d->cur.xmax + EXTRA_SCROLL_PAD, (float)y + ACHANNEL_HEIGHT_HALF(ac)); } else if (ac->datatype == ANIMCONT_MASK) { /* TODO --- this is a copy of gpencil */ /* frames less than one get less saturated background */ - if (sel) glColor4ub(col1[0], col1[1], col1[2], 0x22); - else glColor4ub(col2[0], col2[1], col2[2], 0x22); - glRectf(0.0f, (float)y - ACHANNEL_HEIGHT_HALF(ac), v2d->cur.xmin, (float)y + ACHANNEL_HEIGHT_HALF(ac)); + if (sel) immUniformColor4ub(col1[0], col1[1], col1[2], 0x22); + else immUniformColor4ub(col2[0], col2[1], col2[2], 0x22); + immRectf(pos, 0.0f, (float)y - ACHANNEL_HEIGHT_HALF(ac), v2d->cur.xmin, (float)y + ACHANNEL_HEIGHT_HALF(ac)); /* frames one and higher get a saturated background */ - if (sel) glColor4ub(col1[0], col1[1], col1[2], 0x44); - else glColor4ub(col2[0], col2[1], col2[2], 0x44); - glRectf(v2d->cur.xmin, (float)y - ACHANNEL_HEIGHT_HALF(ac), v2d->cur.xmax + EXTRA_SCROLL_PAD, (float)y + ACHANNEL_HEIGHT_HALF(ac)); + if (sel) immUniformColor4ub(col1[0], col1[1], col1[2], 0x44); + else immUniformColor4ub(col2[0], col2[1], col2[2], 0x44); + immRectf(pos, v2d->cur.xmin, (float)y - ACHANNEL_HEIGHT_HALF(ac), v2d->cur.xmax + EXTRA_SCROLL_PAD, (float)y + ACHANNEL_HEIGHT_HALF(ac)); } } } @@ -325,18 +329,29 @@ void draw_channel_strips(bAnimContext *ac, SpaceAction *saction, ARegion *ar) y -= ACHANNEL_STEP(ac); } glDisable(GL_BLEND); - - /* Draw keyframes + + /* black line marking 'current frame' for Time-Slide transform mode */ + if (saction->flag & SACTION_MOVING) { + immUniformColor3f(0.0f, 0.0f, 0.0f); + + immBegin(GL_LINES, 2); + immVertex2f(pos, saction->timeslide, v2d->cur.ymin - EXTRA_SCROLL_PAD); + immVertex2f(pos, saction->timeslide, v2d->cur.ymax); + immEnd(); + } + immUnbindProgram(); + + /* Draw keyframes * 1) Only channels that are visible in the Action Editor get drawn/evaluated. * This is to try to optimize this for heavier data sets * 2) Keyframes which are out of view horizontally are disregarded */ y = (float)(-ACHANNEL_HEIGHT(ac)); - + for (ale = anim_data.first; ale; ale = ale->next) { const float yminc = (float)(y - ACHANNEL_HEIGHT_HALF(ac)); const float ymaxc = (float)(y + ACHANNEL_HEIGHT_HALF(ac)); - + /* check if visible */ if (IN_RANGE(yminc, v2d->cur.ymin, v2d->cur.ymax) || IN_RANGE(ymaxc, v2d->cur.ymin, v2d->cur.ymax) ) @@ -344,7 +359,7 @@ void draw_channel_strips(bAnimContext *ac, SpaceAction *saction, ARegion *ar) /* check if anything to show for this channel */ if (ale->datatype != ALE_NONE) { adt = ANIM_nla_mapping_get(ac, ale); - + /* draw 'keyframes' for each specific datatype */ switch (ale->datatype) { case ALE_ALL: @@ -374,20 +389,10 @@ void draw_channel_strips(bAnimContext *ac, SpaceAction *saction, ARegion *ar) } } } - + y -= ACHANNEL_STEP(ac); } - - /* free tempolary channels used for drawing */ - ANIM_animdata_freelist(&anim_data); - /* black line marking 'current frame' for Time-Slide transform mode */ - if (saction->flag & SACTION_MOVING) { - glColor3f(0.0f, 0.0f, 0.0f); - - glBegin(GL_LINES); - glVertex2f(saction->timeslide, v2d->cur.ymin - EXTRA_SCROLL_PAD); - glVertex2f(saction->timeslide, v2d->cur.ymax); - glEnd(); - } + /* free temporary channels used for drawing */ + ANIM_animdata_freelist(&anim_data); } diff --git a/source/blender/editors/space_api/spacetypes.c b/source/blender/editors/space_api/spacetypes.c index ac6e3123e4e..5ff1d758563 100644 --- a/source/blender/editors/space_api/spacetypes.c +++ b/source/blender/editors/space_api/spacetypes.c @@ -121,12 +121,17 @@ void ED_spacetypes_init(void) ED_operatortypes_view2d(); ED_operatortypes_ui(); - - /* register operators */ + + /* register types for operators and manipulators */ spacetypes = BKE_spacetypes_list(); for (type = spacetypes->first; type; type = type->next) { - if (type->operatortypes) + /* init manipulator types first, operator-types need them */ + if (type->manipulators) { + type->manipulators(); + } + if (type->operatortypes) { type->operatortypes(); + } } /* register internal render callbacks */ diff --git a/source/blender/editors/space_buttons/buttons_context.c b/source/blender/editors/space_buttons/buttons_context.c index da3364d872d..3727c29d9d0 100644 --- a/source/blender/editors/space_buttons/buttons_context.c +++ b/source/blender/editors/space_buttons/buttons_context.c @@ -49,6 +49,7 @@ #include "BKE_context.h" #include "BKE_action.h" +#include "BKE_layer.h" #include "BKE_material.h" #include "BKE_modifier.h" #include "BKE_paint.h" @@ -180,7 +181,9 @@ static int buttons_context_path_object(ButsContextPath *path) /* if we have a scene, use the scene's active object */ else if (buttons_context_path_scene(path)) { scene = path->ptr[path->len - 1].data; - ob = (scene->basact) ? scene->basact->object : NULL; + + SceneLayer *sl = BKE_scene_layer_context_active(scene); + ob = (sl->basact) ? sl->basact->object : NULL; if (ob) { RNA_id_pointer_create(&ob->id, &path->ptr[path->len]); @@ -553,6 +556,36 @@ static bool buttons_context_linestyle_pinnable(const bContext *C) } #endif +static int buttons_context_path_collection(const bContext *C, ButsContextPath *path) +{ + PointerRNA *ptr = &path->ptr[path->len - 1]; + + /* if we already have a (pinned) Collection, we're done */ + if (RNA_struct_is_a(ptr->type, &RNA_LayerCollection)) { + return 1; + } + + SceneLayer *sl = CTX_data_scene_layer(C); + LayerCollection *sc = BKE_layer_collection_active(sl); + + if (sc) { + RNA_pointer_create(NULL, &RNA_LayerCollection, sc, &path->ptr[path->len]); + path->len++; + + /* temporary object in context path to get edit mode */ + Object *ob = CTX_data_active_object(C); + if (ob) { + RNA_id_pointer_create(&ob->id, &path->ptr[path->len]); + path->len++; + } + + return 1; + } + + /* no path to a collection possible */ + return 0; +} + static int buttons_context_path(const bContext *C, ButsContextPath *path, int mainb, int flag) { SpaceButs *sbuts = CTX_wm_space_buts(C); @@ -627,7 +660,10 @@ static int buttons_context_path(const bContext *C, ButsContextPath *path, int ma case BCONTEXT_BONE_CONSTRAINT: found = buttons_context_path_pose_bone(path); break; - default: + case BCONTEXT_COLLECTION: + found = buttons_context_path_collection(C, path); + break; + default: found = 0; break; } @@ -744,7 +780,7 @@ const char *buttons_context_dir[] = { "texture", "texture_user", "texture_user_property", "bone", "edit_bone", "pose_bone", "particle_system", "particle_system_editable", "particle_settings", "cloth", "soft_body", "fluid", "smoke", "collision", "brush", "dynamic_paint", - "line_style", NULL + "line_style", "collection", NULL }; int buttons_context(const bContext *C, const char *member, bContextDataResult *result) @@ -1064,6 +1100,10 @@ int buttons_context(const bContext *C, const char *member, bContextDataResult *r set_pointer_type(path, result, &RNA_FreestyleLineStyle); return 1; } + else if (CTX_data_equals(member, "collection")) { + set_pointer_type(path, result, &RNA_LayerCollection); + return 1; + } else { return 0; /* not found */ } diff --git a/source/blender/editors/space_buttons/space_buttons.c b/source/blender/editors/space_buttons/space_buttons.c index e4c23ad74f8..608287939bd 100644 --- a/source/blender/editors/space_buttons/space_buttons.c +++ b/source/blender/editors/space_buttons/space_buttons.c @@ -171,6 +171,8 @@ static void buttons_main_region_draw(const bContext *C, ARegion *ar) ED_region_panels(C, ar, "constraint", sbuts->mainb, vertical); else if (sbuts->mainb == BCONTEXT_BONE_CONSTRAINT) ED_region_panels(C, ar, "bone_constraint", sbuts->mainb, vertical); + else if (sbuts->mainb == BCONTEXT_COLLECTION) + ED_region_panels(C, ar, "collection", sbuts->mainb, vertical); sbuts->re_align = 0; sbuts->mainbo = sbuts->mainb; diff --git a/source/blender/editors/space_clip/clip_dopesheet_draw.c b/source/blender/editors/space_clip/clip_dopesheet_draw.c index 4bf4c1e7baa..872e62dbc97 100644 --- a/source/blender/editors/space_clip/clip_dopesheet_draw.c +++ b/source/blender/editors/space_clip/clip_dopesheet_draw.c @@ -42,8 +42,6 @@ #include "ED_screen.h" #include "ED_clip.h" -#include "BIF_gl.h" - #include "WM_types.h" #include "UI_interface.h" @@ -54,6 +52,9 @@ #include "RNA_access.h" +#include "GPU_draw.h" +#include "GPU_immediate.h" + #include "clip_intern.h" /* own include */ static void track_channel_color(MovieTrackingTrack *track, float default_color[3], float color[3]) @@ -72,78 +73,25 @@ static void track_channel_color(MovieTrackingTrack *track, float default_color[3 } } -static void draw_keyframe_shape(float x, float y, float xscale, float yscale, bool sel, float alpha) +static void draw_keyframe_shape(float x, float y, bool sel, float alpha, + unsigned int pos_id, unsigned int color_id) { - /* coordinates for diamond shape */ - static const float _unit_diamond_shape[4][2] = { - {0.0f, 1.0f}, /* top vert */ - {1.0f, 0.0f}, /* mid-right */ - {0.0f, -1.0f}, /* bottom vert */ - {-1.0f, 0.0f} /* mid-left */ - }; - static GLuint displist1 = 0; - static GLuint displist2 = 0; - int hsize = STRIP_HEIGHT_HALF; - - /* initialize 2 display lists for diamond shape - one empty, one filled */ - if (displist1 == 0) { - displist1 = glGenLists(1); - glNewList(displist1, GL_COMPILE); - - glBegin(GL_LINE_LOOP); - glVertex2fv(_unit_diamond_shape[0]); - glVertex2fv(_unit_diamond_shape[1]); - glVertex2fv(_unit_diamond_shape[2]); - glVertex2fv(_unit_diamond_shape[3]); - glEnd(); - glEndList(); + float color[4] = { 0.91f, 0.91f, 0.91f, alpha }; + if (sel) { + UI_GetThemeColorShadeAlpha4fv(TH_STRIP_SELECT, 50, -255 * (1.0f - alpha), color); } - if (displist2 == 0) { - displist2 = glGenLists(1); - glNewList(displist2, GL_COMPILE); - - glBegin(GL_QUADS); - glVertex2fv(_unit_diamond_shape[0]); - glVertex2fv(_unit_diamond_shape[1]); - glVertex2fv(_unit_diamond_shape[2]); - glVertex2fv(_unit_diamond_shape[3]); - glEnd(); - glEndList(); - } - - glPushMatrix(); - - /* adjust view transform before starting */ - glTranslatef(x, y, 0.0f); - glScalef(1.0f / xscale * hsize, 1.0f / yscale * hsize, 1.0f); - - /* anti-aliased lines for more consistent appearance */ - glEnable(GL_LINE_SMOOTH); - - if (sel) - UI_ThemeColorShadeAlpha(TH_STRIP_SELECT, 50, -255 * (1.0f - alpha)); - else - glColor4f(0.91f, 0.91f, 0.91f, alpha); - - glCallList(displist2); - /* exterior - black frame */ - glColor4f(0.0f, 0.0f, 0.0f, alpha); - glCallList(displist1); - - glDisable(GL_LINE_SMOOTH); - - /* restore view transform */ - glPopMatrix(); + immAttrib4fv(color_id, color); + immVertex2f(pos_id, x, y); } -static void clip_draw_dopesheet_background(ARegion *ar, MovieClip *clip) +static void clip_draw_dopesheet_background(ARegion *ar, MovieClip *clip, unsigned int pos_id) { View2D *v2d = &ar->v2d; MovieTracking *tracking = &clip->tracking; MovieTrackingDopesheet *dopesheet = &tracking->dopesheet; MovieTrackingDopesheetCoverageSegment *coverage_segment; - + for (coverage_segment = dopesheet->coverage_segments.first; coverage_segment; coverage_segment = coverage_segment->next) @@ -153,12 +101,13 @@ static void clip_draw_dopesheet_background(ARegion *ar, MovieClip *clip) int end_frame = BKE_movieclip_remap_clip_to_scene_frame(clip, coverage_segment->end_frame); if (coverage_segment->coverage == TRACKING_COVERAGE_BAD) { - glColor4f(1.0f, 0.0f, 0.0f, 0.07f); + immUniformColor4f(1.0f, 0.0f, 0.0f, 0.07f); + } + else { + immUniformColor4f(1.0f, 1.0f, 0.0f, 0.07f); } - else - glColor4f(1.0f, 1.0f, 0.0f, 0.07f); - glRectf(start_frame, v2d->cur.ymin, end_frame, v2d->cur.ymax); + immRectf(pos_id, start_frame, v2d->cur.ymin, end_frame, v2d->cur.ymax); } } } @@ -175,18 +124,21 @@ void clip_draw_dopesheet_main(SpaceClip *sc, ARegion *ar, Scene *scene) MovieTracking *tracking = &clip->tracking; MovieTrackingDopesheet *dopesheet = &tracking->dopesheet; MovieTrackingDopesheetChannel *channel; - float y, xscale, yscale; float strip[4], selected_strip[4]; float height = (dopesheet->tot_channel * CHANNEL_STEP) + (CHANNEL_HEIGHT); + unsigned int keyframe_ct = 0; + + VertexFormat *format = immVertexFormat(); + unsigned int pos_id = add_attrib(format, "pos", COMP_F32, 2, KEEP_FLOAT); + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + /* don't use totrect set, as the width stays the same * (NOTE: this is ok here, the configuration is pretty straightforward) */ v2d->tot.ymin = (float)(-height); - y = (float) CHANNEL_FIRST; - - UI_view2d_scale_get(v2d, &xscale, &yscale); + float y = (float) CHANNEL_FIRST; /* setup colors for regular and selected strips */ UI_GetThemeColor3fv(TH_STRIP, strip); @@ -197,7 +149,7 @@ void clip_draw_dopesheet_main(SpaceClip *sc, ARegion *ar, Scene *scene) glEnable(GL_BLEND); - clip_draw_dopesheet_background(ar, clip); + clip_draw_dopesheet_background(ar, clip, pos_id); for (channel = dopesheet->channels.first; channel; channel = channel->next) { float yminc = (float) (y - CHANNEL_HEIGHT_HALF); @@ -208,7 +160,6 @@ void clip_draw_dopesheet_main(SpaceClip *sc, ARegion *ar, Scene *scene) IN_RANGE(ymaxc, v2d->cur.ymin, v2d->cur.ymax)) { MovieTrackingTrack *track = channel->track; - float alpha; int i; bool sel = (track->flag & TRACK_DOPE_SEL) != 0; @@ -218,32 +169,26 @@ void clip_draw_dopesheet_main(SpaceClip *sc, ARegion *ar, Scene *scene) float default_color[4] = {0.8f, 0.93f, 0.8f, 0.3f}; track_channel_color(track, default_color, color); - glColor4fv(color); + immUniformColor4fv(color); - glRectf(v2d->cur.xmin, (float) y - CHANNEL_HEIGHT_HALF, - v2d->cur.xmax + EXTRA_SCROLL_PAD, (float) y + CHANNEL_HEIGHT_HALF); + immRectf(pos_id, v2d->cur.xmin, (float) y - CHANNEL_HEIGHT_HALF, + v2d->cur.xmax + EXTRA_SCROLL_PAD, (float) y + CHANNEL_HEIGHT_HALF); } - alpha = (track->flag & TRACK_LOCKED) ? 0.5f : 1.0f; - /* tracked segments */ for (i = 0; i < channel->tot_segment; i++) { int start_frame = BKE_movieclip_remap_clip_to_scene_frame(clip, channel->segments[2 * i]); int end_frame = BKE_movieclip_remap_clip_to_scene_frame(clip, channel->segments[2 * i + 1]); - if (sel) - glColor4fv(selected_strip); - else - glColor4fv(strip); + immUniformColor4fv(sel ? selected_strip : strip); if (start_frame != end_frame) { - glRectf(start_frame, (float) y - STRIP_HEIGHT_HALF, - end_frame, (float) y + STRIP_HEIGHT_HALF); - draw_keyframe_shape(start_frame, y, xscale, yscale, sel, alpha); - draw_keyframe_shape(end_frame, y, xscale, yscale, sel, alpha); + immRectf(pos_id, start_frame, (float) y - STRIP_HEIGHT_HALF, + end_frame, (float) y + STRIP_HEIGHT_HALF); + keyframe_ct += 2; } else { - draw_keyframe_shape(start_frame, y, xscale, yscale, sel, alpha); + keyframe_ct++; } } @@ -253,9 +198,7 @@ void clip_draw_dopesheet_main(SpaceClip *sc, ARegion *ar, Scene *scene) MovieTrackingMarker *marker = &track->markers[i]; if ((marker->flag & (MARKER_DISABLED | MARKER_TRACKED)) == 0) { - int framenr = BKE_movieclip_remap_clip_to_scene_frame(clip, marker->framenr); - - draw_keyframe_shape(framenr, y, xscale, yscale, sel, alpha); + keyframe_ct++; } i++; @@ -266,6 +209,76 @@ void clip_draw_dopesheet_main(SpaceClip *sc, ARegion *ar, Scene *scene) y -= CHANNEL_STEP; } + immUnbindProgram(); + + if (keyframe_ct > 0) { + /* draw keyframe markers */ + format = immVertexFormat(); + pos_id = add_attrib(format, "pos", COMP_F32, 2, KEEP_FLOAT); + unsigned int size_id = add_attrib(format, "size", COMP_F32, 1, KEEP_FLOAT); + unsigned int color_id = add_attrib(format, "color", COMP_U8, 4, NORMALIZE_INT_TO_FLOAT); + unsigned int outline_color_id = add_attrib(format, "outlineColor", COMP_U8, 4, NORMALIZE_INT_TO_FLOAT); + + immBindBuiltinProgram(GPU_SHADER_KEYFRAME_DIAMOND); + GPU_enable_program_point_size(); + immBegin(PRIM_POINTS, keyframe_ct); + + /* all same size with black outline */ + immAttrib1f(size_id, 2.0f * STRIP_HEIGHT_HALF); + immAttrib3ub(outline_color_id, 0, 0, 0); + + y = (float) CHANNEL_FIRST; /* start again at the top */ + for (channel = dopesheet->channels.first; channel; channel = channel->next) { + float yminc = (float) (y - CHANNEL_HEIGHT_HALF); + float ymaxc = (float) (y + CHANNEL_HEIGHT_HALF); + + /* check if visible */ + if (IN_RANGE(yminc, v2d->cur.ymin, v2d->cur.ymax) || + IN_RANGE(ymaxc, v2d->cur.ymin, v2d->cur.ymax)) + { + MovieTrackingTrack *track = channel->track; + int i; + bool sel = (track->flag & TRACK_DOPE_SEL) != 0; + float alpha = (track->flag & TRACK_LOCKED) ? 0.5f : 1.0f; + + /* tracked segments */ + for (i = 0; i < channel->tot_segment; i++) { + int start_frame = BKE_movieclip_remap_clip_to_scene_frame(clip, channel->segments[2 * i]); + int end_frame = BKE_movieclip_remap_clip_to_scene_frame(clip, channel->segments[2 * i + 1]); + + if (start_frame != end_frame) { + draw_keyframe_shape(start_frame, y, sel, alpha, pos_id, color_id); + draw_keyframe_shape(end_frame, y, sel, alpha, pos_id, color_id); + } + else { + draw_keyframe_shape(start_frame, y, sel, alpha, pos_id, color_id); + } + } + + /* keyframes */ + i = 0; + while (i < track->markersnr) { + MovieTrackingMarker *marker = &track->markers[i]; + + if ((marker->flag & (MARKER_DISABLED | MARKER_TRACKED)) == 0) { + int framenr = BKE_movieclip_remap_clip_to_scene_frame(clip, marker->framenr); + + draw_keyframe_shape(framenr, y, sel, alpha, pos_id, color_id); + } + + i++; + } + } + + /* adjust y-position for next one */ + y -= CHANNEL_STEP; + } + + immEnd(); + GPU_disable_program_point_size(); + immUnbindProgram(); + } + glDisable(GL_BLEND); } @@ -279,22 +292,15 @@ void clip_draw_dopesheet_channels(const bContext *C, ARegion *ar) SpaceClip *sc = CTX_wm_space_clip(C); View2D *v2d = &ar->v2d; MovieClip *clip = ED_space_clip_get_clip(sc); - MovieTracking *tracking; - MovieTrackingDopesheet *dopesheet; - MovieTrackingDopesheetChannel *channel; uiStyle *style = UI_style_get(); - uiBlock *block; int fontid = style->widget.uifont_id; - int height; - float y; - PropertyRNA *chan_prop_lock; - + if (!clip) return; - tracking = &clip->tracking; - dopesheet = &tracking->dopesheet; - height = (dopesheet->tot_channel * CHANNEL_STEP) + (CHANNEL_HEIGHT); + MovieTracking *tracking = &clip->tracking; + MovieTrackingDopesheet *dopesheet = &tracking->dopesheet; + int height = (dopesheet->tot_channel * CHANNEL_STEP) + (CHANNEL_HEIGHT); if (height > BLI_rcti_size_y(&v2d->mask)) { /* don't use totrect set, as the width stays the same @@ -309,6 +315,37 @@ void clip_draw_dopesheet_channels(const bContext *C, ARegion *ar) /* loop through channels, and set up drawing depending on their type * first pass: just the standard GL-drawing for backdrop + text */ + float y = (float) CHANNEL_FIRST; + + VertexFormat *format = immVertexFormat(); + unsigned pos = add_attrib(format, "pos", GL_FLOAT, 2, KEEP_FLOAT); + + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + + MovieTrackingDopesheetChannel *channel; + for (channel = dopesheet->channels.first; channel; channel = channel->next) { + float yminc = (float) (y - CHANNEL_HEIGHT_HALF); + float ymaxc = (float) (y + CHANNEL_HEIGHT_HALF); + + /* check if visible */ + if (IN_RANGE(yminc, v2d->cur.ymin, v2d->cur.ymax) || + IN_RANGE(ymaxc, v2d->cur.ymin, v2d->cur.ymax)) + { + MovieTrackingTrack *track = channel->track; + float color[3]; + track_channel_color(track, NULL, color); + immUniformColor3fv(color); + + immRectf(pos, v2d->cur.xmin, (float) y - CHANNEL_HEIGHT_HALF, + v2d->cur.xmax + EXTRA_SCROLL_PAD, (float) y + CHANNEL_HEIGHT_HALF); + } + + /* adjust y-position for next one */ + y -= CHANNEL_STEP; + } + immUnbindProgram(); + + /* second pass: text */ y = (float) CHANNEL_FIRST; BLF_size(fontid, 11.0f * U.pixelsize, U.dpi); @@ -322,21 +359,11 @@ void clip_draw_dopesheet_channels(const bContext *C, ARegion *ar) IN_RANGE(ymaxc, v2d->cur.ymin, v2d->cur.ymax)) { MovieTrackingTrack *track = channel->track; - float font_height, color[3]; bool sel = (track->flag & TRACK_DOPE_SEL) != 0; - track_channel_color(track, NULL, color); - glColor3fv(color); - - glRectf(v2d->cur.xmin, (float) y - CHANNEL_HEIGHT_HALF, - v2d->cur.xmax + EXTRA_SCROLL_PAD, (float) y + CHANNEL_HEIGHT_HALF); - - if (sel) - UI_ThemeColor(TH_TEXT_HI); - else - UI_ThemeColor(TH_TEXT); + UI_FontThemeColor(fontid, sel ? TH_TEXT_HI : TH_TEXT); - font_height = BLF_height(fontid, channel->name, sizeof(channel->name)); + float font_height = BLF_height(fontid, channel->name, sizeof(channel->name)); BLF_position(fontid, v2d->cur.xmin + CHANNEL_PAD, y - font_height / 2.0f, 0.0f); BLF_draw(fontid, channel->name, strlen(channel->name)); @@ -346,12 +373,12 @@ void clip_draw_dopesheet_channels(const bContext *C, ARegion *ar) y -= CHANNEL_STEP; } - /* second pass: widgets */ - block = UI_block_begin(C, ar, __func__, UI_EMBOSS); + /* third pass: widgets */ + uiBlock *block = UI_block_begin(C, ar, __func__, UI_EMBOSS); y = (float) CHANNEL_FIRST; /* get RNA properties (once) */ - chan_prop_lock = RNA_struct_type_find_property(&RNA_MovieTrackingTrack, "lock"); + PropertyRNA *chan_prop_lock = RNA_struct_type_find_property(&RNA_MovieTrackingTrack, "lock"); BLI_assert(chan_prop_lock); glEnable(GL_BLEND); diff --git a/source/blender/editors/space_clip/clip_draw.c b/source/blender/editors/space_clip/clip_draw.c index 695d04d3850..670ed2f29eb 100644 --- a/source/blender/editors/space_clip/clip_draw.c +++ b/source/blender/editors/space_clip/clip_draw.c @@ -59,6 +59,8 @@ #include "BIF_glutil.h" #include "GPU_basic_shader.h" +#include "GPU_immediate.h" +#include "GPU_matrix.h" #include "WM_types.h" @@ -73,19 +75,19 @@ /*********************** main area drawing *************************/ -static void draw_keyframe(int frame, int cfra, int sfra, float framelen, int width) +static void draw_keyframe(int frame, int cfra, int sfra, float framelen, int width, unsigned int pos) { int height = (frame == cfra) ? 22 : 10; int x = (frame - sfra) * framelen; if (width == 1) { - glBegin(GL_LINES); - glVertex2i(x, 0); - glVertex2i(x, height * UI_DPI_FAC); - glEnd(); + immBegin(GL_LINES, 2); + immVertex2i(pos, x, 0); + immVertex2i(pos, x, height * UI_DPI_FAC); + immEnd(); } else { - glRecti(x, 0, x + width, height * UI_DPI_FAC); + immRecti(pos, x, 0, x + width, height * UI_DPI_FAC); } } @@ -166,6 +168,9 @@ static void draw_movieclip_cache(SpaceClip *sc, ARegion *ar, MovieClip *clip, Sc BKE_movieclip_get_cache_segments(clip, &sc->user, &totseg, &points); ED_region_cache_draw_cached_segments(ar, totseg, points, sfra, efra); + unsigned int pos = add_attrib(immVertexFormat(), "pos", COMP_I32, 2, CONVERT_INT_TO_FLOAT); + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + /* track */ if (act_track || act_plane_track) { for (i = sfra - clip->start_frame + 1, a = 0; i <= efra - clip->start_frame + 1; i++) { @@ -189,14 +194,17 @@ static void draw_movieclip_cache(SpaceClip *sc, ARegion *ar, MovieClip *clip, Sc if (generic_track_is_marker_enabled(act_track, act_plane_track, a)) { framenr = generic_track_get_marker_framenr(act_track, act_plane_track, a); - if (framenr != i) - glColor4ub(128, 128, 0, 96); - else if (generic_track_is_marker_keyframed(act_track, act_plane_track, a)) - glColor4ub(255, 255, 0, 196); - else - glColor4ub(255, 255, 0, 96); + if (framenr != i) { + immUniformColor4ub(128, 128, 0, 96); + } + else if (generic_track_is_marker_keyframed(act_track, act_plane_track, a)) { + immUniformColor4ub(255, 255, 0, 196); + } + else { + immUniformColor4ub(255, 255, 0, 96); + } - glRecti((i - sfra + clip->start_frame - 1) * framelen, 0, (i - sfra + clip->start_frame) * framelen, 4 * UI_DPI_FAC); + immRecti(pos, (i - sfra + clip->start_frame - 1) * framelen, 0, (i - sfra + clip->start_frame) * framelen, 4 * UI_DPI_FAC); } } } @@ -206,7 +214,7 @@ static void draw_movieclip_cache(SpaceClip *sc, ARegion *ar, MovieClip *clip, Sc int n = reconstruction->camnr; MovieReconstructedCamera *cameras = reconstruction->cameras; - glColor4ub(255, 0, 0, 96); + immUniformColor4ub(255, 0, 0, 96); for (i = sfra, a = 0; i <= efra; i++) { bool ok = false; @@ -223,8 +231,9 @@ static void draw_movieclip_cache(SpaceClip *sc, ARegion *ar, MovieClip *clip, Sc a++; } - if (!ok) - glRecti((i - sfra + clip->start_frame - 1) * framelen, 0, (i - sfra + clip->start_frame) * framelen, 8 * UI_DPI_FAC); + if (!ok) { + immRecti(pos, (i - sfra + clip->start_frame - 1) * framelen, 0, (i - sfra + clip->start_frame) * framelen, 8 * UI_DPI_FAC); + } } } @@ -233,15 +242,22 @@ static void draw_movieclip_cache(SpaceClip *sc, ARegion *ar, MovieClip *clip, Sc /* current frame */ x = (sc->user.framenr - sfra) / (efra - sfra + 1) * ar->winx; - UI_ThemeColor(TH_CFRAME); - glRecti(x, 0, x + ceilf(framelen), 8 * UI_DPI_FAC); + immUniformThemeColor(TH_CFRAME); + immRecti(pos, x, 0, x + ceilf(framelen), 8 * UI_DPI_FAC); + + immUnbindProgram(); ED_region_cache_draw_curfra_label(sc->user.framenr, x, 8.0f * UI_DPI_FAC); + pos = add_attrib(immVertexFormat(), "pos", COMP_I32, 2, CONVERT_INT_TO_FLOAT); + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + /* solver keyframes */ - glColor4ub(175, 255, 0, 255); - draw_keyframe(act_object->keyframe1 + clip->start_frame - 1, CFRA, sfra, framelen, 2); - draw_keyframe(act_object->keyframe2 + clip->start_frame - 1, CFRA, sfra, framelen, 2); + immUniformColor4ub(175, 255, 0, 255); + draw_keyframe(act_object->keyframe1 + clip->start_frame - 1, CFRA, sfra, framelen, 2, pos); + draw_keyframe(act_object->keyframe2 + clip->start_frame - 1, CFRA, sfra, framelen, 2, pos); + + immUnbindProgram(); /* movie clip animation */ if ((sc->mode == SC_MODE_MASKEDIT) && sc->mask_info.mask) { @@ -275,11 +291,16 @@ static void draw_movieclip_muted(ARegion *ar, int width, int height, float zoomx { int x, y; + unsigned int pos = add_attrib(immVertexFormat(), "pos", GL_FLOAT, 2, KEEP_FLOAT); + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + /* find window pixel coordinates of origin */ UI_view2d_view_to_region(&ar->v2d, 0.0f, 0.0f, &x, &y); - glColor3f(0.0f, 0.0f, 0.0f); - glRectf(x, y, x + zoomx * width, y + zoomy * height); + immUniformColor3f(0.0f, 0.0f, 0.0f); + immRectf(pos, x, y, x + zoomx * width, y + zoomy * height); + + immUnbindProgram(); } static void draw_movieclip_buffer(const bContext *C, SpaceClip *sc, ARegion *ar, ImBuf *ibuf, @@ -297,7 +318,7 @@ static void draw_movieclip_buffer(const bContext *C, SpaceClip *sc, ARegion *ar, glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - fdrawcheckerboard(x, y, x + zoomx * ibuf->x, y + zoomy * ibuf->y); + imm_draw_checker_box(x, y, x + zoomx * ibuf->x, y + zoomy * ibuf->y); } /* non-scaled proxy shouldn't use filtering */ @@ -335,10 +356,7 @@ static void draw_stabilization_border(SpaceClip *sc, ARegion *ar, int width, int /* draw boundary border for frame if stabilization is enabled */ if (sc->flag & SC_SHOW_STABLE && clip->tracking.stabilization.flag & TRACKING_2D_STABILIZATION) { - glColor3f(0.0f, 0.0f, 0.0f); - - GPU_basic_shader_bind_enable(GPU_SHADER_LINE | GPU_SHADER_STIPPLE); - GPU_basic_shader_line_stipple(3, 0xAAAA); + setlinestyle(3); glEnable(GL_COLOR_LOGIC_OP); glLogicOp(GL_NOR); @@ -349,17 +367,20 @@ static void draw_stabilization_border(SpaceClip *sc, ARegion *ar, int width, int glScalef(zoomx, zoomy, 1.0f); glMultMatrixf(sc->stabmat); - glBegin(GL_LINE_LOOP); - glVertex2f(0.0f, 0.0f); - glVertex2f(width, 0.0f); - glVertex2f(width, height); - glVertex2f(0.0f, height); - glEnd(); + unsigned int pos = add_attrib(immVertexFormat(), "pos", GL_FLOAT, 2, KEEP_FLOAT); + + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + immUniformColor3f(0.0f, 0.0f, 0.0f); + + imm_draw_line_box(pos, 0.0f, 0.0f, width, height); + + immUnbindProgram(); glPopMatrix(); glDisable(GL_COLOR_LOGIC_OP); - GPU_basic_shader_bind_disable(GPU_SHADER_LINE | GPU_SHADER_STIPPLE); + + setlinestyle(0); } } @@ -423,69 +444,113 @@ static void draw_track_path(SpaceClip *sc, MovieClip *UNUSED(clip), MovieTrackin i++; } + unsigned int pos = add_attrib(immVertexFormat(), "pos", GL_FLOAT, 2, KEEP_FLOAT); + + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + if (!tiny) { - UI_ThemeColor(TH_MARKER_OUTLINE); + immUniformThemeColor(TH_MARKER_OUTLINE); if (TRACK_VIEW_SELECTED(sc, track)) { - glPointSize(5.0f); - glBegin(GL_POINTS); - for (i = a; i < b; i++) { - if (i != curindex) - glVertex2f(path[i][0], path[i][1]); + if ((b - a - 1) >= 1) { + glPointSize(5.0f); + + immBegin(GL_POINTS, b - a - 1); + + for (i = a; i < b; i++) { + if (i != curindex) { + immVertex2f(pos, path[i][0], path[i][1]); + } + } + + immEnd(); } - glEnd(); } - glLineWidth(3.0f); - glBegin(GL_LINE_STRIP); - for (i = a; i < b; i++) - glVertex2f(path[i][0], path[i][1]); - glEnd(); - } + if ((b - a) >= 2) { + glLineWidth(3.0f); + + immBegin(GL_LINE_STRIP, b - a); + + for (i = a; i < b; i++) { + immVertex2f(pos, path[i][0], path[i][1]); + } - UI_ThemeColor(TH_PATH_BEFORE); + immEnd(); + } + } if (TRACK_VIEW_SELECTED(sc, track)) { glPointSize(3.0f); - glBegin(GL_POINTS); - for (i = a; i < b; i++) { - if (i == count + 1) - UI_ThemeColor(TH_PATH_AFTER); - if (i != curindex) - glVertex2f(path[i][0], path[i][1]); + if ((curindex - a) >= 1) { + immUniformThemeColor(TH_PATH_BEFORE); + + immBegin(GL_POINTS, curindex - a); + + for (i = a; i < curindex; i++) { + immVertex2f(pos, path[i][0], path[i][1]); + } + + immEnd(); } - glEnd(); - } - UI_ThemeColor(TH_PATH_BEFORE); + if ((b - curindex - 1) >= 1) { + immUniformThemeColor(TH_PATH_AFTER); + + immBegin(GL_POINTS, b - curindex - 1); + + for (i = curindex + 1; i < b; i++) { + immVertex2f(pos, path[i][0], path[i][1]); + } + + immEnd(); + } + } glLineWidth(1); - glBegin(GL_LINE_STRIP); - for (i = a; i < b; i++) { - if (i == count + 1) - UI_ThemeColor(TH_PATH_AFTER); + if ((curindex - a + 1) >= 2) { + immUniformThemeColor(TH_PATH_BEFORE); - glVertex2f(path[i][0], path[i][1]); + immBegin(GL_LINE_STRIP, curindex - a + 1); + + for (i = a; i <= curindex; i++) { + immVertex2f(pos, path[i][0], path[i][1]); + } + + immEnd(); } - glEnd(); + + if ((b - curindex) >= 2) { + immUniformThemeColor(TH_PATH_AFTER); + + immBegin(GL_LINE_STRIP, b - curindex); + + for (i = curindex; i < b; i++) { + immVertex2f(pos, path[i][0], path[i][1]); + } + + immEnd(); + } + + immUnbindProgram(); } static void draw_marker_outline(SpaceClip *sc, MovieTrackingTrack *track, MovieTrackingMarker *marker, - const float marker_pos[2], int width, int height) + const float marker_pos[2], int width, int height, unsigned int position) { int tiny = sc->flag & SC_SHOW_TINY_MARKER; bool show_search = false; float px[2]; - UI_ThemeColor(TH_MARKER_OUTLINE); - px[0] = 1.0f / width / sc->zoom; px[1] = 1.0f / height / sc->zoom; glLineWidth(tiny ? 1.0f : 3.0f); + immUniformThemeColor(TH_MARKER_OUTLINE); + if ((marker->flag & MARKER_DISABLED) == 0) { float pos[2]; float p[2]; @@ -500,51 +565,56 @@ static void draw_marker_outline(SpaceClip *sc, MovieTrackingTrack *track, MovieT marker->pattern_corners[2], marker->pattern_corners[3])) { glPointSize(tiny ? 3.0f : 4.0f); - glBegin(GL_POINTS); - glVertex2f(pos[0], pos[1]); - glEnd(); + + immBegin(GL_POINTS, 1); + immVertex2f(position, pos[0], pos[1]); + immEnd(); } else { - glBegin(GL_LINES); - glVertex2f(pos[0] + px[0] * 2, pos[1]); - glVertex2f(pos[0] + px[0] * 8, pos[1]); + immBegin(GL_LINES, 8); + + immVertex2f(position, pos[0] + px[0] * 2, pos[1]); + immVertex2f(position, pos[0] + px[0] * 8, pos[1]); - glVertex2f(pos[0] - px[0] * 2, pos[1]); - glVertex2f(pos[0] - px[0] * 8, pos[1]); + immVertex2f(position, pos[0] - px[0] * 2, pos[1]); + immVertex2f(position, pos[0] - px[0] * 8, pos[1]); - glVertex2f(pos[0], pos[1] - px[1] * 2); - glVertex2f(pos[0], pos[1] - px[1] * 8); + immVertex2f(position, pos[0], pos[1] - px[1] * 2); + immVertex2f(position, pos[0], pos[1] - px[1] * 8); - glVertex2f(pos[0], pos[1] + px[1] * 2); - glVertex2f(pos[0], pos[1] + px[1] * 8); - glEnd(); + immVertex2f(position, pos[0], pos[1] + px[1] * 2); + immVertex2f(position, pos[0], pos[1] + px[1] * 8); + + immEnd(); } } /* pattern and search outline */ glPushMatrix(); glTranslate2fv(marker_pos); + gpuMatrixUpdate_legacy(); if (sc->flag & SC_SHOW_MARKER_PATTERN) { - glBegin(GL_LINE_LOOP); - glVertex2fv(marker->pattern_corners[0]); - glVertex2fv(marker->pattern_corners[1]); - glVertex2fv(marker->pattern_corners[2]); - glVertex2fv(marker->pattern_corners[3]); - glEnd(); + immBegin(GL_LINE_LOOP, 4); + immVertex2fv(position, marker->pattern_corners[0]); + immVertex2fv(position, marker->pattern_corners[1]); + immVertex2fv(position, marker->pattern_corners[2]); + immVertex2fv(position, marker->pattern_corners[3]); + immEnd(); } show_search = (TRACK_VIEW_SELECTED(sc, track) && ((marker->flag & MARKER_DISABLED) == 0 || (sc->flag & SC_SHOW_MARKER_PATTERN) == 0)) != 0; + if (sc->flag & SC_SHOW_MARKER_SEARCH && show_search) { - glBegin(GL_LINE_LOOP); - glVertex2f(marker->search_min[0], marker->search_min[1]); - glVertex2f(marker->search_max[0], marker->search_min[1]); - glVertex2f(marker->search_max[0], marker->search_max[1]); - glVertex2f(marker->search_min[0], marker->search_max[1]); - glEnd(); + imm_draw_line_box(position, marker->search_min[0], + marker->search_min[1], + marker->search_max[0], + marker->search_max[1]); } + glPopMatrix(); + gpuMatrixUpdate_legacy(); } static void track_colors(MovieTrackingTrack *track, int act, float col[3], float scol[3]) @@ -568,7 +638,7 @@ static void track_colors(MovieTrackingTrack *track, int act, float col[3], float } static void draw_marker_areas(SpaceClip *sc, MovieTrackingTrack *track, MovieTrackingMarker *marker, - const float marker_pos[2], int width, int height, int act, int sel) + const float marker_pos[2], int width, int height, int act, int sel, unsigned int position) { int tiny = sc->flag & SC_SHOW_TINY_MARKER; bool show_search = false; @@ -586,18 +656,18 @@ static void draw_marker_areas(SpaceClip *sc, MovieTrackingTrack *track, MovieTra float pos[2], p[2]; if (track->flag & TRACK_LOCKED) { - if (act) - UI_ThemeColor(TH_ACT_MARKER); - else if (track->flag & SELECT) - UI_ThemeColorShade(TH_LOCK_MARKER, 64); - else - UI_ThemeColor(TH_LOCK_MARKER); + if (act) { + immUniformThemeColor(TH_ACT_MARKER); + } + else if (track->flag & SELECT) { + immUniformThemeColorShade(TH_LOCK_MARKER, 64); + } + else { + immUniformThemeColor(TH_LOCK_MARKER); + } } else { - if (track->flag & SELECT) - glColor3fv(scol); - else - glColor3fv(col); + immUniformColor3fv((track->flag & SELECT) ? scol : col); } add_v2_v2v2(pos, marker->pos, track->offset); @@ -609,123 +679,106 @@ static void draw_marker_areas(SpaceClip *sc, MovieTrackingTrack *track, MovieTra marker->pattern_corners[2], marker->pattern_corners[3])) { glPointSize(tiny ? 1.0f : 2.0f); - glBegin(GL_POINTS); - glVertex2f(pos[0], pos[1]); - glEnd(); + + immBegin(GL_POINTS, 1); + immVertex2f(position, pos[0], pos[1]); + immEnd(); } else { - glBegin(GL_LINES); - glVertex2f(pos[0] + px[0] * 3, pos[1]); - glVertex2f(pos[0] + px[0] * 7, pos[1]); + immBegin(GL_LINES, 8); + + immVertex2f(position, pos[0] + px[0] * 3, pos[1]); + immVertex2f(position, pos[0] + px[0] * 7, pos[1]); + + immVertex2f(position, pos[0] - px[0] * 3, pos[1]); + immVertex2f(position, pos[0] - px[0] * 7, pos[1]); + + immVertex2f(position, pos[0], pos[1] - px[1] * 3); + immVertex2f(position, pos[0], pos[1] - px[1] * 7); - glVertex2f(pos[0] - px[0] * 3, pos[1]); - glVertex2f(pos[0] - px[0] * 7, pos[1]); + immVertex2f(position, pos[0], pos[1] + px[1] * 3); + immVertex2f(position, pos[0], pos[1] + px[1] * 7); - glVertex2f(pos[0], pos[1] - px[1] * 3); - glVertex2f(pos[0], pos[1] - px[1] * 7); + immEnd(); - glVertex2f(pos[0], pos[1] + px[1] * 3); - glVertex2f(pos[0], pos[1] + px[1] * 7); - glEnd(); + immUniformColor3f(0.0f, 0.0f, 0.0f); + setlinestyle(3); - glColor3f(0.0f, 0.0f, 0.0f); - GPU_basic_shader_bind_enable(GPU_SHADER_LINE | GPU_SHADER_STIPPLE); - GPU_basic_shader_line_stipple(3, 0xAAAA); glEnable(GL_COLOR_LOGIC_OP); glLogicOp(GL_NOR); - glBegin(GL_LINES); - glVertex2fv(pos); - glVertex2fv(marker_pos); - glEnd(); + immBegin(GL_LINES, 2); + immVertex2fv(position, pos); + immVertex2fv(position, marker_pos); + immEnd(); glDisable(GL_COLOR_LOGIC_OP); - GPU_basic_shader_bind_disable(GPU_SHADER_LINE | GPU_SHADER_STIPPLE); + + setlinestyle(0); } } /* pattern */ glPushMatrix(); glTranslate2fv(marker_pos); + gpuMatrixUpdate_legacy(); if (tiny) { - GPU_basic_shader_bind_enable(GPU_SHADER_LINE | GPU_SHADER_STIPPLE); - GPU_basic_shader_line_stipple(3, 0xAAAA); - } - else { - GPU_basic_shader_bind_enable(GPU_SHADER_LINE); + setlinestyle(3); } - if ((track->pat_flag & SELECT) == sel && (sc->flag & SC_SHOW_MARKER_PATTERN)) { - if (track->flag & TRACK_LOCKED) { - if (act) - UI_ThemeColor(TH_ACT_MARKER); - else if (track->pat_flag & SELECT) - UI_ThemeColorShade(TH_LOCK_MARKER, 64); - else UI_ThemeColor(TH_LOCK_MARKER); + if (track->flag & TRACK_LOCKED) { + if (act) { + immUniformThemeColor(TH_ACT_MARKER); + } + else if (track->pat_flag & SELECT) { + immUniformThemeColorShade(TH_LOCK_MARKER, 64); + } + else { + immUniformThemeColor(TH_LOCK_MARKER); + } + } + else if (marker->flag & MARKER_DISABLED) { + if (act) { + immUniformThemeColor(TH_ACT_MARKER); } - else if (marker->flag & MARKER_DISABLED) { - if (act) - UI_ThemeColor(TH_ACT_MARKER); - else if (track->pat_flag & SELECT) - UI_ThemeColorShade(TH_DIS_MARKER, 128); - else UI_ThemeColor(TH_DIS_MARKER); + else if (track->pat_flag & SELECT) { + immUniformThemeColorShade(TH_DIS_MARKER, 128); } else { - if (track->pat_flag & SELECT) - glColor3fv(scol); - else glColor3fv(col); + immUniformThemeColor(TH_DIS_MARKER); } + } + else { + immUniformColor3fv((track->pat_flag & SELECT) ? scol : col); + } - glBegin(GL_LINE_LOOP); - glVertex2fv(marker->pattern_corners[0]); - glVertex2fv(marker->pattern_corners[1]); - glVertex2fv(marker->pattern_corners[2]); - glVertex2fv(marker->pattern_corners[3]); - glEnd(); + if ((track->pat_flag & SELECT) == sel && (sc->flag & SC_SHOW_MARKER_PATTERN)) { + immBegin(GL_LINE_LOOP, 4); + immVertex2fv(position, marker->pattern_corners[0]); + immVertex2fv(position, marker->pattern_corners[1]); + immVertex2fv(position, marker->pattern_corners[2]); + immVertex2fv(position, marker->pattern_corners[3]); + immEnd(); } /* search */ show_search = (TRACK_VIEW_SELECTED(sc, track) && ((marker->flag & MARKER_DISABLED) == 0 || (sc->flag & SC_SHOW_MARKER_PATTERN) == 0)) != 0; - if ((track->search_flag & SELECT) == sel && (sc->flag & SC_SHOW_MARKER_SEARCH) && show_search) { - if (track->flag & TRACK_LOCKED) { - if (act) - UI_ThemeColor(TH_ACT_MARKER); - else if (track->search_flag & SELECT) - UI_ThemeColorShade(TH_LOCK_MARKER, 64); - else UI_ThemeColor(TH_LOCK_MARKER); - } - else if (marker->flag & MARKER_DISABLED) { - if (act) - UI_ThemeColor(TH_ACT_MARKER); - else if (track->search_flag & SELECT) - UI_ThemeColorShade(TH_DIS_MARKER, 128); - else UI_ThemeColor(TH_DIS_MARKER); - } - else { - if (track->search_flag & SELECT) - glColor3fv(scol); - else - glColor3fv(col); - } - glBegin(GL_LINE_LOOP); - glVertex2f(marker->search_min[0], marker->search_min[1]); - glVertex2f(marker->search_max[0], marker->search_min[1]); - glVertex2f(marker->search_max[0], marker->search_max[1]); - glVertex2f(marker->search_min[0], marker->search_max[1]); - glEnd(); + if ((track->search_flag & SELECT) == sel && (sc->flag & SC_SHOW_MARKER_SEARCH) && show_search) { + imm_draw_line_box(position, marker->search_min[0], + marker->search_min[1], + marker->search_max[0], + marker->search_max[1]); } if (tiny) { - GPU_basic_shader_bind_disable(GPU_SHADER_LINE | GPU_SHADER_STIPPLE); - } - else { - GPU_basic_shader_bind_disable(GPU_SHADER_LINE); + setlinestyle(0); } glPopMatrix(); + gpuMatrixUpdate_legacy(); } static float get_shortest_pattern_side(MovieTrackingMarker *marker) @@ -746,7 +799,7 @@ static float get_shortest_pattern_side(MovieTrackingMarker *marker) return sqrtf(len_sq); } -static void draw_marker_slide_square(float x, float y, float dx, float dy, int outline, float px[2]) +static void draw_marker_slide_square(float x, float y, float dx, float dy, int outline, float px[2], unsigned int pos) { float tdx, tdy; @@ -758,15 +811,10 @@ static void draw_marker_slide_square(float x, float y, float dx, float dy, int o tdy += px[1]; } - glBegin(GL_QUADS); - glVertex3f(x - tdx, y + tdy, 0.0f); - glVertex3f(x + tdx, y + tdy, 0.0f); - glVertex3f(x + tdx, y - tdy, 0.0f); - glVertex3f(x - tdx, y - tdy, 0.0f); - glEnd(); + immRectf(pos, x - tdx, y - tdy, x + tdx, y + tdy); } -static void draw_marker_slide_triangle(float x, float y, float dx, float dy, int outline, float px[2]) +static void draw_marker_slide_triangle(float x, float y, float dx, float dy, int outline, float px[2], unsigned int pos) { float tdx, tdy; @@ -778,15 +826,16 @@ static void draw_marker_slide_triangle(float x, float y, float dx, float dy, int tdy += px[1]; } - glBegin(GL_TRIANGLES); - glVertex3f(x, y, 0.0f); - glVertex3f(x - tdx, y, 0.0f); - glVertex3f(x, y + tdy, 0.0f); - glEnd(); + immBegin(GL_TRIANGLES, 3); + immVertex2f(pos, x, y); + immVertex2f(pos, x - tdx, y); + immVertex2f(pos, x, y + tdy); + immEnd(); } static void draw_marker_slide_zones(SpaceClip *sc, MovieTrackingTrack *track, MovieTrackingMarker *marker, - const float marker_pos[2], int outline, int sel, int act, int width, int height) + const float marker_pos[2], int outline, int sel, int act, + int width, int height, unsigned int pos) { float dx, dy, patdx, patdy, searchdx, searchdy; int tiny = sc->flag & SC_SHOW_TINY_MARKER; @@ -801,11 +850,12 @@ static void draw_marker_slide_zones(SpaceClip *sc, MovieTrackingTrack *track, Mo track_colors(track, act, col, scol); if (outline) { - UI_ThemeColor(TH_MARKER_OUTLINE); + immUniformThemeColor(TH_MARKER_OUTLINE); } glPushMatrix(); glTranslate2fv(marker_pos); + gpuMatrixUpdate_legacy(); dx = 6.0f / width / sc->zoom; dy = 6.0f / height / sc->zoom; @@ -822,17 +872,14 @@ static void draw_marker_slide_zones(SpaceClip *sc, MovieTrackingTrack *track, Mo if ((sc->flag & SC_SHOW_MARKER_SEARCH) && ((track->search_flag & SELECT) == sel || outline)) { if (!outline) { - if (track->search_flag & SELECT) - glColor3fv(scol); - else - glColor3fv(col); + immUniformColor3fv((track->search_flag & SELECT) ? scol : col); } /* search offset square */ - draw_marker_slide_square(marker->search_min[0], marker->search_max[1], searchdx, searchdy, outline, px); + draw_marker_slide_square(marker->search_min[0], marker->search_max[1], searchdx, searchdy, outline, px, pos); /* search re-sizing triangle */ - draw_marker_slide_triangle(marker->search_max[0], marker->search_min[1], searchdx, searchdy, outline, px); + draw_marker_slide_triangle(marker->search_max[0], marker->search_min[1], searchdx, searchdy, outline, px, pos); } if ((sc->flag & SC_SHOW_MARKER_PATTERN) && ((track->pat_flag & SELECT) == sel || outline)) { @@ -842,16 +889,13 @@ static void draw_marker_slide_zones(SpaceClip *sc, MovieTrackingTrack *track, Mo float tilt_ctrl[2]; if (!outline) { - if (track->pat_flag & SELECT) - glColor3fv(scol); - else - glColor3fv(col); + immUniformColor3fv((track->search_flag & SELECT) ? scol : col); } /* pattern's corners sliding squares */ for (i = 0; i < 4; i++) { draw_marker_slide_square(marker->pattern_corners[i][0], marker->pattern_corners[i][1], - patdx / 1.5f, patdy / 1.5f, outline, px); + patdx / 1.5f, patdy / 1.5f, outline, px, pos); } /* ** sliders to control overall pattern ** */ @@ -861,18 +905,17 @@ static void draw_marker_slide_zones(SpaceClip *sc, MovieTrackingTrack *track, Mo glLineWidth(outline ? 3.0f : 1.0f); - glBegin(GL_LINES); - glVertex2f(0.0f, 0.0f); - glVertex2fv(tilt_ctrl); - glEnd(); - - GPU_basic_shader_bind_disable(GPU_SHADER_LINE | GPU_SHADER_STIPPLE); + immBegin(GL_LINES, 2); + immVertex2f(pos, 0.0f, 0.0f); + immVertex2fv(pos, tilt_ctrl); + immEnd(); /* slider to control pattern tilt */ - draw_marker_slide_square(tilt_ctrl[0], tilt_ctrl[1], patdx, patdy, outline, px); + draw_marker_slide_square(tilt_ctrl[0], tilt_ctrl[1], patdx, patdy, outline, px, pos); } glPopMatrix(); + gpuMatrixUpdate_legacy(); } static void draw_marker_texts(SpaceClip *sc, MovieTrackingTrack *track, MovieTrackingMarker *marker, @@ -890,16 +933,17 @@ static void draw_marker_texts(SpaceClip *sc, MovieTrackingTrack *track, MovieTra fontsize = BLF_height_max(fontid); if (marker->flag & MARKER_DISABLED) { - if (act) - UI_ThemeColor(TH_ACT_MARKER); - else - UI_ThemeColorShade(TH_DIS_MARKER, 128); + if (act) { + UI_FontThemeColor(fontid, TH_ACT_MARKER); + } + else { + unsigned char color[4]; + UI_GetThemeColorShade4ubv(TH_DIS_MARKER, 128, color); + BLF_color4ubv(fontid, color); + } } else { - if (act) - UI_ThemeColor(TH_ACT_MARKER); - else - UI_ThemeColor(TH_SEL_MARKER); + UI_FontThemeColor(fontid, act ? TH_ACT_MARKER : TH_SEL_MARKER); } if ((sc->flag & SC_SHOW_MARKER_SEARCH) && @@ -960,10 +1004,7 @@ static void plane_track_colors(bool is_active, float color[3], float selected_co { UI_GetThemeColor3fv(TH_MARKER, color); - if (is_active) - UI_GetThemeColor3fv(TH_ACT_MARKER, selected_color); - else - UI_GetThemeColor3fv(TH_SEL_MARKER, selected_color); + UI_GetThemeColor3fv(is_active ? TH_ACT_MARKER : TH_SEL_MARKER, selected_color); } static void getArrowEndPoint(const int width, const int height, const float zoom, @@ -1060,9 +1101,6 @@ static void draw_plane_marker_image(Scene *scene, glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); } - glColor4f(1.0, 1.0, 1.0, plane_track->image_opacity); - - GPU_basic_shader_bind(GPU_SHADER_TEXTURE_2D | GPU_SHADER_USE_COLOR); glGenTextures(1, (GLuint *)&texid); glBindTexture(GL_TEXTURE_2D, texid); @@ -1076,17 +1114,35 @@ static void draw_plane_marker_image(Scene *scene, glPushMatrix(); glMultMatrixf(gl_matrix); - glBegin(GL_QUADS); - glTexCoord2f(0.0f, 0.0f); glVertex2f(0.0f, 0.0f); - glTexCoord2f(1.0f, 0.0f); glVertex2f(1.0f, 0.0f); - glTexCoord2f(1.0f, 1.0f); glVertex2f(1.0f, 1.0f); - glTexCoord2f(0.0f, 1.0f); glVertex2f(0.0f, 1.0f); - glEnd(); + VertexFormat *imm_format = immVertexFormat(); + unsigned int pos = add_attrib(imm_format, "pos", GL_FLOAT, 2, KEEP_FLOAT); + unsigned int texCoord = add_attrib(imm_format, "texCoord", GL_FLOAT, 2, KEEP_FLOAT); + + immBindBuiltinProgram(GPU_SHADER_2D_IMAGE_COLOR); + immUniform4f("color", 1.0f, 1.0f, 1.0f, plane_track->image_opacity); + immUniform1i("image", GL_TEXTURE0); + + immBegin(GL_QUADS, 4); + + immAttrib2f(texCoord, 0.0f, 0.0f); + immVertex2f(pos, 0.0f, 0.0f); + + immAttrib2f(texCoord, 1.0f, 0.0f); + immVertex2f(pos, 1.0f, 0.0f); + + immAttrib2f(texCoord, 1.0f, 1.0f); + immVertex2f(pos, 1.0f, 1.0f); + + immAttrib2f(texCoord, 0.0f, 1.0f); + immVertex2f(pos, 0.0f, 1.0f); + + immEnd(); + + immUnbindProgram(); glPopMatrix(); glBindTexture(GL_TEXTURE_2D, 0); - GPU_basic_shader_bind(GPU_SHADER_USE_COLOR); if (transparent) { glDisable(GL_BLEND); @@ -1109,20 +1165,7 @@ static void draw_plane_marker_ex(SpaceClip *sc, Scene *scene, MovieTrackingPlane BKE_image_has_ibuf(plane_track->image, NULL); const bool draw_plane_quad = !has_image || plane_track->image_opacity == 0.0f; float px[2]; - - if (draw_outline) { - UI_ThemeColor(TH_MARKER_OUTLINE); - } - else { - float color[3], selected_color[3]; - plane_track_colors(is_active_track, color, selected_color); - if (is_selected_track) { - glColor3fv(selected_color); - } - else { - glColor3fv(color); - } - } + float color[3], selected_color[3]; px[0] = 1.0f / width / sc->zoom; px[1] = 1.0f / height / sc->zoom; @@ -1132,66 +1175,85 @@ static void draw_plane_marker_ex(SpaceClip *sc, Scene *scene, MovieTrackingPlane draw_plane_marker_image(scene, plane_track, plane_marker); } - if (draw_plane_quad) { + if (draw_plane_quad || is_selected_track) { + unsigned int pos = add_attrib(immVertexFormat(), "pos", GL_FLOAT, 2, KEEP_FLOAT); - const bool stipple = !draw_outline && tiny; - const bool thick = draw_outline && !tiny; + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); - if (stipple) { - GPU_basic_shader_bind_enable(GPU_SHADER_LINE | GPU_SHADER_STIPPLE); - GPU_basic_shader_line_stipple(3, 0xAAAA); + if (draw_outline) { + immUniformThemeColor(TH_MARKER_OUTLINE); } else { - GPU_basic_shader_bind_enable(GPU_SHADER_LINE); + plane_track_colors(is_active_track, color, selected_color); + + immUniformColor3fv(is_selected_track ? selected_color : color); } - GPU_basic_shader_line_width(thick ? 3.0f : 1.0f); + if (draw_plane_quad) { + const bool stipple = !draw_outline && tiny; + const bool thick = draw_outline && !tiny; - /* Draw rectangle itself. */ - glBegin(GL_LINE_LOOP); - glVertex2fv(plane_marker->corners[0]); - glVertex2fv(plane_marker->corners[1]); - glVertex2fv(plane_marker->corners[2]); - glVertex2fv(plane_marker->corners[3]); - glEnd(); + if (stipple) { + setlinestyle(3); + } - /* Draw axis. */ - if (!draw_outline) { - float end_point[2]; - glPushAttrib(GL_COLOR_BUFFER_BIT | GL_CURRENT_BIT); + glLineWidth(thick ? 3.0f : 1.0f); - glBegin(GL_LINES); + /* Draw rectangle itself. */ + immBegin(GL_LINE_LOOP, 4); + immVertex2fv(pos, plane_marker->corners[0]); + immVertex2fv(pos, plane_marker->corners[1]); + immVertex2fv(pos, plane_marker->corners[2]); + immVertex2fv(pos, plane_marker->corners[3]); + immEnd(); - getArrowEndPoint(width, height, sc->zoom, plane_marker->corners[0], plane_marker->corners[1], end_point); - glColor3f(1.0, 0.0, 0.0f); - glVertex2fv(plane_marker->corners[0]); - glVertex2fv(end_point); + /* Draw axis. */ + if (!draw_outline) { + float end_point[2]; - getArrowEndPoint(width, height, sc->zoom, plane_marker->corners[0], plane_marker->corners[3], end_point); - glColor3f(0.0, 1.0, 0.0f); - glVertex2fv(plane_marker->corners[0]); - glVertex2fv(end_point); + immUniformColor3f(1.0f, 0.0f, 0.0f); - glEnd(); + immBegin(GL_LINES, 2); - glPopAttrib(); - } + getArrowEndPoint(width, height, sc->zoom, plane_marker->corners[0], plane_marker->corners[1], end_point); + immVertex2fv(pos, plane_marker->corners[0]); + immVertex2fv(pos, end_point); - if (stipple) { - GPU_basic_shader_bind_disable(GPU_SHADER_LINE | GPU_SHADER_STIPPLE); - } - else { - GPU_basic_shader_bind_disable(GPU_SHADER_LINE); + immEnd(); + + immUniformColor3f(0.0f, 1.0f, 0.0f); + + immBegin(GL_LINES, 2); + + getArrowEndPoint(width, height, sc->zoom, plane_marker->corners[0], plane_marker->corners[3], end_point); + immVertex2fv(pos, plane_marker->corners[0]); + immVertex2fv(pos, end_point); + + immEnd(); + } + + if (stipple) { + setlinestyle(0); + } } - } - /* Draw sliders. */ - if (is_selected_track) { - int i; - for (i = 0; i < 4; i++) { - draw_marker_slide_square(plane_marker->corners[i][0], plane_marker->corners[i][1], - 3.0f * px[0], 3.0f * px[1], draw_outline, px); + /* Draw sliders. */ + if (is_selected_track) { + if (draw_outline) { + immUniformThemeColor(TH_MARKER_OUTLINE); + } + else { + immUniformColor3fv(selected_color); + } + + int i; + for (i = 0; i < 4; i++) { + draw_marker_slide_square(plane_marker->corners[i][0], plane_marker->corners[i][1], + 3.0f * px[0], 3.0f * px[1], draw_outline, px, pos); + } } + + immUnbindProgram(); } } @@ -1315,6 +1377,10 @@ static void draw_tracking_tracks(SpaceClip *sc, Scene *scene, ARegion *ar, Movie } } + unsigned int position = add_attrib(immVertexFormat(), "pos", GL_FLOAT, 2, KEEP_FLOAT); + + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + /* markers outline and non-selected areas */ track = tracksbase->first; fp = marker_pos; @@ -1325,10 +1391,10 @@ static void draw_tracking_tracks(SpaceClip *sc, Scene *scene, ARegion *ar, Movie if (MARKER_VISIBLE(sc, track, marker)) { copy_v2_v2(cur_pos, fp ? fp : marker->pos); - draw_marker_outline(sc, track, marker, cur_pos, width, height); - draw_marker_areas(sc, track, marker, cur_pos, width, height, 0, 0); - draw_marker_slide_zones(sc, track, marker, cur_pos, 1, 0, 0, width, height); - draw_marker_slide_zones(sc, track, marker, cur_pos, 0, 0, 0, width, height); + draw_marker_outline(sc, track, marker, cur_pos, width, height, position); + draw_marker_areas(sc, track, marker, cur_pos, width, height, 0, 0, position); + draw_marker_slide_zones(sc, track, marker, cur_pos, 1, 0, 0, width, height, position); + draw_marker_slide_zones(sc, track, marker, cur_pos, 0, 0, 0, width, height, position); if (fp) fp += 2; @@ -1351,8 +1417,8 @@ static void draw_tracking_tracks(SpaceClip *sc, Scene *scene, ARegion *ar, Movie if (!act) { copy_v2_v2(cur_pos, fp ? fp : marker->pos); - draw_marker_areas(sc, track, marker, cur_pos, width, height, 0, 1); - draw_marker_slide_zones(sc, track, marker, cur_pos, 0, 1, 0, width, height); + draw_marker_areas(sc, track, marker, cur_pos, width, height, 0, 1, position); + draw_marker_slide_zones(sc, track, marker, cur_pos, 0, 1, 0, width, height, position); } if (fp) @@ -1371,8 +1437,8 @@ static void draw_tracking_tracks(SpaceClip *sc, Scene *scene, ARegion *ar, Movie if (MARKER_VISIBLE(sc, act_track, marker)) { copy_v2_v2(cur_pos, active_pos ? active_pos : marker->pos); - draw_marker_areas(sc, act_track, marker, cur_pos, width, height, 1, 1); - draw_marker_slide_zones(sc, act_track, marker, cur_pos, 0, 1, 1, width, height); + draw_marker_areas(sc, act_track, marker, cur_pos, width, height, 1, 1, position); + draw_marker_slide_zones(sc, act_track, marker, cur_pos, 0, 1, 1, width, height, position); } } } @@ -1381,7 +1447,6 @@ static void draw_tracking_tracks(SpaceClip *sc, Scene *scene, ARegion *ar, Movie MovieTrackingObject *object = BKE_tracking_object_get_active(tracking); float pos[4], vec[4], mat[4][4], aspy; - glEnable(GL_POINT_SMOOTH); glPointSize(3.0f); aspy = 1.0f / clip->tracking.camera.pixel_aspect; @@ -1410,27 +1475,33 @@ static void draw_tracking_tracks(SpaceClip *sc, Scene *scene, ARegion *ar, Movie sub_v2_v2(vec, npos); - if (len_squared_v2(vec) < (3.0f * 3.0f)) - glColor3f(0.0f, 1.0f, 0.0f); - else - glColor3f(1.0f, 0.0f, 0.0f); + if (len_squared_v2(vec) < (3.0f * 3.0f)) { + immUniformColor3f(0.0f, 1.0f, 0.0f); + } + else { + immUniformColor3f(1.0f, 0.0f, 0.0f); + } - glBegin(GL_POINTS); - if (undistort) - glVertex3f(pos[0] / width, pos[1] / (height * aspy), 0); - else - glVertex3f(npos[0] / width, npos[1] / (height * aspy), 0); - glEnd(); + immBegin(GL_POINTS, 1); + + if (undistort) { + immVertex2f(position, pos[0] / width, pos[1] / (height * aspy)); + } + else { + immVertex2f(position, npos[0] / width, npos[1] / (height * aspy)); + } + + immEnd(); } } } track = track->next; } - - glDisable(GL_POINT_SMOOTH); } + immUnbindProgram(); + glPopMatrix(); if (sc->flag & SC_SHOW_NAMES) { @@ -1490,6 +1561,10 @@ static void draw_distortion(SpaceClip *sc, ARegion *ar, MovieClip *clip, glMultMatrixf(sc->stabmat); glScalef(width, height, 0); + unsigned int position = add_attrib(immVertexFormat(), "pos", GL_FLOAT, 2, KEEP_FLOAT); + + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + /* grid */ if (sc->flag & SC_SHOW_GRID) { float val[4][2], idx[4][2]; @@ -1560,22 +1635,26 @@ static void draw_distortion(SpaceClip *sc, ARegion *ar, MovieClip *clip, pos[1] += dy; } - glColor3f(1.0f, 0.0f, 0.0f); + immUniformColor3f(1.0f, 0.0f, 0.0f); for (i = 0; i <= n; i++) { - glBegin(GL_LINE_STRIP); + immBegin(GL_LINE_STRIP, n + 1); + for (j = 0; j <= n; j++) { - glVertex2fv(grid[i][j]); + immVertex2fv(position, grid[i][j]); } - glEnd(); + + immEnd(); } for (j = 0; j <= n; j++) { - glBegin(GL_LINE_STRIP); + immBegin(GL_LINE_STRIP, n + 1); + for (i = 0; i <= n; i++) { - glVertex2fv(grid[i][j]); + immVertex2fv(position, grid[i][j]); } - glEnd(); + + immEnd(); } } @@ -1594,7 +1673,8 @@ static void draw_distortion(SpaceClip *sc, ARegion *ar, MovieClip *clip, continue; } - glColor4fv(layer->color); + immUniformColor4fv(layer->color); + glLineWidth(layer->thickness); glPointSize((float)(layer->thickness + 2)); @@ -1604,7 +1684,6 @@ static void draw_distortion(SpaceClip *sc, ARegion *ar, MovieClip *clip, while (stroke) { if (stroke->flag & GP_STROKE_2DSPACE) { if (stroke->totpoints > 1) { - glBegin(GL_LINE_STRIP); for (i = 0; i < stroke->totpoints - 1; i++) { float npos[2], dpos[2], len; int steps; @@ -1627,19 +1706,22 @@ static void draw_distortion(SpaceClip *sc, ARegion *ar, MovieClip *clip, sub_v2_v2v2(dpos, npos, pos); mul_v2_fl(dpos, 1.0f / steps); + immBegin(GL_LINE_STRIP, steps + 1); + for (j = 0; j <= steps; j++) { BKE_tracking_distort_v2(tracking, pos, tpos); - glVertex2f(tpos[0] / width, tpos[1] / (height * aspy)); + immVertex2f(position, tpos[0] / width, tpos[1] / (height * aspy)); add_v2_v2(pos, dpos); } + + immEnd(); } - glEnd(); } else if (stroke->totpoints == 1) { - glBegin(GL_POINTS); - glVertex2f(stroke->points[0].x + offsx, stroke->points[0].y + offsy); - glEnd(); + immBegin(GL_POINTS, 1); + immVertex2f(position, stroke->points[0].x + offsx, stroke->points[0].y + offsy); + immEnd(); } } @@ -1653,6 +1735,8 @@ static void draw_distortion(SpaceClip *sc, ARegion *ar, MovieClip *clip, } } + immUnbindProgram(); + glPopMatrix(); } diff --git a/source/blender/editors/space_clip/clip_graph_draw.c b/source/blender/editors/space_clip/clip_graph_draw.c index 424d25defdd..b373358b49c 100644 --- a/source/blender/editors/space_clip/clip_graph_draw.c +++ b/source/blender/editors/space_clip/clip_graph_draw.c @@ -42,7 +42,10 @@ #include "ED_screen.h" #include "ED_clip.h" -#include "BIF_gl.h" +#include "BIF_glutil.h" + +#include "GPU_immediate.h" +#include "GPU_matrix.h" #include "WM_types.h" @@ -53,52 +56,30 @@ #include "clip_intern.h" // own include -static void draw_curve_knot(float x, float y, float xscale, float yscale, float hsize) -{ - static GLuint displist = 0; - - /* initialize round circle shape */ - if (displist == 0) { - GLUquadricObj *qobj; - - displist = glGenLists(1); - glNewList(displist, GL_COMPILE); - - qobj = gluNewQuadric(); - gluQuadricDrawStyle(qobj, GLU_SILHOUETTE); - gluDisk(qobj, 0, 0.7, 8, 1); - gluDeleteQuadric(qobj); - - glEndList(); - } - - glPushMatrix(); - - glTranslatef(x, y, 0.0f); - glScalef(1.0f / xscale * hsize, 1.0f / yscale * hsize, 1.0f); - glCallList(displist); - - glPopMatrix(); -} +typedef struct TrackMotionCurveUserData { + MovieTrackingTrack *act_track; + bool sel; + float xscale, yscale, hsize; + unsigned int pos; +} TrackMotionCurveUserData; -static void tracking_segment_point_cb(void *UNUSED(userdata), MovieTrackingTrack *UNUSED(track), +static void tracking_segment_point_cb(void *userdata, MovieTrackingTrack *UNUSED(track), MovieTrackingMarker *UNUSED(marker), int UNUSED(coord), int scene_framenr, float val) { - glVertex2f(scene_framenr, val); + TrackMotionCurveUserData *data = (TrackMotionCurveUserData *) userdata; + + immVertex2f(data->pos, scene_framenr, val); } static void tracking_segment_start_cb(void *userdata, MovieTrackingTrack *track, int coord) { - const float colors[2][3] = { - {1.0f, 0.0f, 0.0f}, - {0.0f, 1.0f, 0.0f}, - }; - float col[4]; + TrackMotionCurveUserData *data = (TrackMotionCurveUserData *) userdata; + float col[4] = {0.0f, 0.0f, 0.0f, 0.0f}; - copy_v3_v3(col, colors[coord]); + col[coord] = 1.0f; - if (track == userdata) { + if (track == data->act_track) { col[3] = 1.0f; glLineWidth(2.0f); } @@ -107,22 +88,17 @@ static void tracking_segment_start_cb(void *userdata, MovieTrackingTrack *track, glLineWidth(1.0f); } - glColor4fv(col); + immUniformColor4fv(col); - glBegin(GL_LINE_STRIP); + /* Graph can be composed of smaller segments, if any marker is disabled */ + immBeginAtMost(GL_LINE_STRIP, track->markersnr); } static void tracking_segment_end_cb(void *UNUSED(userdata), int UNUSED(coord)) { - glEnd(); + immEnd(); } -typedef struct TrackMotionCurveUserData { - MovieTrackingTrack *act_track; - bool sel; - float xscale, yscale, hsize; -} TrackMotionCurveUserData; - static void tracking_segment_knot_cb(void *userdata, MovieTrackingTrack *track, MovieTrackingMarker *marker, int coord, int scene_framenr, float val) { @@ -136,16 +112,20 @@ static void tracking_segment_knot_cb(void *userdata, MovieTrackingTrack *track, sel = (marker->flag & sel_flag) ? 1 : 0; if (sel == data->sel) { - if (sel) - UI_ThemeColor(TH_HANDLE_VERTEX_SELECT); - else - UI_ThemeColor(TH_HANDLE_VERTEX); + immUniformThemeColor(sel ? TH_HANDLE_VERTEX_SELECT : TH_HANDLE_VERTEX); + + glPushMatrix(); + glTranslatef(scene_framenr, val, 0.0f); + glScalef(1.0f / data->xscale * data->hsize, 1.0f / data->yscale * data->hsize, 1.0f); + gpuMatrixUpdate_legacy(); + + imm_draw_lined_circle(data->pos, 0, 0, 0.7, 8); - draw_curve_knot(scene_framenr, val, data->xscale, data->yscale, data->hsize); + glPopMatrix(); } } -static void draw_tracks_motion_curves(View2D *v2d, SpaceClip *sc) +static void draw_tracks_motion_curves(View2D *v2d, SpaceClip *sc, unsigned int pos) { MovieClip *clip = ED_space_clip_get_clip(sc); MovieTracking *tracking = &clip->tracking; @@ -162,18 +142,21 @@ static void draw_tracks_motion_curves(View2D *v2d, SpaceClip *sc) userdata.hsize = UI_GetThemeValuef(TH_HANDLE_VERTEX_SIZE); userdata.sel = false; userdata.act_track = act_track; + userdata.pos = pos; UI_view2d_scale_get(v2d, &userdata.xscale, &userdata.yscale); clip_graph_tracking_values_iterate(sc, (sc->flag & SC_SHOW_GRAPH_SEL_ONLY) != 0, (sc->flag & SC_SHOW_GRAPH_HIDDEN) != 0, &userdata, tracking_segment_knot_cb, NULL, NULL); + gpuMatrixUpdate_legacy(); + /* draw graph lines */ glEnable(GL_BLEND); clip_graph_tracking_values_iterate(sc, (sc->flag & SC_SHOW_GRAPH_SEL_ONLY) != 0, (sc->flag & SC_SHOW_GRAPH_HIDDEN) != 0, - act_track, tracking_segment_point_cb, tracking_segment_start_cb, + &userdata, tracking_segment_point_cb, tracking_segment_start_cb, tracking_segment_end_cb); glDisable(GL_BLEND); @@ -183,6 +166,8 @@ static void draw_tracks_motion_curves(View2D *v2d, SpaceClip *sc) (sc->flag & SC_SHOW_GRAPH_SEL_ONLY) != 0, (sc->flag & SC_SHOW_GRAPH_HIDDEN) != 0, &userdata, tracking_segment_knot_cb, NULL, NULL); + + gpuMatrixUpdate_legacy(); } typedef struct TrackErrorCurveUserData { @@ -195,6 +180,7 @@ typedef struct TrackErrorCurveUserData { float projection_matrix[4][4]; int width, height; float aspy; + unsigned int pos; } TrackErrorCurveUserData; static void tracking_error_segment_point_cb(void *userdata, @@ -230,7 +216,7 @@ static void tracking_error_segment_point_cb(void *userdata, sub_v2_v2v2(delta, reprojected_position, marker_position); reprojection_error = len_v2(delta) * weight; - glVertex2f(scene_framenr, reprojection_error); + immVertex2f(data->pos, scene_framenr, reprojection_error); } } @@ -249,20 +235,21 @@ static void tracking_error_segment_start_cb(void *userdata, MovieTrackingTrack * glLineWidth(1.0f); } - glColor4fv(col); + immUniformColor4fv(col); - glBegin(GL_LINE_STRIP); + /* Graph can be composed of smaller segments, if any marker is disabled */ + immBeginAtMost(GL_LINE_STRIP, track->markersnr); } } static void tracking_error_segment_end_cb(void *UNUSED(userdata), int coord) { if (coord == 1) { - glEnd(); + immEnd(); } } -static void draw_tracks_error_curves(SpaceClip *sc) +static void draw_tracks_error_curves(SpaceClip *sc, unsigned int pos) { MovieClip *clip = ED_space_clip_get_clip(sc); MovieTracking *tracking = &clip->tracking; @@ -273,6 +260,7 @@ static void draw_tracks_error_curves(SpaceClip *sc) data.tracking_object = BKE_tracking_object_get_active(tracking); data.active_track = BKE_tracking_track_get_active(tracking); data.matrix_initialized = false; + data.pos = pos; BKE_movieclip_get_size(clip, &sc->user, &data.width, &data.height); data.aspy = 1.0f / tracking->camera.pixel_aspect; @@ -289,37 +277,38 @@ static void draw_tracks_error_curves(SpaceClip *sc) tracking_error_segment_end_cb); } -static void draw_frame_curves(SpaceClip *sc) +static void draw_frame_curves(SpaceClip *sc, unsigned int pos) { MovieClip *clip = ED_space_clip_get_clip(sc); MovieTracking *tracking = &clip->tracking; MovieTrackingReconstruction *reconstruction = BKE_tracking_get_active_reconstruction(tracking); int i, lines = 0, prevfra = 0; - glColor3f(0.0f, 0.0f, 1.0f); + immUniformColor3f(0.0f, 0.0f, 1.0f); for (i = 0; i < reconstruction->camnr; i++) { MovieReconstructedCamera *camera = &reconstruction->cameras[i]; int framenr; if (lines && camera->framenr != prevfra + 1) { - glEnd(); + immEnd(); lines = 0; } if (!lines) { - glBegin(GL_LINE_STRIP); + immBeginAtMost(GL_LINE_STRIP, reconstruction->camnr); lines = 1; } framenr = BKE_movieclip_remap_clip_to_scene_frame(clip, camera->framenr); - glVertex2f(framenr, camera->error); + immVertex2f(pos, framenr, camera->error); prevfra = camera->framenr; } - if (lines) - glEnd(); + if (lines) { + immEnd(); + } } void clip_draw_graph(SpaceClip *sc, ARegion *ar, Scene *scene) @@ -334,17 +323,26 @@ void clip_draw_graph(SpaceClip *sc, ARegion *ar, Scene *scene) UI_view2d_grid_draw(v2d, grid, V2D_GRIDLINES_ALL); UI_view2d_grid_free(grid); + unsigned int pos = add_attrib(immVertexFormat(), "pos", GL_FLOAT, 2, KEEP_FLOAT); + + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + if (clip) { - if (sc->flag & SC_SHOW_GRAPH_TRACKS_MOTION) - draw_tracks_motion_curves(v2d, sc); + if (sc->flag & SC_SHOW_GRAPH_TRACKS_MOTION) { + draw_tracks_motion_curves(v2d, sc, pos); + } - if (sc->flag & SC_SHOW_GRAPH_TRACKS_ERROR) - draw_tracks_error_curves(sc); + if (sc->flag & SC_SHOW_GRAPH_TRACKS_ERROR) { + draw_tracks_error_curves(sc, pos); + } - if (sc->flag & SC_SHOW_GRAPH_FRAMES) - draw_frame_curves(sc); + if (sc->flag & SC_SHOW_GRAPH_FRAMES) { + draw_frame_curves(sc, pos); + } } + immUnbindProgram(); + /* frame range */ clip_draw_sfra_efra(v2d, scene); diff --git a/source/blender/editors/space_clip/clip_utils.c b/source/blender/editors/space_clip/clip_utils.c index 547c2fba66f..6026036c05d 100644 --- a/source/blender/editors/space_clip/clip_utils.c +++ b/source/blender/editors/space_clip/clip_utils.c @@ -43,8 +43,7 @@ #include "BKE_tracking.h" #include "BKE_depsgraph.h" -#include "BIF_gl.h" -#include "BIF_glutil.h" +#include "GPU_immediate.h" #include "WM_api.h" #include "WM_types.h" @@ -52,7 +51,6 @@ #include "ED_screen.h" #include "ED_clip.h" - #include "UI_interface.h" #include "UI_resources.h" #include "UI_view2d.h" @@ -237,31 +235,35 @@ void clip_view_center_to_point(SpaceClip *sc, float x, float y) void clip_draw_cfra(SpaceClip *sc, ARegion *ar, Scene *scene) { + /* Draw a light green line to indicate current frame */ View2D *v2d = &ar->v2d; - float xscale, yscale; + float x = (float)(sc->user.framenr * scene->r.framelen); - /* Draw a light green line to indicate current frame */ - UI_ThemeColor(TH_CFRAME); + unsigned pos = add_attrib(immVertexFormat(), "pos", GL_FLOAT, 2, KEEP_FLOAT); - float x = (float)(sc->user.framenr * scene->r.framelen); + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + immUniformThemeColor(TH_CFRAME); + glLineWidth(2.0f); - glLineWidth(2.0); + immBegin(GL_LINES, 2); + immVertex2f(pos, x, v2d->cur.ymin); + immVertex2f(pos, x, v2d->cur.ymax); + immEnd(); - glBegin(GL_LINES); - glVertex2f(x, v2d->cur.ymin); - glVertex2f(x, v2d->cur.ymax); - glEnd(); + immUnbindProgram(); UI_view2d_view_orthoSpecial(ar, v2d, 1); /* because the frame number text is subject to the same scaling as the contents of the view */ + float xscale, yscale; UI_view2d_scale_get(v2d, &xscale, &yscale); + glPushMatrix(); glScalef(1.0f / xscale, 1.0f, 1.0f); ED_region_cache_draw_curfra_label(sc->user.framenr, (float)sc->user.framenr * xscale, 18); /* restore view transform */ - glScalef(xscale, 1.0, 1.0); + glPopMatrix(); } void clip_draw_sfra_efra(View2D *v2d, Scene *scene) @@ -271,15 +273,27 @@ void clip_draw_sfra_efra(View2D *v2d, Scene *scene) /* currently clip editor supposes that editing clip length is equal to scene frame range */ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glEnable(GL_BLEND); - glColor4f(0.0f, 0.0f, 0.0f, 0.4f); - glRectf(v2d->cur.xmin, v2d->cur.ymin, (float)SFRA, v2d->cur.ymax); - glRectf((float)EFRA, v2d->cur.ymin, v2d->cur.xmax, v2d->cur.ymax); + unsigned pos = add_attrib(immVertexFormat(), "pos", GL_FLOAT, 2, KEEP_FLOAT); + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + + immUniformColor4f(0.0f, 0.0f, 0.0f, 0.4f); + immRectf(pos, v2d->cur.xmin, v2d->cur.ymin, (float)SFRA, v2d->cur.ymax); + immRectf(pos, (float)EFRA, v2d->cur.ymin, v2d->cur.xmax, v2d->cur.ymax); + glDisable(GL_BLEND); - UI_ThemeColorShade(TH_BACK, -60); + immUniformThemeColorShade(TH_BACK, -60); /* thin lines where the actual frames are */ - fdrawline((float)SFRA, v2d->cur.ymin, (float)SFRA, v2d->cur.ymax); - fdrawline((float)EFRA, v2d->cur.ymin, (float)EFRA, v2d->cur.ymax); + glLineWidth(1.0f); + + immBegin(GL_LINES, 4); + immVertex2f(pos, (float)SFRA, v2d->cur.ymin); + immVertex2f(pos, (float)SFRA, v2d->cur.ymax); + immVertex2f(pos, (float)EFRA, v2d->cur.ymin); + immVertex2f(pos, (float)EFRA, v2d->cur.ymax); + immEnd(); + + immUnbindProgram(); } diff --git a/source/blender/editors/space_clip/tracking_ops_orient.c b/source/blender/editors/space_clip/tracking_ops_orient.c index f81180d65a9..7b44e9317ba 100644 --- a/source/blender/editors/space_clip/tracking_ops_orient.c +++ b/source/blender/editors/space_clip/tracking_ops_orient.c @@ -44,6 +44,7 @@ #include "BKE_tracking.h" #include "BKE_global.h" #include "BKE_depsgraph.h" +#include "BKE_layer.h" #include "BKE_object.h" #include "BKE_report.h" @@ -69,17 +70,16 @@ static Object *get_camera_with_movieclip(Scene *scene, MovieClip *clip) return camera; } - for (Base *base = scene->base.first; - base != NULL; - base = base->next) + FOREACH_SCENE_OBJECT(scene, ob) { - if (base->object->type == OB_CAMERA) { - if (BKE_object_movieclip_get(scene, base->object, false) == clip) { - camera = base->object; + if (ob->type == OB_CAMERA) { + if (BKE_object_movieclip_get(scene, ob, false) == clip) { + camera = ob; break; } } } + FOREACH_SCENE_OBJECT_END return camera; } @@ -87,6 +87,7 @@ static Object *get_camera_with_movieclip(Scene *scene, MovieClip *clip) static Object *get_orientation_object(bContext *C) { Scene *scene = CTX_data_scene(C); + SceneLayer *sl = CTX_data_scene_layer(C); SpaceClip *sc = CTX_wm_space_clip(C); MovieClip *clip = ED_space_clip_get_clip(sc); MovieTracking *tracking = &clip->tracking; @@ -97,7 +98,7 @@ static Object *get_orientation_object(bContext *C) object = get_camera_with_movieclip(scene, clip); } else { - object = OBACT; + object = OBACT_NEW; } if (object != NULL && object->parent != NULL) { @@ -111,7 +112,7 @@ static int set_orientation_poll(bContext *C) { SpaceClip *sc = CTX_wm_space_clip(C); if (sc != NULL) { - Scene *scene = CTX_data_scene(C); + SceneLayer *sl = CTX_data_scene_layer(C); MovieClip *clip = ED_space_clip_get_clip(sc); if (clip != NULL) { MovieTracking *tracking = &clip->tracking; @@ -120,7 +121,7 @@ static int set_orientation_poll(bContext *C) return true; } else { - return OBACT != NULL; + return OBACT_NEW != NULL; } } } diff --git a/source/blender/editors/space_console/console_draw.c b/source/blender/editors/space_console/console_draw.c index 6396b390ca0..8055e262611 100644 --- a/source/blender/editors/space_console/console_draw.c +++ b/source/blender/editors/space_console/console_draw.c @@ -40,6 +40,7 @@ #include "MEM_guardedalloc.h" #include "BIF_gl.h" +#include "GPU_immediate.h" #include "UI_interface.h" #include "UI_resources.h" @@ -157,6 +158,8 @@ static int console_textview_line_color(struct TextViewContext *tvc, unsigned cha int offl = 0, offc = 0; int xy[2] = {CONSOLE_DRAW_MARGIN, CONSOLE_DRAW_MARGIN}; int pen[2]; + VertexFormat *format = immVertexFormat(); + unsigned int pos = add_attrib(format, "pos", GL_FLOAT, 2, KEEP_FLOAT); xy[1] += tvc->lheight / 6; console_cursor_wrap_offset(sc->prompt, tvc->console_width, &offl, &offc, NULL); @@ -168,14 +171,17 @@ static int console_textview_line_color(struct TextViewContext *tvc, unsigned cha pen[1] += tvc->lheight * offl; /* cursor */ - UI_GetThemeColor3ubv(TH_CONSOLE_CURSOR, fg); - glColor3ubv(fg); - - glRecti((xy[0] + pen[0]) - 1, - (xy[1] + pen[1]), - (xy[0] + pen[0]) + 1, - (xy[1] + pen[1] + tvc->lheight) - ); + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + immUniformThemeColor(TH_CONSOLE_CURSOR); + + immRectf(pos, + (xy[0] + pen[0]) - 1, + (xy[1] + pen[1]), + (xy[0] + pen[0]) + 1, + (xy[1] + pen[1] + tvc->lheight) + ); + + immUnbindProgram(); } console_line_color(fg, cl_iter->type); diff --git a/source/blender/editors/space_file/file_draw.c b/source/blender/editors/space_file/file_draw.c index 52d01063175..dff32a5f0d5 100644 --- a/source/blender/editors/space_file/file_draw.c +++ b/source/blender/editors/space_file/file_draw.c @@ -71,6 +71,10 @@ #include "WM_api.h" #include "WM_types.h" +//#include "GPU_draw.h" +//#include "GPU_basic_shader.h" +#include "GPU_immediate.h" + #include "filelist.h" #include "file_intern.h" // own include @@ -258,9 +262,10 @@ void file_draw_buttons(const bContext *C, ARegion *ar) static void draw_tile(int sx, int sy, int width, int height, int colorid, int shade) { - UI_ThemeColorShade(colorid, shade); + float color[4]; + UI_GetThemeColorShade4fv(colorid, shade, color); UI_draw_roundbox_corner_set(UI_CNR_ALL); - UI_draw_roundbox((float)sx, (float)(sy - height), (float)(sx + width), (float)sy, 5.0f); + UI_draw_roundbox((float)sx, (float)(sy - height), (float)(sx + width), (float)sy, 5.0f, color); } @@ -285,7 +290,8 @@ static void file_draw_icon(uiBlock *block, const char *path, int sx, int sy, int } -static void file_draw_string(int sx, int sy, const char *string, float width, int height, short align) +static void file_draw_string(int sx, int sy, const char *string, float width, int height, short align, + const unsigned char col[4]) { uiStyle *style; uiFontStyle fs; @@ -310,7 +316,7 @@ static void file_draw_string(int sx, int sy, const char *string, float width, in rect.ymin = sy - height; rect.ymax = sy; - UI_fontstyle_draw(&fs, &rect, fname); + UI_fontstyle_draw(&fs, &rect, fname, col); } void file_calc_previews(const bContext *C, ARegion *ar) @@ -394,8 +400,13 @@ static void file_draw_preview( /* border */ if (use_dropshadow) { - glColor4f(0.0f, 0.0f, 0.0f, 0.4f); - fdrawbox((float)xco, (float)yco, (float)(xco + ex), (float)(yco + ey)); + VertexFormat *format = immVertexFormat(); + unsigned int pos = add_attrib(format, "pos", GL_FLOAT, 2,KEEP_FLOAT); + + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + immUniformColor4f(0.0f, 0.0f, 0.0f, 0.4f); + imm_draw_line_box(pos, (float)xco, (float)yco, (float)(xco + ex), (float)(yco + ey)); + immUnbindProgram(); } but = uiDefBut(block, UI_BTYPE_LABEL, 0, "", xco, yco, ex, ey, NULL, 0.0, 0.0, 0, 0, NULL); @@ -467,33 +478,43 @@ static void draw_dividers(FileLayout *layout, View2D *v2d) const int step = (layout->tile_w + 2 * layout->tile_border_x); int v1[2], v2[2]; int sx; + unsigned int vertex_ct = 0; unsigned char col_hi[3], col_lo[3]; + VertexFormat *format = immVertexFormat(); + unsigned int pos = add_attrib(format, "pos", GL_INT, 2, CONVERT_INT_TO_FLOAT); + unsigned int color = add_attrib(format, "color", GL_UNSIGNED_BYTE, 3, NORMALIZE_INT_TO_FLOAT); + + vertex_ct = (v2d->cur.xmax - v2d->tot.xmin) / step + 1; /* paint at least 1 divider */ + vertex_ct *= 4; /* vertex_count = 2 points per divider * 2 lines per divider */ + UI_GetThemeColorShade3ubv(TH_BACK, 30, col_hi); UI_GetThemeColorShade3ubv(TH_BACK, -30, col_lo); v1[1] = v2d->cur.ymax - layout->tile_border_y; v2[1] = v2d->cur.ymin; - glBegin(GL_LINES); + immBindBuiltinProgram(GPU_SHADER_2D_FLAT_COLOR); + immBegin(GL_LINES, vertex_ct); /* vertical column dividers */ sx = (int)v2d->tot.xmin; while (sx < v2d->cur.xmax) { sx += step; - glColor3ubv(col_lo); v1[0] = v2[0] = sx; - glVertex2iv(v1); - glVertex2iv(v2); + immAttrib3ubv(color, col_lo); + immVertex2iv(pos, v1); + immVertex2iv(pos, v2); - glColor3ubv(col_hi); v1[0] = v2[0] = sx + 1; - glVertex2iv(v1); - glVertex2iv(v2); + immAttrib3ubv(color, col_hi); + immVertex2iv(pos, v1); + immVertex2iv(pos, v2); } - glEnd(); + immEnd(); + immUnbindProgram(); } void file_draw_list(const bContext *C, ARegion *ar) @@ -517,6 +538,7 @@ void file_draw_list(const bContext *C, ARegion *ar) short align; bool do_drag; int column_space = 0.6f * UI_UNIT_X; + unsigned char text_col[4]; const bool small_size = SMALL_SIZE_CHECK(params->thumbnail_size); const bool update_stat_strings = small_size != SMALL_SIZE_CHECK(layout->curr_size); const float thumb_icon_aspect = sqrtf(64.0f / (float)(params->thumbnail_size)); @@ -625,7 +647,7 @@ void file_draw_list(const bContext *C, ARegion *ar) sx += ICON_DEFAULT_WIDTH_SCALE + 0.2f * UI_UNIT_X; } - UI_ThemeColor4(TH_TEXT); + UI_GetThemeColor4ubv(TH_TEXT, text_col); if (file_selflag & FILE_SEL_EDITING) { uiBut *but; @@ -656,7 +678,7 @@ void file_draw_list(const bContext *C, ARegion *ar) if (!(file_selflag& FILE_SEL_EDITING)) { int tpos = (FILE_IMGDISPLAY == params->display) ? sy - layout->tile_h + layout->textheight : sy; - file_draw_string(sx + 1, tpos, file->name, (float)textwidth, textheight, align); + file_draw_string(sx + 1, tpos, file->name, (float)textwidth, textheight, align, text_col); } sx += (int)layout->column_widths[COLUMN_NAME] + column_space; @@ -668,7 +690,8 @@ void file_draw_list(const bContext *C, ARegion *ar) BLI_filelist_entry_size_to_string(NULL, file->entry->size, small_size, file->entry->size_str); } file_draw_string( - sx, sy, file->entry->size_str, layout->column_widths[COLUMN_SIZE], layout->tile_h, align); + sx, sy, file->entry->size_str, layout->column_widths[COLUMN_SIZE], layout->tile_h, + align, text_col); } sx += (int)layout->column_widths[COLUMN_SIZE] + column_space; } @@ -679,10 +702,12 @@ void file_draw_list(const bContext *C, ARegion *ar) NULL, file->entry->time, small_size, file->entry->time_str, file->entry->date_str); } file_draw_string( - sx, sy, file->entry->date_str, layout->column_widths[COLUMN_DATE], layout->tile_h, align); + sx, sy, file->entry->date_str, layout->column_widths[COLUMN_DATE], layout->tile_h, + align, text_col); sx += (int)layout->column_widths[COLUMN_DATE] + column_space; file_draw_string( - sx, sy, file->entry->time_str, layout->column_widths[COLUMN_TIME], layout->tile_h, align); + sx, sy, file->entry->time_str, layout->column_widths[COLUMN_TIME], layout->tile_h, + align, text_col); sx += (int)layout->column_widths[COLUMN_TIME] + column_space; } else { @@ -697,7 +722,8 @@ void file_draw_list(const bContext *C, ARegion *ar) BLI_filelist_entry_size_to_string(NULL, file->entry->size, small_size, file->entry->size_str); } file_draw_string( - sx, sy, file->entry->size_str, layout->column_widths[COLUMN_SIZE], layout->tile_h, align); + sx, sy, file->entry->size_str, layout->column_widths[COLUMN_SIZE], layout->tile_h, + align, text_col); } sx += (int)layout->column_widths[COLUMN_SIZE] + column_space; } diff --git a/source/blender/editors/space_graph/graph_draw.c b/source/blender/editors/space_graph/graph_draw.c index 96a078b2817..9781c909ef6 100644 --- a/source/blender/editors/space_graph/graph_draw.c +++ b/source/blender/editors/space_graph/graph_draw.c @@ -50,6 +50,9 @@ #include "BIF_gl.h" #include "BIF_glutil.h" +#include "GPU_draw.h" +#include "GPU_immediate.h" + #include "ED_anim_api.h" #include "graph_intern.h" @@ -121,16 +124,37 @@ static void draw_fcurve_modifier_controls_envelope(FModifier *fcm, View2D *v2d) /* Points ---------------- */ -/* helper func - draw keyframe vertices only for an F-Curve */ -static void draw_fcurve_vertices_keyframes(FCurve *fcu, SpaceIpo *UNUSED(sipo), View2D *v2d, short edit, short sel) +/* helper func - set color to draw F-Curve data with */ +static void set_fcurve_vertex_color(FCurve *fcu, bool sel) +{ + /* Fade the 'intensity' of the vertices based on the selection of the curves too */ + int alphaOffset = (int)((fcurve_display_alpha(fcu) - 1.0f) * 255); + + float color[4]; + + /* Set color of curve vertex based on state of curve (i.e. 'Edit' Mode) */ + if ((fcu->flag & FCURVE_PROTECTED) == 0) { + /* Curve's points ARE BEING edited */ + UI_GetThemeColorShadeAlpha4fv(sel ? TH_VERTEX_SELECT : TH_VERTEX, 0, alphaOffset, color); + } + else { + /* Curve's points CANNOT BE edited */ + UI_GetThemeColorShadeAlpha4fv(sel ? TH_TEXT_HI : TH_TEXT, 0, alphaOffset, color); + } + + immUniformColor4fv(color); +} + +static void draw_fcurve_selected_keyframe_vertices(FCurve *fcu, View2D *v2d, bool edit, bool sel, unsigned pos) { - BezTriple *bezt = fcu->bezt; const float fac = 0.05f * BLI_rctf_size_x(&v2d->cur); - int i; - - glBegin(GL_POINTS); - - for (i = 0; i < fcu->totvert; i++, bezt++) { + + set_fcurve_vertex_color(fcu, sel); + + immBeginAtMost(GL_POINTS, fcu->totvert); + + BezTriple *bezt = fcu->bezt; + for (int i = 0; i < fcu->totvert; i++, bezt++) { /* as an optimization step, only draw those in view * - we apply a correction factor to ensure that points don't pop in/out due to slight twitches of view size */ @@ -141,80 +165,50 @@ static void draw_fcurve_vertices_keyframes(FCurve *fcu, SpaceIpo *UNUSED(sipo), * - */ if ((bezt->f2 & SELECT) == sel) - glVertex3fv(bezt->vec[1]); + immVertex2fv(pos, bezt->vec[1]); } else { /* no check for selection here, as curve is not editable... */ /* XXX perhaps we don't want to even draw points? maybe add an option for that later */ - glVertex3fv(bezt->vec[1]); + immVertex2fv(pos, bezt->vec[1]); } } } - - glEnd(); -} + immEnd(); +} -/* helper func - draw handle vertex for an F-Curve as a round unfilled circle - * NOTE: the caller MUST HAVE GL_LINE_SMOOTH & GL_BLEND ENABLED, otherwise, the controls don't - * have a consistent appearance (due to off-pixel alignments)... - */ -static void draw_fcurve_handle_control(float x, float y, float xscale, float yscale, float hsize) +/* helper func - draw keyframe vertices only for an F-Curve */ +static void draw_fcurve_keyframe_vertices(FCurve *fcu, View2D *v2d, bool edit, unsigned pos) { - static GLuint displist = 0; - - /* initialize round circle shape */ - if (displist == 0) { - GLUquadricObj *qobj; - - displist = glGenLists(1); - glNewList(displist, GL_COMPILE); - - qobj = gluNewQuadric(); - gluQuadricDrawStyle(qobj, GLU_SILHOUETTE); - gluDisk(qobj, 0, 0.7, 8, 1); - gluDeleteQuadric(qobj); - - glEndList(); - } - - /* adjust view transform before starting */ - glTranslatef(x, y, 0.0f); - glScalef(1.0f / xscale * hsize, 1.0f / yscale * hsize, 1.0f); - - /* draw! */ - glCallList(displist); - - /* restore view transform */ - glScalef(xscale / hsize, yscale / hsize, 1.0); - glTranslatef(-x, -y, 0.0f); + immBindBuiltinProgram(GPU_SHADER_2D_POINT_UNIFORM_SIZE_UNIFORM_COLOR_SMOOTH); + + immUniform1f("size", UI_GetThemeValuef(TH_VERTEX_SIZE) * U.pixelsize); + + draw_fcurve_selected_keyframe_vertices(fcu, v2d, edit, false, pos); + draw_fcurve_selected_keyframe_vertices(fcu, v2d, edit, true, pos); + + immUnbindProgram(); } + /* helper func - draw handle vertices only for an F-Curve (if it is not protected) */ -static void draw_fcurve_vertices_handles(FCurve *fcu, SpaceIpo *sipo, View2D *v2d, short sel, short sel_handle_only, float units_scale) +static void draw_fcurve_selected_handle_vertices(FCurve *fcu, View2D *v2d, bool sel, bool sel_handle_only, unsigned pos) { - BezTriple *bezt = fcu->bezt; - BezTriple *prevbezt = NULL; - float hsize, xscale, yscale; - int i; - - /* get view settings */ - hsize = UI_GetThemeValuef(TH_HANDLE_VERTEX_SIZE) * U.pixelsize; - UI_view2d_scale_get(v2d, &xscale, &yscale); + (void) v2d; /* TODO: use this to draw only points in view */ - /* Compensate OGL scale sued for unit mapping, so circle will be circle, not ellipse */ - yscale *= units_scale; - /* set handle color */ - if (sel) UI_ThemeColor(TH_HANDLE_VERTEX_SELECT); - else UI_ThemeColor(TH_HANDLE_VERTEX); - - /* anti-aliased lines for more consistent appearance */ - if ((sipo->flag & SIPO_BEAUTYDRAW_OFF) == 0) glEnable(GL_LINE_SMOOTH); - glEnable(GL_BLEND); - - for (i = 0; i < fcu->totvert; i++, prevbezt = bezt, bezt++) { - /* Draw the editmode handles for a bezier curve (others don't have handles) + float hcolor[3]; + UI_GetThemeColor3fv(sel ? TH_HANDLE_VERTEX_SELECT : TH_HANDLE_VERTEX, hcolor); + immUniform4f("outlineColor", hcolor[0], hcolor[1], hcolor[2], 1.0f); + immUniformColor3fvAlpha(hcolor, 0.4f); + + immBeginAtMost(GL_POINTS, fcu->totvert * 2); + + BezTriple *bezt = fcu->bezt; + BezTriple *prevbezt = NULL; + for (int i = 0; i < fcu->totvert; i++, prevbezt = bezt, bezt++) { + /* Draw the editmode handles for a bezier curve (others don't have handles) * if their selection status matches the selection status we're drawing for * - first handle only if previous beztriple was bezier-mode * - second handle only if current beztriple is bezier-mode @@ -225,68 +219,61 @@ static void draw_fcurve_vertices_handles(FCurve *fcu, SpaceIpo *sipo, View2D *v2 if (!sel_handle_only || BEZT_ISSEL_ANY(bezt)) { if ((!prevbezt && (bezt->ipo == BEZT_IPO_BEZ)) || (prevbezt && (prevbezt->ipo == BEZT_IPO_BEZ))) { if ((bezt->f1 & SELECT) == sel) /* && v2d->cur.xmin < bezt->vec[0][0] < v2d->cur.xmax)*/ - draw_fcurve_handle_control(bezt->vec[0][0], bezt->vec[0][1], xscale, yscale, hsize); + immVertex2fv(pos, bezt->vec[0]); } - + if (bezt->ipo == BEZT_IPO_BEZ) { if ((bezt->f3 & SELECT) == sel) /* && v2d->cur.xmin < bezt->vec[2][0] < v2d->cur.xmax)*/ - draw_fcurve_handle_control(bezt->vec[2][0], bezt->vec[2][1], xscale, yscale, hsize); + immVertex2fv(pos, bezt->vec[2]); } } } - - if ((sipo->flag & SIPO_BEAUTYDRAW_OFF) == 0) glDisable(GL_LINE_SMOOTH); - glDisable(GL_BLEND); + + immEnd(); } -/* helper func - set color to draw F-Curve data with */ -static void set_fcurve_vertex_color(FCurve *fcu, short sel) +/* helper func - draw handle vertices only for an F-Curve (if it is not protected) */ +static void draw_fcurve_handle_vertices(FCurve *fcu, View2D *v2d, bool sel_handle_only, unsigned pos) { - /* Fade the 'intensity' of the vertices based on the selection of the curves too */ - int alphaOffset = (int)((fcurve_display_alpha(fcu) - 1.0f) * 255); - - /* Set color of curve vertex based on state of curve (i.e. 'Edit' Mode) */ - if ((fcu->flag & FCURVE_PROTECTED) == 0) { - /* Curve's points ARE BEING edited */ - if (sel) UI_ThemeColorShadeAlpha(TH_VERTEX_SELECT, 0, alphaOffset); - else UI_ThemeColorShadeAlpha(TH_VERTEX, 0, alphaOffset); - } - else { - /* Curve's points CANNOT BE edited */ - if (sel) UI_ThemeColorShadeAlpha(TH_TEXT_HI, 0, alphaOffset); - else UI_ThemeColorShadeAlpha(TH_TEXT, 0, alphaOffset); - } + /* smooth outlines for more consistent appearance */ + immBindBuiltinProgram(GPU_SHADER_2D_POINT_UNIFORM_SIZE_UNIFORM_COLOR_OUTLINE_SMOOTH); + + /* set handle size */ + immUniform1f("size", (UI_GetThemeValuef(TH_HANDLE_VERTEX_SIZE) + 1.0f) * U.pixelsize); + immUniform1f("outlineWidth", 1.0f * U.pixelsize); + + draw_fcurve_selected_handle_vertices(fcu, v2d, false, sel_handle_only, pos); + draw_fcurve_selected_handle_vertices(fcu, v2d, true, sel_handle_only, pos); + + immUnbindProgram(); } -static void draw_fcurve_vertices(SpaceIpo *sipo, ARegion *ar, FCurve *fcu, short do_handles, short sel_handle_only, float units_scale) +static void draw_fcurve_vertices(ARegion *ar, FCurve *fcu, bool do_handles, bool sel_handle_only) { View2D *v2d = &ar->v2d; - + /* only draw points if curve is visible - * - draw unselected points before selected points as separate passes to minimize color-changing overhead - * (XXX dunno if this is faster than drawing all in one pass though) - * and also to make sure in the case of overlapping points that the selected is always visible + * - draw unselected points before selected points as separate passes + * to make sure in the case of overlapping points that the selected is always visible * - draw handles before keyframes, so that keyframes will overlap handles (keyframes are more important for users) */ - - glPointSize(UI_GetThemeValuef(TH_VERTEX_SIZE)); - + + unsigned pos = add_attrib(immVertexFormat(), "pos", GL_FLOAT, 2, KEEP_FLOAT); + + glEnable(GL_BLEND); + GPU_enable_program_point_size(); + /* draw the two handles first (if they're shown, the curve doesn't have just a single keyframe, and the curve is being edited) */ if (do_handles) { - set_fcurve_vertex_color(fcu, 0); - draw_fcurve_vertices_handles(fcu, sipo, v2d, 0, sel_handle_only, units_scale); - - set_fcurve_vertex_color(fcu, 1); - draw_fcurve_vertices_handles(fcu, sipo, v2d, 1, sel_handle_only, units_scale); + draw_fcurve_handle_vertices(fcu, v2d, sel_handle_only, pos); } - + /* draw keyframes over the handles */ - set_fcurve_vertex_color(fcu, 0); - draw_fcurve_vertices_keyframes(fcu, sipo, v2d, !(fcu->flag & FCURVE_PROTECTED), 0); - - set_fcurve_vertex_color(fcu, 1); - draw_fcurve_vertices_keyframes(fcu, sipo, v2d, !(fcu->flag & FCURVE_PROTECTED), 1); + draw_fcurve_keyframe_vertices(fcu, v2d, !(fcu->flag & FCURVE_PROTECTED), pos); + + GPU_disable_program_point_size(); + glDisable(GL_BLEND); } /* Handles ---------------- */ @@ -303,10 +290,10 @@ static bool draw_fcurve_handles_check(SpaceIpo *sipo, FCurve *fcu) (fcu->totvert <= 1) /* do not show handles if there is only 1 keyframe, otherwise they all clump together in an ugly ball */ ) { - return 0; + return false; } else { - return 1; + return true; } } @@ -1080,7 +1067,7 @@ void graph_draw_curves(bAnimContext *ac, SpaceIpo *sipo, ARegion *ar, View2DGrid glDisable(GL_BLEND); } - draw_fcurve_vertices(sipo, ar, fcu, do_handles, (sipo->flag & SIPO_SELVHANDLESONLY), unit_scale); + draw_fcurve_vertices(ar, fcu, do_handles, (sipo->flag & SIPO_SELVHANDLESONLY)); } else { /* samples: only draw two indicators at either end as indicators */ diff --git a/source/blender/editors/space_graph/space_graph.c b/source/blender/editors/space_graph/space_graph.c index f12db310856..70d3fad9554 100644 --- a/source/blender/editors/space_graph/space_graph.c +++ b/source/blender/editors/space_graph/space_graph.c @@ -53,7 +53,7 @@ #include "ED_anim_api.h" #include "ED_markers.h" -#include "BIF_gl.h" +#include "GPU_immediate.h" #include "WM_api.h" #include "WM_types.h" @@ -265,43 +265,52 @@ static void graph_main_region_draw(const bContext *C, ARegion *ar) /* only free grid after drawing data, as we need to use it to determine sampling rate */ UI_view2d_grid_free(grid); - - /* horizontal component of value-cursor (value line before the current frame line) */ - if ((sipo->flag & SIPO_NODRAWCURSOR) == 0) { - float y = sipo->cursorVal; - - /* Draw a green line to indicate the cursor value */ - UI_ThemeColorShadeAlpha(TH_CFRAME, -10, -50); - glEnable(GL_BLEND); - glLineWidth(2.0); + if (((sipo->flag & SIPO_NODRAWCURSOR) == 0) || (sipo->mode == SIPO_MODE_DRIVERS)) { + unsigned pos = add_attrib(immVertexFormat(), "pos", GL_FLOAT, 2, KEEP_FLOAT); - glBegin(GL_LINES); - glVertex2f(v2d->cur.xmin, y); - glVertex2f(v2d->cur.xmax, y); - glEnd(); + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); - glDisable(GL_BLEND); - } - - /* current frame or vertical component of vertical component of the cursor */ - if (sipo->mode == SIPO_MODE_DRIVERS) { - /* cursor x-value */ - float x = sipo->cursorTime; - - /* to help differentiate this from the current frame, draw slightly darker like the horizontal one */ - UI_ThemeColorShadeAlpha(TH_CFRAME, -40, -50); - glEnable(GL_BLEND); - glLineWidth(2.0); - - glBegin(GL_LINES); - glVertex2f(x, v2d->cur.ymin); - glVertex2f(x, v2d->cur.ymax); - glEnd(); + /* horizontal component of value-cursor (value line before the current frame line) */ + if ((sipo->flag & SIPO_NODRAWCURSOR) == 0) { + + float y = sipo->cursorVal; + + /* Draw a green line to indicate the cursor value */ + immUniformThemeColorShadeAlpha(TH_CFRAME, -10, -50); + glEnable(GL_BLEND); + glLineWidth(2.0); + + immBegin(GL_LINES, 2); + immVertex2f(pos, v2d->cur.xmin, y); + immVertex2f(pos, v2d->cur.xmax, y); + immEnd(); - glDisable(GL_BLEND); + glDisable(GL_BLEND); + } + + /* current frame or vertical component of vertical component of the cursor */ + if (sipo->mode == SIPO_MODE_DRIVERS) { + /* cursor x-value */ + float x = sipo->cursorTime; + + /* to help differentiate this from the current frame, draw slightly darker like the horizontal one */ + immUniformThemeColorShadeAlpha(TH_CFRAME, -40, -50); + glEnable(GL_BLEND); + glLineWidth(2.0); + + immBegin(GL_LINES, 2); + immVertex2f(pos, x, v2d->cur.ymin); + immVertex2f(pos, x, v2d->cur.ymax); + immEnd(); + + glDisable(GL_BLEND); + } + + immUnbindProgram(); } - else { + + if (sipo->mode != SIPO_MODE_DRIVERS) { /* current frame */ if (sipo->flag & SIPO_DRAWTIME) flag |= DRAWCFRA_UNIT_SECONDS; if ((sipo->flag & SIPO_NODRAWCFRANUM) == 0) flag |= DRAWCFRA_SHOW_NUMBOX; diff --git a/source/blender/editors/space_image/image_draw.c b/source/blender/editors/space_image/image_draw.c index e810f4db7dd..dd575619c0f 100644 --- a/source/blender/editors/space_image/image_draw.c +++ b/source/blender/editors/space_image/image_draw.c @@ -718,39 +718,6 @@ void draw_image_sample_line(SpaceImage *sima) } } -/* XXX becomes WM paint cursor */ -#if 0 -static void draw_image_view_tool(Scene *scene) -{ - ToolSettings *settings = scene->toolsettings; - Brush *brush = settings->imapaint.brush; - int mval[2]; - float radius; - int draw = 0; - - if (brush) { - if (settings->imapaint.flag & IMAGEPAINT_DRAWING) { - if (settings->imapaint.flag & IMAGEPAINT_DRAW_TOOL_DRAWING) - draw = 1; - } - else if (settings->imapaint.flag & IMAGEPAINT_DRAW_TOOL) - draw = 1; - - if (draw) { - getmouseco_areawin(mval); - - radius = BKE_brush_size_get(brush) * G.sima->zoom; - fdrawXORcirc(mval[0], mval[1], radius); - - if (brush->innerradius != 1.0) { - radius *= brush->innerradius; - fdrawXORcirc(mval[0], mval[1], radius); - } - } - } -} -#endif - static unsigned char *get_alpha_clone_image(const bContext *C, Scene *scene, int *width, int *height) { Brush *brush = BKE_paint_brush(&scene->toolsettings->imapaint.paint); diff --git a/source/blender/editors/space_image/space_image.c b/source/blender/editors/space_image/space_image.c index 6ddf78290aa..22b70e04397 100644 --- a/source/blender/editors/space_image/space_image.c +++ b/source/blender/editors/space_image/space_image.c @@ -687,6 +687,7 @@ static void image_main_region_draw(const bContext *C, ARegion *ar) Mask *mask = NULL; bool curve = false; Scene *scene = CTX_data_scene(C); + SceneLayer *sl = CTX_data_scene_layer(C); View2D *v2d = &ar->v2d; //View2DScrollers *scrollers; float col[3]; @@ -722,7 +723,7 @@ static void image_main_region_draw(const bContext *C, ARegion *ar) ED_region_draw_cb_draw(C, ar, REGION_DRAW_PRE_VIEW); - ED_uvedit_draw_main(sima, ar, scene, obedit, obact); + ED_uvedit_draw_main(sima, ar, scene, sl, obedit, obact); /* check for mask (delay draw) */ if (ED_space_image_show_uvedit(sima, obedit)) { diff --git a/source/blender/editors/space_info/info_stats.c b/source/blender/editors/space_info/info_stats.c index 8dc6c4229b2..435d9b2ee26 100644 --- a/source/blender/editors/space_info/info_stats.c +++ b/source/blender/editors/space_info/info_stats.c @@ -269,9 +269,9 @@ static void stats_object_sculpt_dynamic_topology(Object *ob, SceneStats *stats) stats->tottri = ob->sculpt->bm->totface; } -static void stats_dupli_object(Base *base, Object *ob, SceneStats *stats) +static void stats_dupli_object(BaseLegacy *base, Object *ob, SceneStats *stats) { - if (base->flag & SELECT) stats->totobjsel++; + if (base->flag_legacy & SELECT) stats->totobjsel++; if (ob->transflag & OB_DUPLIPARTS) { /* Dupli Particles */ @@ -300,7 +300,7 @@ static void stats_dupli_object(Base *base, Object *ob, SceneStats *stats) } } - stats_object(ob, base->flag & SELECT, 1, stats); + stats_object(ob, base->flag_legacy & SELECT, 1, stats); stats->totobj++; } else if (ob->parent && (ob->parent->transflag & (OB_DUPLIVERTS | OB_DUPLIFACES))) { @@ -316,23 +316,23 @@ static void stats_dupli_object(Base *base, Object *ob, SceneStats *stats) } stats->totobj += tot; - stats_object(ob, base->flag & SELECT, tot, stats); + stats_object(ob, base->flag_legacy & SELECT, tot, stats); } else if (ob->transflag & OB_DUPLIFRAMES) { /* Dupli Frames */ int tot = count_duplilist(ob); stats->totobj += tot; - stats_object(ob, base->flag & SELECT, tot, stats); + stats_object(ob, base->flag_legacy & SELECT, tot, stats); } else if ((ob->transflag & OB_DUPLIGROUP) && ob->dup_group) { /* Dupli Group */ int tot = count_duplilist(ob); stats->totobj += tot; - stats_object(ob, base->flag & SELECT, tot, stats); + stats_object(ob, base->flag_legacy & SELECT, tot, stats); } else { /* No Dupli */ - stats_object(ob, base->flag & SELECT, 1, stats); + stats_object(ob, base->flag_legacy & SELECT, 1, stats); stats->totobj++; } } @@ -348,7 +348,7 @@ static void stats_update(Scene *scene) { SceneStats stats = {0}; Object *ob = (scene->basact) ? scene->basact->object : NULL; - Base *base; + BaseLegacy *base; if (scene->obedit) { /* Edit Mode */ diff --git a/source/blender/editors/space_info/textview.c b/source/blender/editors/space_info/textview.c index c801a736e31..8ee488ac591 100644 --- a/source/blender/editors/space_info/textview.c +++ b/source/blender/editors/space_info/textview.c @@ -39,6 +39,8 @@ #include "BLI_utildefines.h" #include "BLI_string_utf8.h" +#include "GPU_immediate.h" + #include "BIF_gl.h" #include "BKE_text.h" @@ -81,9 +83,15 @@ static void console_draw_sel(const char *str, const int sel[2], const int xy[2], glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - glColor4ubv(bg_sel); - glRecti(xy[0] + (cwidth * sta), xy[1] - 2 + lheight, xy[0] + (cwidth * end), xy[1] - 2); + VertexFormat *format = immVertexFormat(); + unsigned pos = add_attrib(format, "pos", GL_INT, 2, CONVERT_INT_TO_FLOAT); + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + + immUniformColor4ubv(bg_sel); + immRecti(pos, xy[0] + (cwidth * sta), xy[1] - 2 + lheight, xy[0] + (cwidth * end), xy[1] - 2); + + immUnbindProgram(); glDisable(GL_BLEND); } @@ -182,21 +190,25 @@ static int console_draw_string(ConsoleDrawContext *cdc, const char *str, int str cdc->sel[1] = str_len - sel_orig[0]; if (bg) { - glColor3ubv(bg); - glRecti(0, cdc->xy[1], cdc->winx, (cdc->xy[1] + (cdc->lheight * tot_lines))); - } + VertexFormat *format = immVertexFormat(); + unsigned pos = add_attrib(format, "pos", GL_INT, 2, CONVERT_INT_TO_FLOAT); + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); - glColor3ubv(fg); + immUniformColor3ubv(bg); + immRecti(pos, 0, cdc->xy[1], cdc->winx, (cdc->xy[1] + (cdc->lheight * tot_lines))); + + immUnbindProgram(); + } /* last part needs no clipping */ BLF_position(cdc->font_id, cdc->xy[0], cdc->lofs + cdc->xy[1], 0); + BLF_color3ubv(cdc->font_id, fg); BLF_draw_mono(cdc->font_id, s, len, cdc->cwidth); if (cdc->sel[0] != cdc->sel[1]) { console_step_sel(cdc, -initial_offset); // glColor4ub(255, 0, 0, 96); // debug console_draw_sel(s, cdc->sel, cdc->xy, len, cdc->cwidth, cdc->lheight, bg_sel); - glColor3ubv(fg); } cdc->xy[1] += cdc->lheight; @@ -212,7 +224,6 @@ static int console_draw_string(ConsoleDrawContext *cdc, const char *str, int str console_step_sel(cdc, len); // glColor4ub(0, 255, 0, 96); // debug console_draw_sel(s, cdc->sel, cdc->xy, len, cdc->cwidth, cdc->lheight, bg_sel); - glColor3ubv(fg); } cdc->xy[1] += cdc->lheight; @@ -230,11 +241,15 @@ static int console_draw_string(ConsoleDrawContext *cdc, const char *str, int str else { /* simple, no wrap */ if (bg) { - glColor3ubv(bg); - glRecti(0, cdc->xy[1], cdc->winx, cdc->xy[1] + cdc->lheight); - } + VertexFormat *format = immVertexFormat(); + unsigned pos = add_attrib(format, "pos", GL_INT, 2, CONVERT_INT_TO_FLOAT); + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); - glColor3ubv(fg); + immUniformColor3ubv(bg); + immRecti(pos, 0, cdc->xy[1], cdc->winx, cdc->xy[1] + cdc->lheight); + + immUnbindProgram(); + } BLF_position(cdc->font_id, cdc->xy[0], cdc->lofs + cdc->xy[1], 0); BLF_draw_mono(cdc->font_id, str, str_len, cdc->cwidth); diff --git a/source/blender/editors/space_logic/logic_window.c b/source/blender/editors/space_logic/logic_window.c index 3de44174d6a..f1a08a45c29 100644 --- a/source/blender/editors/space_logic/logic_window.c +++ b/source/blender/editors/space_logic/logic_window.c @@ -460,7 +460,7 @@ static void set_sca_ob(Object *ob) static ID **get_selected_and_linked_obs(bContext *C, short *count, short scavisflag) { - Base *base; + BaseLegacy *base; Main *bmain= CTX_data_main(C); Scene *scene= CTX_data_scene(C); Object *ob, *obt, *obact= CTX_data_active_object(C); @@ -491,7 +491,7 @@ static ID **get_selected_and_linked_obs(bContext *C, short *count, short scavisf base= FIRSTBASE; while (base) { if (base->lay & lay) { - if (base->flag & SELECT) { + if (base->flag_legacy & SELECT) { if (scavisflag & BUTS_SENS_SEL) base->object->scavisflag |= OB_VIS_SENS; if (scavisflag & BUTS_CONT_SEL) base->object->scavisflag |= OB_VIS_CONT; if (scavisflag & BUTS_ACT_SEL) base->object->scavisflag |= OB_VIS_ACT; diff --git a/source/blender/editors/space_nla/nla_channels.c b/source/blender/editors/space_nla/nla_channels.c index e9c46e9d04b..48e822ef876 100644 --- a/source/blender/editors/space_nla/nla_channels.c +++ b/source/blender/editors/space_nla/nla_channels.c @@ -45,6 +45,7 @@ #include "BKE_nla.h" #include "BKE_context.h" #include "BKE_global.h" +#include "BKE_scene.h" #include "BKE_screen.h" #include "BKE_report.h" @@ -125,7 +126,7 @@ static int mouse_nla_channels(bContext *C, bAnimContext *ac, float x, int channe { bDopeSheet *ads = (bDopeSheet *)ac->data; Scene *sce = (Scene *)ads->source; - Base *base = (Base *)ale->data; + BaseLegacy *base = (BaseLegacy *)ale->data; Object *ob = base->object; AnimData *adt = ob->adt; @@ -133,24 +134,24 @@ static int mouse_nla_channels(bContext *C, bAnimContext *ac, float x, int channe /* set selection status */ if (selectmode == SELECT_INVERT) { /* swap select */ - base->flag ^= SELECT; - ob->flag = base->flag; + base->flag_legacy ^= SELECT; + BKE_scene_base_flag_sync_from_base(base); if (adt) adt->flag ^= ADT_UI_SELECTED; } else { - Base *b; + BaseLegacy *b; /* deselect all */ /* TODO: should this deselect all other types of channels too? */ for (b = sce->base.first; b; b = b->next) { - b->flag &= ~SELECT; - b->object->flag = b->flag; + b->flag_legacy &= ~SELECT; + BKE_scene_base_flag_sync_from_base(b); if (b->object->adt) b->object->adt->flag &= ~(ADT_UI_SELECTED | ADT_UI_ACTIVE); } /* select object now */ - base->flag |= SELECT; + base->flag_legacy |= SELECT; ob->flag |= SELECT; if (adt) adt->flag |= ADT_UI_SELECTED; } diff --git a/source/blender/editors/space_nla/nla_draw.c b/source/blender/editors/space_nla/nla_draw.c index 5b3c062e16d..e744a39fde9 100644 --- a/source/blender/editors/space_nla/nla_draw.c +++ b/source/blender/editors/space_nla/nla_draw.c @@ -1,3 +1,4 @@ + /* * ***** BEGIN GPL LICENSE BLOCK ***** * @@ -53,9 +54,11 @@ #include "ED_anim_api.h" #include "ED_keyframes_draw.h" -#include "BIF_gl.h" #include "BIF_glutil.h" +#include "GPU_immediate.h" +#include "GPU_draw.h" + #include "WM_types.h" #include "UI_interface.h" @@ -97,50 +100,68 @@ void nla_action_get_color(AnimData *adt, bAction *act, float color[4]) } /* draw the keyframes in the specified Action */ -static void nla_action_draw_keyframes(AnimData *adt, bAction *act, View2D *v2d, float y, float ymin, float ymax) +static void nla_action_draw_keyframes(AnimData *adt, bAction *act, float y, float ymin, float ymax) { - DLRBT_Tree keys; - ActKeyColumn *ak; - float xscale, f1, f2; - float color[4]; - /* get a list of the keyframes with NLA-scaling applied */ + DLRBT_Tree keys; BLI_dlrbTree_init(&keys); action_to_keylist(adt, act, &keys, NULL); BLI_dlrbTree_linkedlist_sync(&keys); - - if (ELEM(NULL, act, keys.first)) + + if (!(act && keys.first)) return; - + /* draw a darkened region behind the strips * - get and reset the background color, this time without the alpha to stand out better * (amplified alpha is used instead) */ + float color[4]; nla_action_get_color(adt, act, color); color[3] *= 2.5f; - - glColor4fv(color); + + VertexFormat *format = immVertexFormat(); + unsigned int pos_id = add_attrib(format, "pos", COMP_F32, 2, KEEP_FLOAT); + + immUniformColor4fv(color); + /* - draw a rect from the first to the last frame (no extra overlaps for now) * that is slightly stumpier than the track background (hardcoded 2-units here) */ - f1 = ((ActKeyColumn *)keys.first)->cfra; - f2 = ((ActKeyColumn *)keys.last)->cfra; - - glRectf(f1, ymin + 2, f2, ymax - 2); - - - /* get View2D scaling factor */ - UI_view2d_scale_get(v2d, &xscale, NULL); - - /* for now, color is hardcoded to be black */ - glColor3f(0.0f, 0.0f, 0.0f); - - /* just draw each keyframe as a simple dot (regardless of the selection status) - * - size is 3.0f which is smaller than the editable keyframes, so that there is a distinction - */ - for (ak = keys.first; ak; ak = ak->next) - draw_keyframe_shape(ak->cfra, y, xscale, 3.0f, 0, ak->key_type, KEYFRAME_SHAPE_FRAME, 1.0f); - + float f1 = ((ActKeyColumn *)keys.first)->cfra; + float f2 = ((ActKeyColumn *)keys.last)->cfra; + + immRectf(pos_id, f1, ymin + 2, f2, ymax - 2); + immUnbindProgram(); + + /* count keys before drawing */ + unsigned int key_ct = 0; + for (ActKeyColumn *ak = keys.first; ak; ak = ak->next) { + key_ct++; + } + + if (key_ct > 0) { + format = immVertexFormat(); + pos_id = add_attrib(format, "pos", COMP_F32, 2, KEEP_FLOAT); + unsigned int size_id = add_attrib(format, "size", COMP_F32, 1, KEEP_FLOAT); + unsigned int color_id = add_attrib(format, "color", COMP_U8, 4, NORMALIZE_INT_TO_FLOAT); + unsigned int outline_color_id = add_attrib(format, "outlineColor", COMP_U8, 4, NORMALIZE_INT_TO_FLOAT); + immBindBuiltinProgram(GPU_SHADER_KEYFRAME_DIAMOND); + GPU_enable_program_point_size(); + immBegin(PRIM_POINTS, key_ct); + + /* - disregard the selection status of keyframes so they draw a certain way + * - size is 3.0f which is smaller than the editable keyframes, so that there is a distinction + */ + for (ActKeyColumn *ak = keys.first; ak; ak = ak->next) { + draw_keyframe_shape(ak->cfra, y, 3.0f, false, ak->key_type, KEYFRAME_SHAPE_FRAME, 1.0f, + pos_id, size_id, color_id, outline_color_id); + } + + immEnd(); + GPU_disable_program_point_size(); + immUnbindProgram(); + } + /* free icons */ BLI_dlrbTree_free(&keys); } @@ -148,57 +169,55 @@ static void nla_action_draw_keyframes(AnimData *adt, bAction *act, View2D *v2d, /* Strip Markers ------------------------ */ /* Markers inside an action strip */ -static void nla_actionclip_draw_markers(NlaStrip *strip, float yminc, float ymaxc) +static void nla_actionclip_draw_markers(NlaStrip *strip, float yminc, float ymaxc, int shade, unsigned int pos) { - bAction *act = strip->act; - TimeMarker *marker; - - if (ELEM(NULL, strip->act, strip->act->markers.first)) + const bAction *act = strip->act; + + if (!(act && act->markers.first)) return; - - for (marker = act->markers.first; marker; marker = marker->next) { + + immUniformThemeColorShade(TH_STRIP_SELECT, shade); + + immBeginAtMost(PRIM_POINTS, BLI_listbase_count(&act->markers)); + for (TimeMarker *marker = act->markers.first; marker; marker = marker->next) { if ((marker->frame > strip->actstart) && (marker->frame < strip->actend)) { float frame = nlastrip_get_frame(strip, marker->frame, NLATIME_CONVERT_MAP); - + /* just a simple line for now */ - // XXX: draw a triangle instead... - fdrawline(frame, yminc + 1, frame, ymaxc - 1); + /* XXX: draw a triangle instead... */ + immVertex2f(pos, frame, yminc + 1); + immVertex2f(pos, frame, ymaxc - 1); } } + immEnd(); } /* Markers inside a NLA-Strip */ -static void nla_strip_draw_markers(NlaStrip *strip, float yminc, float ymaxc) +static void nla_strip_draw_markers(NlaStrip *strip, float yminc, float ymaxc, unsigned int pos) { - glLineWidth(2.0); + glLineWidth(2.0f); if (strip->type == NLASTRIP_TYPE_CLIP) { /* try not to be too conspicuous, while being visible enough when transforming */ - if (strip->flag & NLASTRIP_FLAG_SELECT) - UI_ThemeColorShade(TH_STRIP_SELECT, -60); - else - UI_ThemeColorShade(TH_STRIP_SELECT, -40); - + int shade = (strip->flag & NLASTRIP_FLAG_SELECT) ? -60 : -40; + setlinestyle(3); /* just draw the markers in this clip */ - nla_actionclip_draw_markers(strip, yminc, ymaxc); + nla_actionclip_draw_markers(strip, yminc, ymaxc, shade, pos); setlinestyle(0); } else if (strip->flag & NLASTRIP_FLAG_TEMP_META) { /* just a solid color, so that it is very easy to spot */ - UI_ThemeColorShade(TH_STRIP_SELECT, 20); - + int shade = 20; /* draw the markers in the first level of strips only (if they are actions) */ for (NlaStrip *nls = strip->strips.first; nls; nls = nls->next) { if (nls->type == NLASTRIP_TYPE_CLIP) { - nla_actionclip_draw_markers(nls, yminc, ymaxc); + nla_actionclip_draw_markers(nls, yminc, ymaxc, shade, pos); } } } - - glLineWidth(1.0); } /* Strips (Proper) ---------------------- */ @@ -266,15 +285,12 @@ static void nla_strip_get_color_inside(AnimData *adt, NlaStrip *strip, float col } /* helper call for drawing influence/time control curves for a given NLA-strip */ -static void nla_draw_strip_curves(NlaStrip *strip, float yminc, float ymaxc) +static void nla_draw_strip_curves(NlaStrip *strip, float yminc, float ymaxc, unsigned int pos) { + immUniformColor4f(0.7f, 0.7f, 0.7f, 1.0f); + const float yheight = ymaxc - yminc; - - /* drawing color is simply a light-gray */ - // TODO: is this color suitable? - // XXX nasty hacked color for now... which looks quite bad too... - glColor3f(0.7f, 0.7f, 0.7f); - + /* draw with AA'd line */ glEnable(GL_LINE_SMOOTH); glEnable(GL_BLEND); @@ -285,42 +301,43 @@ static void nla_draw_strip_curves(NlaStrip *strip, float yminc, float ymaxc) float cfra; /* plot the curve (over the strip's main region) */ - glBegin(GL_LINE_STRIP); + immBegin(GL_LINE_STRIP, abs((int)(strip->end - strip->start) + 1)); + /* sample at 1 frame intervals, and draw * - min y-val is yminc, max is y-maxc, so clamp in those regions */ for (cfra = strip->start; cfra <= strip->end; cfra += 1.0f) { - float y = evaluate_fcurve(fcu, cfra); // assume this to be in 0-1 range - glVertex2f(cfra, ((y * yheight) + yminc)); + float y = evaluate_fcurve(fcu, cfra); /* assume this to be in 0-1 range */ + immVertex2f(pos, cfra, ((y * yheight) + yminc)); } - glEnd(); // GL_LINE_STRIP + + immEnd(); } else { /* use blend in/out values only if both aren't zero */ if ((IS_EQF(strip->blendin, 0.0f) && IS_EQF(strip->blendout, 0.0f)) == 0) { - glBegin(GL_LINE_STRIP); + immBeginAtMost(GL_LINE_STRIP, 4); + /* start of strip - if no blendin, start straight at 1, otherwise from 0 to 1 over blendin frames */ if (IS_EQF(strip->blendin, 0.0f) == 0) { - glVertex2f(strip->start, yminc); - glVertex2f(strip->start + strip->blendin, ymaxc); + immVertex2f(pos, strip->start, yminc); + immVertex2f(pos, strip->start + strip->blendin, ymaxc); } else - glVertex2f(strip->start, ymaxc); + immVertex2f(pos, strip->start, ymaxc); /* end of strip */ if (IS_EQF(strip->blendout, 0.0f) == 0) { - glVertex2f(strip->end - strip->blendout, ymaxc); - glVertex2f(strip->end, yminc); + immVertex2f(pos, strip->end - strip->blendout, ymaxc); + immVertex2f(pos, strip->end, yminc); } else - glVertex2f(strip->end, ymaxc); - glEnd(); // GL_LINE_STRIP + immVertex2f(pos, strip->end, ymaxc); + + immEnd(); } } - - /* time -------------------------- */ - // XXX do we want to draw this curve? in a different color too? - + /* turn off AA'd lines */ glDisable(GL_LINE_SMOOTH); glDisable(GL_BLEND); @@ -330,11 +347,14 @@ static void nla_draw_strip_curves(NlaStrip *strip, float yminc, float ymaxc) static void nla_draw_strip(SpaceNla *snla, AnimData *adt, NlaTrack *nlt, NlaStrip *strip, View2D *v2d, float yminc, float ymaxc) { const bool non_solo = ((adt && (adt->flag & ADT_NLA_SOLO_TRACK)) && (nlt->flag & NLATRACK_SOLO) == 0); - float color[3]; - + float color[4] = {1.0f, 1.0f, 1.0f, 1.0f}; + /* get color of strip */ nla_strip_get_color_inside(adt, strip, color); - + + unsigned int pos = add_attrib(immVertexFormat(), "pos", COMP_F32, 2, KEEP_FLOAT); + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + /* draw extrapolation info first (as backdrop) * - but this should only be drawn if track has some contribution */ @@ -342,7 +362,7 @@ static void nla_draw_strip(SpaceNla *snla, AnimData *adt, NlaTrack *nlt, NlaStri /* enable transparency... */ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glEnable(GL_BLEND); - + switch (strip->extendmode) { /* since this does both sides, only do the 'before' side, and leave the rest to the next case */ case NLASTRIP_EXTEND_HOLD: @@ -351,15 +371,10 @@ static void nla_draw_strip(SpaceNla *snla, AnimData *adt, NlaTrack *nlt, NlaStri */ if (strip->prev == NULL) { /* set the drawing color to the color of the strip, but with very faint alpha */ - glColor4f(color[0], color[1], color[2], 0.15f); - + immUniformColor3fvAlpha(color, 0.15f); + /* draw the rect to the edge of the screen */ - glBegin(GL_QUADS); - glVertex2f(v2d->cur.xmin, yminc); - glVertex2f(v2d->cur.xmin, ymaxc); - glVertex2f(strip->start, ymaxc); - glVertex2f(strip->start, yminc); - glEnd(); + immRectf(pos, v2d->cur.xmin, yminc, strip->start, ymaxc); } /* fall-through */ @@ -368,118 +383,132 @@ static void nla_draw_strip(SpaceNla *snla, AnimData *adt, NlaTrack *nlt, NlaStri /* only need to try and draw if the next strip doesn't occur immediately after */ if ((strip->next == NULL) || (IS_EQF(strip->next->start, strip->end) == 0)) { /* set the drawing color to the color of the strip, but this time less faint */ - glColor4f(color[0], color[1], color[2], 0.3f); + immUniformColor3fvAlpha(color, 0.3f); /* draw the rect to the next strip or the edge of the screen */ - glBegin(GL_QUADS); - glVertex2f(strip->end, yminc); - glVertex2f(strip->end, ymaxc); - - if (strip->next) { - glVertex2f(strip->next->start, ymaxc); - glVertex2f(strip->next->start, yminc); - } - else { - glVertex2f(v2d->cur.xmax, ymaxc); - glVertex2f(v2d->cur.xmax, yminc); - } - glEnd(); + float x2 = strip->next ? strip->next->start : v2d->cur.xmax; + immRectf(pos, strip->end, yminc, x2, ymaxc); } break; } - + glDisable(GL_BLEND); } - - + + /* draw 'inside' of strip itself */ if (non_solo == 0) { + immUnbindProgram(); + /* strip is in normal track */ - glColor3fv(color); UI_draw_roundbox_corner_set(UI_CNR_ALL); /* all corners rounded */ - - UI_draw_roundbox_shade_x(GL_POLYGON, strip->start, yminc, strip->end, ymaxc, 0.0, 0.5, 0.1); + UI_draw_roundbox_shade_x(GL_TRIANGLE_FAN, strip->start, yminc, strip->end, ymaxc, 0.0, 0.5, 0.1, color); + + /* restore current vertex format & program (roundbox trashes it) */ + pos = add_attrib(immVertexFormat(), "pos", COMP_F32, 2, KEEP_FLOAT); + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); } else { /* strip is in disabled track - make less visible */ - glColor4f(color[0], color[1], color[2], 0.1f); + immUniformColor3fvAlpha(color, 0.1f); glEnable(GL_BLEND); - glRectf(strip->start, yminc, strip->end, ymaxc); + immRectf(pos, strip->start, yminc, strip->end, ymaxc); glDisable(GL_BLEND); } - - + + /* draw strip's control 'curves' * - only if user hasn't hidden them... */ if ((snla->flag & SNLA_NOSTRIPCURVES) == 0) - nla_draw_strip_curves(strip, yminc, ymaxc); - - + nla_draw_strip_curves(strip, yminc, ymaxc, pos); + + /* draw markings indicating locations of local markers (useful for lining up different actions) */ if ((snla->flag & SNLA_NOLOCALMARKERS) == 0) - nla_strip_draw_markers(strip, yminc, ymaxc); - - /* draw strip outline + nla_strip_draw_markers(strip, yminc, ymaxc, pos); + + immUnbindProgram(); + + /* draw strip outline * - color used here is to indicate active vs non-active */ if (strip->flag & NLASTRIP_FLAG_ACTIVE) { /* strip should appear 'sunken', so draw a light border around it */ - glColor3f(0.9f, 1.0f, 0.9f); // FIXME: hardcoded temp-hack colors + color[0] = 0.9f; /* FIXME: hardcoded temp-hack colors */ + color[1] = 1.0f; + color[2] = 0.9f; } else { /* strip should appear to stand out, so draw a dark border around it */ - glColor3f(0.0f, 0.0f, 0.0f); + color[0] = color[1] = color[2] = 0.0f; /* FIXME: or 1.0f ?? */ } - + /* - line style: dotted for muted */ if ((nlt->flag & NLATRACK_MUTED) || (strip->flag & NLASTRIP_FLAG_MUTED)) setlinestyle(4); - + /* draw outline */ - UI_draw_roundbox_shade_x(GL_LINE_LOOP, strip->start, yminc, strip->end, ymaxc, 0.0, 0.0, 0.1); - + UI_draw_roundbox_shade_x(GL_LINE_LOOP, strip->start, yminc, strip->end, ymaxc, 0.0, 0.0, 0.1, color); + + /* restore current vertex format & program (roundbox trashes it) */ + pos = add_attrib(immVertexFormat(), "pos", COMP_F32, 2, KEEP_FLOAT); + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + + immUniformColor3fv(color); + /* if action-clip strip, draw lines delimiting repeats too (in the same color as outline) */ if ((strip->type == NLASTRIP_TYPE_CLIP) && IS_EQF(strip->repeat, 1.0f) == 0) { float repeatLen = (strip->actend - strip->actstart) * strip->scale; - int i; - + /* only draw lines for whole-numbered repeats, starting from the first full-repeat * up to the last full repeat (but not if it lies on the end of the strip) */ - for (i = 1; i < strip->repeat; i++) { + immBeginAtMost(PRIM_LINES, 2 * (strip->repeat - 1)); + for (int i = 1; i < strip->repeat; i++) { float repeatPos = strip->start + (repeatLen * i); - + /* don't draw if line would end up on or after the end of the strip */ - if (repeatPos < strip->end) - fdrawline(repeatPos, yminc + 4, repeatPos, ymaxc - 4); + if (repeatPos < strip->end) { + immVertex2f(pos, repeatPos, yminc + 4); + immVertex2f(pos, repeatPos, ymaxc - 4); + } } + immEnd(); } /* or if meta-strip, draw lines delimiting extents of sub-strips (in same color as outline, if more than 1 exists) */ else if ((strip->type == NLASTRIP_TYPE_META) && (strip->strips.first != strip->strips.last)) { - NlaStrip *cs; - float y = (ymaxc - yminc) / 2.0f + yminc; - + float y = (ymaxc - yminc) * 0.5f + yminc; + + immBeginAtMost(PRIM_LINES, 4 * BLI_listbase_count(&strip->strips)); /* up to 2 lines per strip */ + /* only draw first-level of child-strips, but don't draw any lines on the endpoints */ - for (cs = strip->strips.first; cs; cs = cs->next) { + for (NlaStrip *cs = strip->strips.first; cs; cs = cs->next) { /* draw start-line if not same as end of previous (and only if not the first strip) * - on upper half of strip */ - if ((cs->prev) && IS_EQF(cs->prev->end, cs->start) == 0) - fdrawline(cs->start, y, cs->start, ymaxc); - + if ((cs->prev) && IS_EQF(cs->prev->end, cs->start) == 0) { + immVertex2f(pos, cs->start, y); + immVertex2f(pos, cs->start, ymaxc); + } + /* draw end-line if not the last strip * - on lower half of strip */ - if (cs->next) - fdrawline(cs->end, yminc, cs->end, y); + if (cs->next) { + immVertex2f(pos, cs->end, yminc); + immVertex2f(pos, cs->end, y); + } } + + immEnd(); } - + /* reset linestyle */ setlinestyle(0); -} + immUnbindProgram(); +} /* add the relevant text to the cache of text-strings to draw in pixelspace */ static void nla_draw_strip_text( @@ -490,7 +519,6 @@ static void nla_draw_strip_text( char str[256]; size_t str_len; char col[4]; - rctf rect; /* just print the name and the range */ if (strip->flag & NLASTRIP_FLAG_TEMP_META) { @@ -517,12 +545,14 @@ static void nla_draw_strip_text( /* set bounding-box for text * - padding of 2 'units' on either side */ - // TODO: make this centered? - rect.xmin = xminc; - rect.ymin = yminc; - rect.xmax = xmaxc; - rect.ymax = ymaxc; - + /* TODO: make this centered? */ + rctf rect = { + .xmin = xminc, + .ymin = yminc, + .xmax = xmaxc, + .ymax = ymaxc + }; + /* add this string to the cache of texts to draw */ UI_view2d_text_cache_add_rectf(v2d, &rect, str, str_len, col); } @@ -535,9 +565,7 @@ static void nla_draw_strip_frames_text(NlaTrack *UNUSED(nlt), NlaStrip *strip, V const float ytol = 1.0f; /* small offset to vertical positioning of text, for legibility */ const char col[4] = {220, 220, 220, 255}; /* light gray */ char numstr[32]; - size_t numstr_len; - - + /* Always draw times above the strip, whereas sequencer drew below + above. * However, we should be fine having everything on top, since these tend to be * quite spaced out. @@ -545,9 +573,9 @@ static void nla_draw_strip_frames_text(NlaTrack *UNUSED(nlt), NlaStrip *strip, V * while also preserving some accuracy, since we do use floats */ /* start frame */ - numstr_len = BLI_snprintf_rlen(numstr, sizeof(numstr), "%.1f", strip->start); + size_t numstr_len = BLI_snprintf_rlen(numstr, sizeof(numstr), "%.1f", strip->start); UI_view2d_text_cache_add(v2d, strip->start - 1.0f, ymaxc + ytol, numstr, numstr_len, col); - + /* end frame */ numstr_len = BLI_snprintf_rlen(numstr, sizeof(numstr), "%.1f", strip->end); UI_view2d_text_cache_add(v2d, strip->end, ymaxc + ytol, numstr, numstr_len, col); @@ -557,20 +585,14 @@ static void nla_draw_strip_frames_text(NlaTrack *UNUSED(nlt), NlaStrip *strip, V void draw_nla_main_data(bAnimContext *ac, SpaceNla *snla, ARegion *ar) { - ListBase anim_data = {NULL, NULL}; - bAnimListElem *ale; - int filter; - View2D *v2d = &ar->v2d; - float y = 0.0f; - size_t items; - int height; const float pixelx = BLI_rctf_size_x(&v2d->cur) / BLI_rcti_size_x(&v2d->mask); const float text_margin_x = (8 * UI_DPI_FAC) * pixelx; /* build list of channels to draw */ - filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_LIST_CHANNELS); - items = ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); + ListBase anim_data = {NULL, NULL}; + int filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_LIST_CHANNELS); + size_t items = ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); /* Update max-extent of channels here (taking into account scrollers): * - this is done to allow the channel list to be scrollable, but must be done here @@ -578,16 +600,16 @@ void draw_nla_main_data(bAnimContext *ac, SpaceNla *snla, ARegion *ar) * - offset of NLACHANNEL_HEIGHT*2 is added to the height of the channels, as first is for * start of list offset, and the second is as a correction for the scrollers. */ - height = ((items * NLACHANNEL_STEP(snla)) + (NLACHANNEL_HEIGHT(snla) * 2)); + int height = ((items * NLACHANNEL_STEP(snla)) + (NLACHANNEL_HEIGHT(snla) * 2)); /* don't use totrect set, as the width stays the same * (NOTE: this is ok here, the configuration is pretty straightforward) */ v2d->tot.ymin = (float)(-height); /* loop through channels, and set up drawing depending on their type */ - y = (float)(-NLACHANNEL_HEIGHT(snla)); + float y = (float)(-NLACHANNEL_HEIGHT(snla)); - for (ale = anim_data.first; ale; ale = ale->next) { + for (bAnimListElem *ale = anim_data.first; ale; ale = ale->next) { const float yminc = (float)(y - NLACHANNEL_HEIGHT_HALF(snla)); const float ymaxc = (float)(y + NLACHANNEL_HEIGHT_HALF(snla)); @@ -601,11 +623,10 @@ void draw_nla_main_data(bAnimContext *ac, SpaceNla *snla, ARegion *ar) { AnimData *adt = ale->adt; NlaTrack *nlt = (NlaTrack *)ale->data; - NlaStrip *strip; - int index; /* draw each strip in the track (if visible) */ - for (strip = nlt->strips.first, index = 1; strip; strip = strip->next, index++) { + int index = 1; + for (NlaStrip *strip = nlt->strips.first; strip; strip = strip->next, index++) { if (BKE_nlastrip_within_bounds(strip, v2d->cur.xmin, v2d->cur.xmax)) { const float xminc = strip->start + text_margin_x; const float xmaxc = strip->end + text_margin_x; @@ -630,45 +651,60 @@ void draw_nla_main_data(bAnimContext *ac, SpaceNla *snla, ARegion *ar) case ANIMTYPE_NLAACTION: { AnimData *adt = ale->adt; - float color[4]; - + + unsigned int pos = add_attrib(immVertexFormat(), "pos", COMP_F32, 2, KEEP_FLOAT); + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + /* just draw a semi-shaded rect spanning the width of the viewable area if there's data, * and a second darker rect within which we draw keyframe indicator dots if there's data */ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glEnable(GL_BLEND); - + /* get colors for drawing */ + float color[4]; nla_action_get_color(adt, ale->data, color); - glColor4fv(color); - + immUniformColor4fv(color); + /* draw slightly shifted up for greater separation from standard channels, * but also slightly shorter for some more contrast when viewing the strips */ - glRectf(v2d->cur.xmin, yminc + NLACHANNEL_SKIP, v2d->cur.xmax, ymaxc - NLACHANNEL_SKIP); - - /* draw keyframes in the action */ - nla_action_draw_keyframes(adt, ale->data, v2d, y, yminc + NLACHANNEL_SKIP, ymaxc - NLACHANNEL_SKIP); + immRectf(pos, v2d->cur.xmin, yminc + NLACHANNEL_SKIP, v2d->cur.xmax, ymaxc - NLACHANNEL_SKIP); /* draw 'embossed' lines above and below the strip for effect */ /* white base-lines */ glLineWidth(2.0f); - glColor4f(1.0f, 1.0f, 1.0f, 0.3); - fdrawline(v2d->cur.xmin, yminc + NLACHANNEL_SKIP, v2d->cur.xmax, yminc + NLACHANNEL_SKIP); - fdrawline(v2d->cur.xmin, ymaxc - NLACHANNEL_SKIP, v2d->cur.xmax, ymaxc - NLACHANNEL_SKIP); - + immUniformColor4f(1.0f, 1.0f, 1.0f, 0.3); + immBegin(PRIM_LINES, 4); + immVertex2f(pos, v2d->cur.xmin, yminc + NLACHANNEL_SKIP); + immVertex2f(pos, v2d->cur.xmax, yminc + NLACHANNEL_SKIP); + immVertex2f(pos, v2d->cur.xmin, ymaxc - NLACHANNEL_SKIP); + immVertex2f(pos, v2d->cur.xmax, ymaxc - NLACHANNEL_SKIP); + immEnd(); + /* black top-lines */ glLineWidth(1.0f); - glColor3f(0.0f, 0.0f, 0.0f); - fdrawline(v2d->cur.xmin, yminc + NLACHANNEL_SKIP, v2d->cur.xmax, yminc + NLACHANNEL_SKIP); - fdrawline(v2d->cur.xmin, ymaxc - NLACHANNEL_SKIP, v2d->cur.xmax, ymaxc - NLACHANNEL_SKIP); - + immUniformColor3f(0.0f, 0.0f, 0.0f); + immBegin(PRIM_LINES, 4); + immVertex2f(pos, v2d->cur.xmin, yminc + NLACHANNEL_SKIP); + immVertex2f(pos, v2d->cur.xmax, yminc + NLACHANNEL_SKIP); + immVertex2f(pos, v2d->cur.xmin, ymaxc - NLACHANNEL_SKIP); + immVertex2f(pos, v2d->cur.xmax, ymaxc - NLACHANNEL_SKIP); + immEnd(); + + /* TODO: these lines but better --^ */ + + immUnbindProgram(); + + /* draw keyframes in the action */ + nla_action_draw_keyframes(adt, ale->data, y, yminc + NLACHANNEL_SKIP, ymaxc - NLACHANNEL_SKIP); + glDisable(GL_BLEND); break; } } } - + /* adjust y-position for next one */ y -= NLACHANNEL_STEP(snla); } @@ -684,17 +720,14 @@ void draw_nla_channel_list(const bContext *C, bAnimContext *ac, ARegion *ar) { ListBase anim_data = {NULL, NULL}; bAnimListElem *ale; - int filter; SpaceNla *snla = (SpaceNla *)ac->sl; View2D *v2d = &ar->v2d; float y = 0.0f; - size_t items; - int height; /* build list of channels to draw */ - filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_LIST_CHANNELS); - items = ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); + int filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_LIST_CHANNELS); + size_t items = ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); /* Update max-extent of channels here (taking into account scrollers): * - this is done to allow the channel list to be scrollable, but must be done here @@ -702,7 +735,7 @@ void draw_nla_channel_list(const bContext *C, bAnimContext *ac, ARegion *ar) * - offset of NLACHANNEL_HEIGHT*2 is added to the height of the channels, as first is for * start of list offset, and the second is as a correction for the scrollers. */ - height = ((items * NLACHANNEL_STEP(snla)) + (NLACHANNEL_HEIGHT(snla) * 2)); + int height = ((items * NLACHANNEL_STEP(snla)) + (NLACHANNEL_HEIGHT(snla) * 2)); /* don't use totrect set, as the width stays the same * (NOTE: this is ok here, the configuration is pretty straightforward) */ diff --git a/source/blender/editors/space_node/drawnode.c b/source/blender/editors/space_node/drawnode.c index d31a475e45e..0b292e242f0 100644 --- a/source/blender/editors/space_node/drawnode.c +++ b/source/blender/editors/space_node/drawnode.c @@ -53,6 +53,9 @@ #include "BIF_gl.h" #include "BIF_glutil.h" +#include "GPU_draw.h" +#include "GPU_immediate.h" + #include "RNA_access.h" #include "RNA_define.h" @@ -62,6 +65,7 @@ #include "WM_types.h" #include "UI_resources.h" +#include "UI_view2d.h" #include "IMB_colormanagement.h" #include "IMB_imbuf_types.h" @@ -80,49 +84,6 @@ static void node_socket_button_label(bContext *UNUSED(C), uiLayout *layout, Poin uiItemL(layout, text, 0); } - -/* ****************** BASE DRAW FUNCTIONS FOR NEW OPERATOR NODES ***************** */ - -#if 0 /* UNUSED */ -static void node_draw_socket_new(bNodeSocket *sock, float size) -{ - float x = sock->locx, y = sock->locy; - - /* 16 values of sin function */ - static float si[16] = { - 0.00000000f, 0.39435585f, 0.72479278f, 0.93775213f, - 0.99871650f, 0.89780453f, 0.65137248f, 0.29936312f, - -0.10116832f, -0.48530196f, -0.79077573f, -0.96807711f, - -0.98846832f, -0.84864425f, -0.57126821f, -0.20129852f - }; - /* 16 values of cos function */ - static float co[16] = { - 1.00000000f, 0.91895781f, 0.68896691f, 0.34730525f, - -0.05064916f, -0.44039415f, -0.75875812f, -0.95413925f, - -0.99486932f, -0.87434661f, -0.61210598f, -0.25065253f, - 0.15142777f, 0.52896401f, 0.82076344f, 0.97952994f, - }; - int a; - - glColor3ub(180, 180, 180); - - glBegin(GL_POLYGON); - for (a = 0; a < 16; a++) - glVertex2f(x + size * si[a], y + size * co[a]); - glEnd(); - - glColor4ub(0, 0, 0, 150); - glEnable(GL_BLEND); - glEnable(GL_LINE_SMOOTH); - glBegin(GL_LINE_LOOP); - for (a = 0; a < 16; a++) - glVertex2f(x + size * si[a], y + size * co[a]); - glEnd(); - glDisable(GL_LINE_SMOOTH); - glDisable(GL_BLEND); -} -#endif - /* ****************** BUTTON CALLBACKS FOR ALL TREES ***************** */ static void node_buts_value(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) @@ -465,7 +426,7 @@ static void node_draw_frame(const bContext *C, ARegion *ar, SpaceNode *snode, { rctf *rct = &node->totr; int color_id = node_get_colorid(node); - unsigned char color[4]; + float color[4]; float alpha; /* skip if out of view */ @@ -475,36 +436,37 @@ static void node_draw_frame(const bContext *C, ARegion *ar, SpaceNode *snode, return; } - UI_GetThemeColor4ubv(TH_NODE_FRAME, color); - alpha = (float)(color[3]) / 255.0f; + UI_GetThemeColor4fv(TH_NODE_FRAME, color); + alpha = color[3]; /* shadow */ node_draw_shadow(snode, node, BASIS_RAD, alpha); /* body */ - if (node->flag & NODE_CUSTOM_COLOR) - glColor4f(node->color[0], node->color[1], node->color[2], alpha); + if (node->flag & NODE_CUSTOM_COLOR) { + rgba_float_args_set(color, node->color[0], node->color[1], node->color[2], alpha); + } else - UI_ThemeColor4(TH_NODE_FRAME); + UI_GetThemeColor4fv(TH_NODE_FRAME, color); glEnable(GL_BLEND); UI_draw_roundbox_corner_set(UI_CNR_ALL); - UI_draw_roundbox(rct->xmin, rct->ymin, rct->xmax, rct->ymax, BASIS_RAD); + UI_draw_roundbox(rct->xmin, rct->ymin, rct->xmax, rct->ymax, BASIS_RAD, color); glDisable(GL_BLEND); /* outline active and selected emphasis */ if (node->flag & SELECT) { glEnable(GL_BLEND); glEnable(GL_LINE_SMOOTH); - + if (node->flag & NODE_ACTIVE) - UI_ThemeColorShadeAlpha(TH_ACTIVE, 0, -40); + UI_GetThemeColorShadeAlpha4fv(TH_ACTIVE, 0, -40, color); else - UI_ThemeColorShadeAlpha(TH_SELECT, 0, -40); + UI_GetThemeColorShadeAlpha4fv(TH_SELECT, 0, -40, color); + UI_draw_roundbox_corner_set(UI_CNR_ALL); - UI_draw_roundbox_gl_mode(GL_LINE_LOOP, - rct->xmin, rct->ymin, - rct->xmax, rct->ymax, BASIS_RAD); - + UI_draw_roundbox_gl_mode(GL_LINE_LOOP, rct->xmin, rct->ymin, rct->xmax, rct->ymax, BASIS_RAD, color); + + glDisable(GL_LINE_SMOOTH); glDisable(GL_BLEND); } @@ -580,14 +542,12 @@ static void node_draw_reroute_prepare(const bContext *UNUSED(C), bNodeTree *UNUS static void node_draw_reroute(const bContext *C, ARegion *ar, SpaceNode *UNUSED(snode), bNodeTree *ntree, bNode *node, bNodeInstanceKey UNUSED(key)) { - bNodeSocket *sock; char showname[128]; /* 128 used below */ rctf *rct = &node->totr; #if 0 /* UNUSED */ float size = NODE_REROUTE_SIZE; #endif - float socket_size = NODE_SOCKSIZE; /* skip if out of view */ if (node->totr.xmax < ar->v2d.cur.xmin || node->totr.xmin > ar->v2d.cur.xmax || @@ -637,9 +597,7 @@ static void node_draw_reroute(const bContext *C, ARegion *ar, SpaceNode *UNUSED( /* only draw input socket. as they all are placed on the same position. * highlight also if node itself is selected, since we don't display the node body separately! */ - for (sock = node->inputs.first; sock; sock = sock->next) { - node_socket_circle_draw(C, ntree, node, sock, socket_size, (sock->flag & SELECT) || (node->flag & SELECT)); - } + node_draw_sockets(&ar->v2d, C, ntree, node, false, node->flag & SELECT); UI_block_end(C, node->block); UI_block_draw(C, node->block); @@ -2218,14 +2176,21 @@ static void node_composit_backdrop_viewer(SpaceNode *snode, ImBuf *backdrop, bNo const float cx = x + snode->zoom * backdropWidth * node->custom3; const float cy = y + snode->zoom * backdropHeight * node->custom4; - glColor3f(1.0, 1.0, 1.0); + VertexFormat *format = immVertexFormat(); + unsigned int pos = add_attrib(format, "pos", GL_FLOAT, 2, KEEP_FLOAT); - glBegin(GL_LINES); - glVertex2f(cx - 25, cy - 25); - glVertex2f(cx + 25, cy + 25); - glVertex2f(cx + 25, cy - 25); - glVertex2f(cx - 25, cy + 25); - glEnd(); + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + + immUniformColor3f(1.0f, 1.0f, 1.0f); + + immBegin(GL_LINES, 4); + immVertex2f(pos, cx - 25, cy - 25); + immVertex2f(pos, cx + 25, cy + 25); + immVertex2f(pos, cx + 25, cy - 25); + immVertex2f(pos, cx - 25, cy + 25); + immEnd(); + + immUnbindProgram(); } } @@ -2244,9 +2209,6 @@ static void node_composit_backdrop_boxmask(SpaceNode *snode, ImBuf *backdrop, bN float cx, cy, x1, x2, x3, x4; float y1, y2, y3, y4; - - glColor3f(1.0, 1.0, 1.0); - cx = x + snode->zoom * backdropWidth * boxmask->x; cy = y + snode->zoom * backdropHeight * boxmask->y; @@ -2259,12 +2221,21 @@ static void node_composit_backdrop_boxmask(SpaceNode *snode, ImBuf *backdrop, bN y3 = cy - (-sine * -halveBoxWidth + cosine * -halveBoxHeight) * snode->zoom; y4 = cy - (-sine * halveBoxWidth + cosine * -halveBoxHeight) * snode->zoom; - glBegin(GL_LINE_LOOP); - glVertex2f(x1, y1); - glVertex2f(x2, y2); - glVertex2f(x3, y3); - glVertex2f(x4, y4); - glEnd(); + VertexFormat *format = immVertexFormat(); + unsigned int pos = add_attrib(format, "pos", GL_FLOAT, 2, KEEP_FLOAT); + + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + + immUniformColor3f(1.0f, 1.0f, 1.0f); + + immBegin(GL_LINE_LOOP, 4); + immVertex2f(pos, x1, y1); + immVertex2f(pos, x2, y2); + immVertex2f(pos, x3, y3); + immVertex2f(pos, x4, y4); + immEnd(); + + immUnbindProgram(); } static void node_composit_backdrop_ellipsemask(SpaceNode *snode, ImBuf *backdrop, bNode *node, int x, int y) @@ -2282,9 +2253,6 @@ static void node_composit_backdrop_ellipsemask(SpaceNode *snode, ImBuf *backdrop float cx, cy, x1, x2, x3, x4; float y1, y2, y3, y4; - - glColor3f(1.0, 1.0, 1.0); - cx = x + snode->zoom * backdropWidth * ellipsemask->x; cy = y + snode->zoom * backdropHeight * ellipsemask->y; @@ -2297,13 +2265,21 @@ static void node_composit_backdrop_ellipsemask(SpaceNode *snode, ImBuf *backdrop y3 = cy - (-sine * -halveBoxWidth + cosine * -halveBoxHeight) * snode->zoom; y4 = cy - (-sine * halveBoxWidth + cosine * -halveBoxHeight) * snode->zoom; - glBegin(GL_LINE_LOOP); + VertexFormat *format = immVertexFormat(); + unsigned int pos = add_attrib(format, "pos", GL_FLOAT, 2, KEEP_FLOAT); + + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + + immUniformColor3f(1.0f, 1.0f, 1.0f); + + immBegin(GL_LINE_LOOP, 4); + immVertex2f(pos, x1, y1); + immVertex2f(pos, x2, y2); + immVertex2f(pos, x3, y3); + immVertex2f(pos, x4, y4); + immEnd(); - glVertex2f(x1, y1); - glVertex2f(x2, y2); - glVertex2f(x3, y3); - glVertex2f(x4, y4); - glEnd(); + immUnbindProgram(); } static void node_composit_buts_ellipsemask(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) @@ -3643,27 +3619,27 @@ void node_draw_link(View2D *v2d, SpaceNode *snode, bNodeLink *link) // node_draw_link_straight(v2d, snode, link, th_col1, do_shaded, th_col2, do_triple, th_col3); } -void ED_node_draw_snap(View2D *v2d, const float cent[2], float size, NodeBorder border) +void ED_node_draw_snap(View2D *v2d, const float cent[2], float size, NodeBorder border, unsigned pos) { - glBegin(GL_LINES); + immBegin(GL_LINES, 4); if (border & (NODE_LEFT | NODE_RIGHT)) { - glVertex2f(cent[0], v2d->cur.ymin); - glVertex2f(cent[0], v2d->cur.ymax); + immVertex2f(pos, cent[0], v2d->cur.ymin); + immVertex2f(pos, cent[0], v2d->cur.ymax); } else { - glVertex2f(cent[0], cent[1] - size); - glVertex2f(cent[0], cent[1] + size); + immVertex2f(pos, cent[0], cent[1] - size); + immVertex2f(pos, cent[0], cent[1] + size); } if (border & (NODE_TOP | NODE_BOTTOM)) { - glVertex2f(v2d->cur.xmin, cent[1]); - glVertex2f(v2d->cur.xmax, cent[1]); + immVertex2f(pos, v2d->cur.xmin, cent[1]); + immVertex2f(pos, v2d->cur.xmax, cent[1]); } else { - glVertex2f(cent[0] - size, cent[1]); - glVertex2f(cent[0] + size, cent[1]); + immVertex2f(pos, cent[0] - size, cent[1]); + immVertex2f(pos, cent[0] + size, cent[1]); } - glEnd(); + immEnd(); } diff --git a/source/blender/editors/space_node/node_draw.c b/source/blender/editors/space_node/node_draw.c index ab40c55b59d..40917f8e349 100644 --- a/source/blender/editors/space_node/node_draw.c +++ b/source/blender/editors/space_node/node_draw.c @@ -54,6 +54,9 @@ #include "BIF_gl.h" #include "BIF_glutil.h" +#include "GPU_draw.h" +#include "GPU_immediate.h" + #include "WM_api.h" #include "WM_types.h" @@ -617,60 +620,16 @@ static void node_draw_mute_line(View2D *v2d, SpaceNode *snode, bNode *node) glDisable(GL_LINE_SMOOTH); } -/* this might have some more generic use */ -static void node_circle_draw(float x, float y, float size, const float col[4], int highlight) +static void node_socket_circle_draw(const bContext *C, bNodeTree *ntree, PointerRNA node_ptr, bNodeSocket *sock, unsigned pos, unsigned col) { - /* 16 values of sin function */ - static const float si[16] = { - 0.00000000f, 0.39435585f, 0.72479278f, 0.93775213f, - 0.99871650f, 0.89780453f, 0.65137248f, 0.29936312f, - -0.10116832f, -0.48530196f, -0.79077573f, -0.96807711f, - -0.98846832f, -0.84864425f, -0.57126821f, -0.20129852f - }; - /* 16 values of cos function */ - static const float co[16] = { - 1.00000000f, 0.91895781f, 0.68896691f, 0.34730525f, - -0.05064916f, -0.44039415f, -0.75875812f, -0.95413925f, - -0.99486932f, -0.87434661f, -0.61210598f, -0.25065253f, - 0.15142777f, 0.52896401f, 0.82076344f, 0.97952994f, - }; - int a; - - glColor4fv(col); - - glEnable(GL_BLEND); - glBegin(GL_POLYGON); - for (a = 0; a < 16; a++) - glVertex2f(x + size * si[a], y + size * co[a]); - glEnd(); - glDisable(GL_BLEND); - - if (highlight) { - UI_ThemeColor(TH_TEXT_HI); - glLineWidth(1.5f); - } - else { - glColor4ub(0, 0, 0, 150); - } - glEnable(GL_BLEND); - glEnable(GL_LINE_SMOOTH); - glBegin(GL_LINE_LOOP); - for (a = 0; a < 16; a++) - glVertex2f(x + size * si[a], y + size * co[a]); - glEnd(); - glDisable(GL_LINE_SMOOTH); - glDisable(GL_BLEND); -} - -void node_socket_circle_draw(const bContext *C, bNodeTree *ntree, bNode *node, bNodeSocket *sock, float size, int highlight) -{ - PointerRNA ptr, node_ptr; + PointerRNA ptr; float color[4]; RNA_pointer_create((ID *)ntree, &RNA_NodeSocket, sock, &ptr); - RNA_pointer_create((ID *)ntree, &RNA_Node, node, &node_ptr); sock->typeinfo->draw_color((bContext *)C, &ptr, &node_ptr, color); - node_circle_draw(sock->locx, sock->locy, size, color, highlight); + + immAttrib4fv(col, color); + immVertex2f(pos, sock->locx, sock->locy); } /* ************** Socket callbacks *********** */ @@ -679,10 +638,15 @@ static void node_draw_preview_background(float tile, rctf *rect) { float x, y; + VertexFormat *format = immVertexFormat(); + unsigned pos = add_attrib(format, "pos", GL_FLOAT, 2, KEEP_FLOAT); + + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + /* draw checkerboard backdrop to show alpha */ - glColor3ub(120, 120, 120); - glRectf(rect->xmin, rect->ymin, rect->xmax, rect->ymax); - glColor3ub(160, 160, 160); + immUniformColor3ub(120, 120, 120); + immRectf(pos, rect->xmin, rect->ymin, rect->xmax, rect->ymax); + immUniformColor3ub(160, 160, 160); for (y = rect->ymin; y < rect->ymax; y += tile * 2) { for (x = rect->xmin; x < rect->xmax; x += tile * 2) { @@ -693,7 +657,7 @@ static void node_draw_preview_background(float tile, rctf *rect) if (y + tile > rect->ymax) tiley = rect->ymax - y; - glRectf(x, y, x + tilex, y + tiley); + immRectf(pos, x, y, x + tilex, y + tiley); } } for (y = rect->ymin + tile; y < rect->ymax; y += tile * 2) { @@ -705,9 +669,10 @@ static void node_draw_preview_background(float tile, rctf *rect) if (y + tile > rect->ymax) tiley = rect->ymax - y; - glRectf(x, y, x + tilex, y + tiley); + immRectf(pos, x, y, x + tilex, y + tiley); } } + immUnbindProgram(); } /* not a callback */ @@ -773,23 +738,129 @@ void node_draw_shadow(SpaceNode *snode, bNode *node, float radius, float alpha) else { const float margin = 3.0f; - glColor4f(0.0f, 0.0f, 0.0f, 0.33f); + float color[4] = {0.0f, 0.0f, 0.0f, 0.33f}; glEnable(GL_BLEND); UI_draw_roundbox(rct->xmin - margin, rct->ymin - margin, - rct->xmax + margin, rct->ymax + margin, radius + margin); + rct->xmax + margin, rct->ymax + margin, radius + margin, color); glDisable(GL_BLEND); } } +void node_draw_sockets(View2D *v2d, const bContext *C, bNodeTree *ntree, bNode *node, bool draw_outputs, bool select_all) +{ + PointerRNA node_ptr; + RNA_pointer_create((ID *)ntree, &RNA_Node, node, &node_ptr); + + float xscale, yscale; + UI_view2d_scale_get(v2d, &xscale, &yscale); + + VertexFormat *format = immVertexFormat(); + unsigned pos = add_attrib(format, "pos", GL_FLOAT, 2, KEEP_FLOAT); + unsigned col = add_attrib(format, "color", GL_FLOAT, 4, KEEP_FLOAT); + + glEnable(GL_BLEND); + GPU_enable_program_point_size(); + + immBindBuiltinProgram(GPU_SHADER_2D_POINT_UNIFORM_SIZE_VARYING_COLOR_OUTLINE_SMOOTH); + + /* set handle size */ + immUniform1f("size", 2.0f * NODE_SOCKSIZE * xscale); // 2 * size to have diameter + + if (!select_all) { + /* outline for unselected sockets */ + immUniform1f("outlineWidth", 1.0f); + immUniform4f("outlineColor", 0.0f, 0.0f, 0.0f, 0.6f); + + immBeginAtMost(GL_POINTS, BLI_listbase_count(&node->inputs) + BLI_listbase_count(&node->outputs)); + } + + /* socket inputs */ + short selected_input_ct = 0; + bNodeSocket *sock; + for (sock = node->inputs.first; sock; sock = sock->next) { + if (nodeSocketIsHidden(sock)) + continue; + if (select_all || (sock->flag & SELECT)) { + ++selected_input_ct; + continue; + } + + node_socket_circle_draw(C, ntree, node_ptr, sock, pos, col); + } + + /* socket outputs */ + short selected_output_ct = 0; + if (draw_outputs) { + for (sock = node->outputs.first; sock; sock = sock->next) { + if (nodeSocketIsHidden(sock)) + continue; + if (select_all || (sock->flag & SELECT)) { + ++selected_output_ct; + continue; + } + + node_socket_circle_draw(C, ntree, node_ptr, sock, pos, col); + } + } + + if (!select_all) { + immEnd(); + } + + /* go back and draw selected sockets */ + if (selected_input_ct + selected_output_ct > 0) { + /* outline for selected sockets */ + float c[3]; + UI_GetThemeColor3fv(TH_TEXT_HI, c); + immUniform4f("outlineColor", c[0], c[1], c[2], 1.0f); + immUniform1f("outlineWidth", 1.5f); + + immBegin(GL_POINTS, selected_input_ct + selected_output_ct); + + if (selected_input_ct) { + /* socket inputs */ + for (sock = node->inputs.first; sock; sock = sock->next) { + if (nodeSocketIsHidden(sock)) + continue; + if (select_all || (sock->flag & SELECT)) { + node_socket_circle_draw(C, ntree, node_ptr, sock, pos, col); + if (--selected_input_ct == 0) + break; /* stop as soon as last one is drawn */ + } + } + } + + if (selected_output_ct) { + /* socket outputs */ + for (sock = node->outputs.first; sock; sock = sock->next) { + if (nodeSocketIsHidden(sock)) + continue; + if (select_all || (sock->flag & SELECT)) { + node_socket_circle_draw(C, ntree, node_ptr, sock, pos, col); + if (--selected_output_ct == 0) + break; /* stop as soon as last one is drawn */ + } + } + } + + immEnd(); + } + + immUnbindProgram(); + + GPU_disable_program_point_size(); + glDisable(GL_BLEND); +} + static void node_draw_basis(const bContext *C, ARegion *ar, SpaceNode *snode, bNodeTree *ntree, bNode *node, bNodeInstanceKey key) { bNodeInstanceHash *previews = CTX_data_pointer_get(C, "node_previews").data; - bNodeSocket *sock; rctf *rct = &node->totr; float iconofs; /* float socket_size = NODE_SOCKSIZE*U.dpi/72; */ /* UNUSED */ float iconbutw = 0.8f * UI_UNIT_X; int color_id = node_get_colorid(node); + float color[4]; char showname[128]; /* 128 used below */ View2D *v2d = &ar->v2d; @@ -798,7 +869,7 @@ static void node_draw_basis(const bContext *C, ARegion *ar, SpaceNode *snode, bN nodeSynchronizeID(node, false); /* skip if out of view */ - if (BLI_rctf_isect(&node->totr, &ar->v2d.cur, NULL) == false) { + if (BLI_rctf_isect(&node->totr, &v2d->cur, NULL) == false) { UI_block_end(C, node->block); node->block = NULL; return; @@ -809,21 +880,20 @@ static void node_draw_basis(const bContext *C, ARegion *ar, SpaceNode *snode, bN /* header uses color from backdrop, but we make it opaqie */ if (color_id == TH_NODE) { - float col[3]; - UI_GetThemeColorShade3fv(color_id, -20, col); - glColor4f(col[0], col[1], col[2], 1.0f); + UI_GetThemeColorShade3fv(color_id, -20, color); } else - UI_ThemeColor(color_id); + UI_GetThemeColor4fv(color_id, color); if (node->flag & NODE_MUTED) - UI_ThemeColorBlend(color_id, TH_REDALERT, 0.5f); + UI_GetThemeColorBlendShade4fv(color_id, TH_REDALERT, 0.5f, 0, color); + #ifdef WITH_COMPOSITOR if (ntree->type == NTREE_COMPOSIT && (snode->flag & SNODE_SHOW_HIGHLIGHT)) { if (COM_isHighlightedbNode(node)) { - UI_ThemeColorBlend(color_id, TH_ACTIVE, 0.5f); + UI_GetThemeColorBlendShade4fv(color_id, TH_ACTIVE, 0.5f, 0, color); } } #endif @@ -831,7 +901,7 @@ static void node_draw_basis(const bContext *C, ARegion *ar, SpaceNode *snode, bN glLineWidth(1.0f); UI_draw_roundbox_corner_set(UI_CNR_TOP_LEFT | UI_CNR_TOP_RIGHT); - UI_draw_roundbox(rct->xmin, rct->ymax - NODE_DY, rct->xmax, rct->ymax, BASIS_RAD); + UI_draw_roundbox(rct->xmin, rct->ymax - NODE_DY, rct->xmax, rct->ymax, BASIS_RAD, color); /* show/hide icons */ iconofs = rct->xmax - 0.35f * U.widget_unit; @@ -864,10 +934,12 @@ static void node_draw_basis(const bContext *C, ARegion *ar, SpaceNode *snode, bN } /* title */ - if (node->flag & SELECT) - UI_ThemeColor(TH_SELECT); - else - UI_ThemeColorBlendShade(TH_TEXT, color_id, 0.4f, 10); + if (node->flag & SELECT) { + UI_GetThemeColor4fv(TH_SELECT, color); + } + else { + UI_GetThemeColorBlendShade4fv(TH_SELECT, color_id, 0.4f, 10, color); + } /* open/close entirely? */ { @@ -882,15 +954,11 @@ static void node_draw_basis(const bContext *C, ARegion *ar, SpaceNode *snode, bN UI_block_emboss_set(node->block, UI_EMBOSS); /* custom draw function for this button */ - UI_draw_icon_tri(rct->xmin + 0.5f * U.widget_unit, rct->ymax - NODE_DY / 2.0f, 'v'); + UI_draw_icon_tri(rct->xmin + 0.5f * U.widget_unit, rct->ymax - NODE_DY / 2.0f, 'v', color); } - /* this isn't doing anything for the label, so commenting out */ -#if 0 - if (node->flag & SELECT) - UI_ThemeColor(TH_TEXT_HI); - else - UI_ThemeColor(TH_TEXT); +#if 0 /* this isn't doing anything for the label, so commenting out */ + UI_ThemeColor((node->flag & SELECT) ? TH_TEXT_HI : TH_TEXT); #endif nodeLabel(ntree, node, showname, sizeof(showname)); @@ -905,30 +973,27 @@ static void node_draw_basis(const bContext *C, ARegion *ar, SpaceNode *snode, bN /* body */ if (!nodeIsRegistered(node)) - UI_ThemeColor4(TH_REDALERT); /* use warning color to indicate undefined types */ - else if (node->flag & NODE_CUSTOM_COLOR) - glColor3fv(node->color); + UI_GetThemeColor4fv(TH_REDALERT, color); /* use warning color to indicate undefined types */ + else if (node->flag & NODE_CUSTOM_COLOR) { + rgba_float_args_set(color, node->color[0], node->color[1], node->color[2], 1.0f); + } else - UI_ThemeColor4(TH_NODE); + UI_GetThemeColor4fv(TH_NODE, color); glEnable(GL_BLEND); UI_draw_roundbox_corner_set(UI_CNR_BOTTOM_LEFT | UI_CNR_BOTTOM_RIGHT); - UI_draw_roundbox(rct->xmin, rct->ymin, rct->xmax, rct->ymax - NODE_DY, BASIS_RAD); + UI_draw_roundbox(rct->xmin, rct->ymin, rct->xmax, rct->ymax - NODE_DY, BASIS_RAD, color); glDisable(GL_BLEND); /* outline active and selected emphasis */ if (node->flag & SELECT) { - glEnable(GL_BLEND); glEnable(GL_LINE_SMOOTH); - - if (node->flag & NODE_ACTIVE) - UI_ThemeColorShadeAlpha(TH_ACTIVE, 0, -40); - else - UI_ThemeColorShadeAlpha(TH_SELECT, 0, -40); - + + UI_GetThemeColorShadeAlpha4fv((node->flag & NODE_ACTIVE) ? TH_ACTIVE : TH_SELECT, 0, -40, color); + UI_draw_roundbox_corner_set(UI_CNR_ALL); - UI_draw_roundbox_gl_mode(GL_LINE_LOOP, rct->xmin, rct->ymin, rct->xmax, rct->ymax, BASIS_RAD); - + UI_draw_roundbox_gl_mode(GL_LINE_LOOP, rct->xmin, rct->ymin, rct->xmax, rct->ymax, BASIS_RAD, color); + glDisable(GL_LINE_SMOOTH); glDisable(GL_BLEND); } @@ -937,23 +1002,8 @@ static void node_draw_basis(const bContext *C, ARegion *ar, SpaceNode *snode, bN if (node->flag & NODE_MUTED) node_draw_mute_line(v2d, snode, node); - - /* socket inputs, buttons */ - for (sock = node->inputs.first; sock; sock = sock->next) { - if (nodeSocketIsHidden(sock)) - continue; - - node_socket_circle_draw(C, ntree, node, sock, NODE_SOCKSIZE, sock->flag & SELECT); - } - - /* socket outputs */ - for (sock = node->outputs.first; sock; sock = sock->next) { - if (nodeSocketIsHidden(sock)) - continue; - - node_socket_circle_draw(C, ntree, node, sock, NODE_SOCKSIZE, sock->flag & SELECT); - } - + node_draw_sockets(v2d, C, ntree, node, true, false); + /* preview */ if (node->flag & NODE_PREVIEW && previews) { bNodePreview *preview = BKE_node_instance_hash_lookup(previews, key); @@ -973,13 +1023,16 @@ static void node_draw_basis(const bContext *C, ARegion *ar, SpaceNode *snode, bN static void node_draw_hidden(const bContext *C, ARegion *ar, SpaceNode *snode, bNodeTree *ntree, bNode *node, bNodeInstanceKey UNUSED(key)) { - bNodeSocket *sock; rctf *rct = &node->totr; float dx, centy = BLI_rctf_cent_y(rct); float hiddenrad = BLI_rctf_size_y(rct) / 2.0f; - float socket_size = NODE_SOCKSIZE; int color_id = node_get_colorid(node); + float color[4]; char showname[128]; /* 128 is used below */ + View2D *v2d = &ar->v2d; + float xscale, yscale; + + UI_view2d_scale_get(v2d, &xscale, &yscale); /* shadow */ node_draw_shadow(snode, node, hiddenrad, 1.0f); @@ -987,31 +1040,29 @@ static void node_draw_hidden(const bContext *C, ARegion *ar, SpaceNode *snode, b /* body */ UI_ThemeColor(color_id); if (node->flag & NODE_MUTED) - UI_ThemeColorBlend(color_id, TH_REDALERT, 0.5f); + UI_GetThemeColorBlendShade4fv(color_id, TH_REDALERT, 0.5f, 0, color); #ifdef WITH_COMPOSITOR if (ntree->type == NTREE_COMPOSIT && (snode->flag & SNODE_SHOW_HIGHLIGHT)) { if (COM_isHighlightedbNode(node)) { - UI_ThemeColorBlend(color_id, TH_ACTIVE, 0.5f); + UI_GetThemeColorBlendShade4fv(color_id, TH_ACTIVE, 0.5f, 0, color); } } #else (void)ntree; #endif - UI_draw_roundbox(rct->xmin, rct->ymin, rct->xmax, rct->ymax, hiddenrad); + UI_draw_roundbox(rct->xmin, rct->ymin, rct->xmax, rct->ymax, hiddenrad, color); /* outline active and selected emphasis */ if (node->flag & SELECT) { glEnable(GL_BLEND); glEnable(GL_LINE_SMOOTH); - if (node->flag & NODE_ACTIVE) - UI_ThemeColorShadeAlpha(TH_ACTIVE, 0, -40); - else - UI_ThemeColorShadeAlpha(TH_SELECT, 0, -40); - UI_draw_roundbox_gl_mode(GL_LINE_LOOP, rct->xmin, rct->ymin, rct->xmax, rct->ymax, hiddenrad); - + UI_GetThemeColorShadeAlpha4fv((node->flag & NODE_ACTIVE) ? TH_ACTIVE : TH_SELECT, 0, -40, color); + + UI_draw_roundbox_gl_mode(GL_LINE_LOOP, rct->xmin, rct->ymin, rct->xmax, rct->ymax, hiddenrad, color); + glDisable(GL_LINE_SMOOTH); glDisable(GL_BLEND); } @@ -1021,18 +1072,19 @@ static void node_draw_hidden(const bContext *C, ARegion *ar, SpaceNode *snode, b glEnable(GL_BLEND); glEnable(GL_LINE_SMOOTH); - glColor3fv(node->color); - UI_draw_roundbox_gl_mode(GL_LINE_LOOP, rct->xmin + 1, rct->ymin + 1, rct->xmax -1, rct->ymax - 1, hiddenrad); + UI_draw_roundbox_gl_mode_3fvAlpha(GL_LINE_LOOP, rct->xmin + 1, rct->ymin + 1, rct->xmax -1, rct->ymax - 1, hiddenrad, node->color, 1.0f); glDisable(GL_LINE_SMOOTH); glDisable(GL_BLEND); } /* title */ - if (node->flag & SELECT) - UI_ThemeColor(TH_SELECT); - else - UI_ThemeColorBlendShade(TH_TEXT, color_id, 0.4f, 10); + if (node->flag & SELECT) { + UI_GetThemeColor4fv(TH_SELECT, color); + } + else { + UI_GetThemeColorBlendShade4fv(TH_SELECT, color_id, 0.4f, 10, color); + } /* open entirely icon */ { @@ -1047,18 +1099,15 @@ static void node_draw_hidden(const bContext *C, ARegion *ar, SpaceNode *snode, b UI_block_emboss_set(node->block, UI_EMBOSS); /* custom draw function for this button */ - UI_draw_icon_tri(rct->xmin + 10.0f, centy, 'h'); + UI_draw_icon_tri(rct->xmin + 10.0f, centy, 'h', color); } /* disable lines */ if (node->flag & NODE_MUTED) node_draw_mute_line(&ar->v2d, snode, node); - - if (node->flag & SELECT) - UI_ThemeColor(TH_SELECT); - else - UI_ThemeColor(TH_TEXT); - + + UI_ThemeColor((node->flag & SELECT) ? TH_SELECT : TH_TEXT); + if (node->miniwidth > 0.0f) { nodeLabel(ntree, node, showname, sizeof(showname)); @@ -1082,17 +1131,8 @@ static void node_draw_hidden(const bContext *C, ARegion *ar, SpaceNode *snode, b fdrawline(rct->xmax - dx, centy - 4.0f, rct->xmax - dx, centy + 4.0f); fdrawline(rct->xmax - dx - 3.0f * snode->aspect, centy - 4.0f, rct->xmax - dx - 3.0f * snode->aspect, centy + 4.0f); - /* sockets */ - for (sock = node->inputs.first; sock; sock = sock->next) { - if (!nodeSocketIsHidden(sock)) - node_socket_circle_draw(C, ntree, node, sock, socket_size, sock->flag & SELECT); - } - - for (sock = node->outputs.first; sock; sock = sock->next) { - if (!nodeSocketIsHidden(sock)) - node_socket_circle_draw(C, ntree, node, sock, socket_size, sock->flag & SELECT); - } - + node_draw_sockets(v2d, C, ntree, node, true, false); + UI_block_end(C, node->block); UI_block_draw(C, node->block); node->block = NULL; @@ -1233,7 +1273,7 @@ static void draw_tree_path(SpaceNode *snode) ED_node_tree_path_get_fixedbuf(snode, info, sizeof(info)); - UI_ThemeColor(TH_TEXT_HI); + UI_FontThemeColor(BLF_default(), TH_TEXT_HI); BLF_draw_default(1.5f * UI_UNIT_X, 1.5f * UI_UNIT_Y, 0.0f, info, sizeof(info)); } @@ -1272,12 +1312,14 @@ static void draw_group_overlay(const bContext *C, ARegion *ar) View2D *v2d = &ar->v2d; rctf rect = v2d->cur; uiBlock *block; - + float color[4]; + /* shade node groups to separate them visually */ - UI_ThemeColorShadeAlpha(TH_NODE_GROUP, 0, -70); glEnable(GL_BLEND); + + UI_GetThemeColorShadeAlpha4fv(TH_NODE_GROUP, 0, -70, color); UI_draw_roundbox_corner_set(UI_CNR_NONE); - UI_draw_roundbox_gl_mode(GL_POLYGON, rect.xmin, rect.ymin, rect.xmax, rect.ymax, 0); + UI_draw_roundbox_gl_mode(GL_TRIANGLE_FAN, rect.xmin, rect.ymin, rect.xmax, rect.ymax, 0, color); glDisable(GL_BLEND); /* set the block bounds to clip mouse events from underlying nodes */ diff --git a/source/blender/editors/space_node/node_intern.h b/source/blender/editors/space_node/node_intern.h index 6b8fa0b88fe..3b5d32a432a 100644 --- a/source/blender/editors/space_node/node_intern.h +++ b/source/blender/editors/space_node/node_intern.h @@ -67,12 +67,11 @@ void snode_group_offset(struct SpaceNode *snode, float *x, float *y); /* transfo /* node_draw.c */ int node_get_colorid(struct bNode *node); -void node_socket_circle_draw(const struct bContext *C, struct bNodeTree *ntree, struct bNode *node, - struct bNodeSocket *sock, float size, int highlight); int node_get_resize_cursor(int directions); void node_draw_shadow(struct SpaceNode *snode, struct bNode *node, float radius, float alpha); void node_draw_default(const struct bContext *C, struct ARegion *ar, struct SpaceNode *snode, struct bNodeTree *ntree, struct bNode *node, bNodeInstanceKey key); +void node_draw_sockets(struct View2D *v2d, const struct bContext *C, struct bNodeTree *ntree, struct bNode *node, bool draw_outputs, bool select_all); void node_update_default(const struct bContext *C, struct bNodeTree *ntree, struct bNode *node); int node_select_area_default(struct bNode *node, int x, int y); int node_tweak_area_default(struct bNode *node, int x, int y); diff --git a/source/blender/editors/space_outliner/CMakeLists.txt b/source/blender/editors/space_outliner/CMakeLists.txt index 289d6e715e1..18998b5de5c 100644 --- a/source/blender/editors/space_outliner/CMakeLists.txt +++ b/source/blender/editors/space_outliner/CMakeLists.txt @@ -37,6 +37,7 @@ set(INC_SYS ) set(SRC + outliner_collections.c outliner_draw.c outliner_edit.c outliner_ops.c diff --git a/source/blender/editors/space_outliner/outliner_collections.c b/source/blender/editors/space_outliner/outliner_collections.c new file mode 100644 index 00000000000..cf63e17870f --- /dev/null +++ b/source/blender/editors/space_outliner/outliner_collections.c @@ -0,0 +1,429 @@ +/* + * ***** 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. + * + * Contributor(s): Blender Foundation, Dalai Felinto + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/editors/space_outliner/outliner_collections.c + * \ingroup spoutliner + */ + +#include "BKE_context.h" +#include "BKE_collection.h" +#include "BKE_layer.h" +#include "BKE_report.h" + +#include "BLI_listbase.h" + +#include "ED_screen.h" + +#include "WM_api.h" +#include "WM_types.h" + +#include "RNA_access.h" +#include "RNA_define.h" +#include "RNA_enum_types.h" + +#include "UI_resources.h" + +#include "outliner_intern.h" /* own include */ + +/* -------------------------------------------------------------------- */ + +static LayerCollection *outliner_collection_active(bContext *C) +{ + TODO_LAYER_OPERATORS; + /* consider that we may have overrides or objects active + * leading to no active collections */ + return CTX_data_layer_collection(C); +} + +static CollectionOverride *outliner_override_active(bContext *UNUSED(C)) +{ + TODO_LAYER_OPERATORS; + TODO_LAYER_OVERRIDE; + return NULL; +} + +/* -------------------------------------------------------------------- */ +/* collection manager operators */ + +/** + * Recursively get the collection for a given index + */ +static SceneCollection *scene_collection_from_index(ListBase *lb, const int number, int *i) +{ + for (SceneCollection *sc = lb->first; sc; sc = sc->next) { + if (*i == number) { + return sc; + } + + (*i)++; + + SceneCollection *sc_nested = scene_collection_from_index(&sc->scene_collections, number, i); + if (sc_nested) { + return sc_nested; + } + } + return NULL; +} + +static int collection_link_exec(bContext *C, wmOperator *op) +{ + Scene *scene = CTX_data_scene(C); + SceneLayer *sl = CTX_data_scene_layer(C); + SceneCollection *sc_master = BKE_collection_master(scene); + SceneCollection *sc; + + int scene_collection_index = RNA_enum_get(op->ptr, "scene_collection"); + if (scene_collection_index == 0) { + sc = sc_master; + } + else { + int index = 1; + sc = scene_collection_from_index(&sc_master->scene_collections, scene_collection_index, &index); + BLI_assert(sc); + } + + BKE_collection_link(sl, sc); + + WM_main_add_notifier(NC_SCENE | ND_LAYER, NULL); + return OPERATOR_FINISHED; +} + +static int collection_link_invoke(bContext *C, wmOperator *op, const wmEvent *event) +{ + if (BKE_collection_master(CTX_data_scene(C))->scene_collections.first == NULL) { + RNA_enum_set(op->ptr, "scene_collection", 0); + return collection_link_exec(C, op); + } + else { + return WM_enum_search_invoke(C, op, event); + } +} + +static void collection_scene_collection_itemf_recursive( + EnumPropertyItem *tmp, EnumPropertyItem **item, int *totitem, int *value, SceneCollection *sc) +{ + tmp->value = *value; + tmp->icon = ICON_COLLAPSEMENU; + tmp->identifier = sc->name; + tmp->name = sc->name; + RNA_enum_item_add(item, totitem, tmp); + + (*value)++; + + for (SceneCollection *ncs = sc->scene_collections.first; ncs; ncs = ncs->next) { + collection_scene_collection_itemf_recursive(tmp, item, totitem, value, ncs); + } +} + +static EnumPropertyItem *collection_scene_collection_itemf(bContext *C, PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), bool *r_free) +{ + EnumPropertyItem tmp = {0, "", 0, "", ""}; + EnumPropertyItem *item = NULL; + int value = 0, totitem = 0; + + Scene *scene = CTX_data_scene(C); + SceneCollection *sc = BKE_collection_master(scene); + + collection_scene_collection_itemf_recursive(&tmp, &item, &totitem, &value, sc); + RNA_enum_item_end(&item, &totitem); + *r_free = true; + + return item; +} + +void OUTLINER_OT_collection_link(wmOperatorType *ot) +{ + PropertyRNA *prop; + + /* identifiers */ + ot->name = "Add Collection"; + ot->idname = "OUTLINER_OT_collection_link"; + ot->description = "Link a new collection to the active layer"; + + /* api callbacks */ + ot->exec = collection_link_exec; + ot->invoke = collection_link_invoke; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + prop = RNA_def_enum(ot->srna, "scene_collection", DummyRNA_NULL_items, 0, "Scene Collection", ""); + RNA_def_enum_funcs(prop, collection_scene_collection_itemf); + RNA_def_property_flag(prop, PROP_ENUM_NO_TRANSLATE); + ot->prop = prop; +} + +/** + * Returns true if selected element is a collection directly + * linked to the active SceneLayer (not a nested collection) + */ +static int collection_unlink_poll(bContext *C) +{ + LayerCollection *lc = outliner_collection_active(C); + + if (lc == NULL) { + return 0; + } + + SceneLayer *sl = CTX_data_scene_layer(C); + return BLI_findindex(&sl->layer_collections, lc) != -1 ? 1 : 0; +} + +static int collection_unlink_exec(bContext *C, wmOperator *op) +{ + LayerCollection *lc = outliner_collection_active(C); + + if (lc == NULL) { + BKE_report(op->reports, RPT_ERROR, "Active element is not a collection"); + return OPERATOR_CANCELLED; + } + + SceneLayer *sl = CTX_data_scene_layer(C); + BKE_collection_unlink(sl, lc); + + WM_main_add_notifier(NC_SCENE | ND_LAYER, NULL); + return OPERATOR_FINISHED; +} + +void OUTLINER_OT_collection_unlink(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Add Collection"; + ot->idname = "OUTLINER_OT_collection_unlink"; + ot->description = "Unlink collection from the active layer"; + + /* api callbacks */ + ot->exec = collection_unlink_exec; + ot->poll = collection_unlink_poll; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; +} + +static int collection_new_exec(bContext *C, wmOperator *UNUSED(op)) +{ + Scene *scene = CTX_data_scene(C); + SceneLayer *sl = CTX_data_scene_layer(C); + + SceneCollection *sc = BKE_collection_add(scene, NULL, NULL); + BKE_collection_link(sl, sc); + + WM_main_add_notifier(NC_SCENE | ND_LAYER, NULL); + return OPERATOR_FINISHED; +} + +void OUTLINER_OT_collection_new(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "New Collection"; + ot->idname = "OUTLINER_OT_collection_new"; + ot->description = "Add a new collection to the scene, and link it to the active layer"; + + /* api callbacks */ + ot->exec = collection_new_exec; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; +} + +/** + * Returns true is selected element is a collection + */ +static int collection_override_new_poll(bContext *(C)) +{ +#ifdef TODO_LAYER_OVERRIDE + /* disable for now, since it's not implemented */ + (void) C; + return 0; +#else + return outliner_collection_active(C) ? 1 : 0; +#endif +} + +static int collection_override_new_invoke(bContext *UNUSED(C), wmOperator *op, const wmEvent *UNUSED(event)) +{ + TODO_LAYER_OPERATORS; + TODO_LAYER_OVERRIDE; + BKE_report(op->reports, RPT_ERROR, "OUTLINER_OT_collections_override_new not implemented yet"); + return OPERATOR_CANCELLED; +} + +/* in the middle of renames remove s */ +void OUTLINER_OT_collection_override_new(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "New Override"; + ot->idname = "OUTLINER_OT_collection_override_new"; + ot->description = "Add a new override to the active collection"; + + /* api callbacks */ + ot->invoke = collection_override_new_invoke; + ot->poll = collection_override_new_poll; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; +} + +/** + * Returns true if selected element is a collection + * or an override, but not a master collection + */ +static int collection_delete_poll(bContext *C) +{ + LayerCollection *lc = outliner_collection_active(C); + + if (lc == NULL) { + /* try override */ + return outliner_override_active(C) ? 1 : 0; + } + + return (lc->scene_collection == BKE_collection_master(CTX_data_scene(C))) ? 0 : 1; +} + +static int collection_delete_exec(bContext *C, wmOperator *op) +{ + Scene *scene = CTX_data_scene(C); + LayerCollection *lc = outliner_collection_active(C); + + TODO_LAYER_OVERRIDE; /* handle operators */ + + if (lc == NULL) { + BKE_report(op->reports, RPT_ERROR, "Active element is not a collection"); + return OPERATOR_CANCELLED; + } + + if (lc->scene_collection == BKE_collection_master(scene)) { + BKE_report(op->reports, RPT_ERROR, "You cannot delete the master collection, try unliking it instead"); + return OPERATOR_CANCELLED; + } + + BKE_collection_remove(scene, lc->scene_collection); + + WM_main_add_notifier(NC_SCENE | ND_LAYER, NULL); + return OPERATOR_FINISHED; +} + +void OUTLINER_OT_collection_delete(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Delete"; + ot->idname = "OUTLINER_OT_collection_delete"; + ot->description = "Delete active override or collection"; + + /* api callbacks */ + ot->exec = collection_delete_exec; + ot->poll = collection_delete_poll; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; +} + +static int collection_select_exec(bContext *C, wmOperator *op) +{ + SceneLayer *sl = CTX_data_scene_layer(C); + const int collection_index = RNA_int_get(op->ptr, "collection_index"); + sl->active_collection = collection_index; + WM_main_add_notifier(NC_SCENE | ND_LAYER, NULL); + return OPERATOR_FINISHED; +} + +void OUTLINER_OT_collection_select(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Select"; + ot->idname = "OUTLINER_OT_collection_select"; + ot->description = "Change active collection or override"; + + /* api callbacks */ + ot->exec = collection_select_exec; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + RNA_def_int(ot->srna, "collection_index", 0, 0, INT_MAX, "Index", + "Index of collection to select", 0, INT_MAX); +} + +/* -------------------------------------------------------------------- */ + +static int stubs_invoke(bContext *UNUSED(C), wmOperator *op, const wmEvent *UNUSED(event)) +{ + TODO_LAYER_OPERATORS; + BKE_report(op->reports, RPT_ERROR, "Operator not implemented yet"); + return OPERATOR_CANCELLED; +} + +void OUTLINER_OT_collection_objects_add(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Add Objects"; + ot->idname = "OUTLINER_OT_collection_objects_add"; + ot->description = "Add selected objects to collection"; + + /* api callbacks */ + ot->invoke = stubs_invoke; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; +} + +void OUTLINER_OT_collection_objects_remove(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Remove Object"; + ot->idname = "OUTLINER_OT_collection_objects_remove"; + ot->description = "Remove objects from collection"; + + /* api callbacks */ + ot->invoke = stubs_invoke; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; +} + +void OUTLINER_OT_collection_objects_select(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Select Objects"; + ot->idname = "OUTLINER_OT_collection_objects_select"; + ot->description = "Select collection objects"; + + /* api callbacks */ + ot->invoke = stubs_invoke; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; +} + +void OUTLINER_OT_collection_objects_deselect(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Deselect Objects"; + ot->idname = "OUTLINER_OT_collection_objects_deselect"; + ot->description = "Deselect collection objects"; + + /* api callbacks */ + ot->invoke = stubs_invoke; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; +} diff --git a/source/blender/editors/space_outliner/outliner_draw.c b/source/blender/editors/space_outliner/outliner_draw.c index 99242fd12f9..f99ccd52bfc 100644 --- a/source/blender/editors/space_outliner/outliner_draw.c +++ b/source/blender/editors/space_outliner/outliner_draw.c @@ -51,6 +51,7 @@ #include "BKE_depsgraph.h" #include "BKE_fcurve.h" #include "BKE_global.h" +#include "BKE_layer.h" #include "BKE_library.h" #include "BKE_main.h" #include "BKE_modifier.h" @@ -69,6 +70,8 @@ #include "BIF_gl.h" #include "BIF_glutil.h" +#include "GPU_immediate.h" + #include "UI_interface.h" #include "UI_interface_icons.h" #include "UI_resources.h" @@ -172,116 +175,6 @@ static void restrictbutton_recursive_bone(Bone *bone_parent, int flag, bool set_ } -static void restrictbutton_recursive_child(bContext *C, Scene *scene, Object *ob_parent, char flag, - bool state, bool deselect, const char *rnapropname) -{ - Main *bmain = CTX_data_main(C); - Object *ob; - - for (ob = bmain->object.first; ob; ob = ob->id.next) { - if (BKE_object_is_child_recursive(ob_parent, ob)) { - /* only do if child object is selectable */ - if ((flag == OB_RESTRICT_SELECT) || (ob->restrictflag & OB_RESTRICT_SELECT) == 0) { - if (state) { - ob->restrictflag |= flag; - if (deselect) { - ED_base_object_select(BKE_scene_base_find(scene, ob), BA_DESELECT); - } - } - else { - ob->restrictflag &= ~flag; - } - } - - if (rnapropname) { - PointerRNA ptr; - PropertyRNA *prop; - ID *id; - bAction *action; - FCurve *fcu; - bool driven, special; - - RNA_id_pointer_create(&ob->id, &ptr); - prop = RNA_struct_find_property(&ptr, rnapropname); - fcu = rna_get_fcurve_context_ui(C, &ptr, prop, 0, NULL, &action, &driven, &special); - - if (fcu && !driven) { - id = ptr.id.data; - if (autokeyframe_cfra_can_key(scene, id)) { - ReportList *reports = CTX_wm_reports(C); - ToolSettings *ts = scene->toolsettings; - eInsertKeyFlags key_flag = ANIM_get_keyframing_flags(scene, 1); - - fcu->flag &= ~FCURVE_SELECTED; - insert_keyframe(reports, id, action, ((fcu->grp) ? (fcu->grp->name) : (NULL)), - fcu->rna_path, fcu->array_index, CFRA, ts->keyframe_type, key_flag); - /* Assuming this is not necessary here, since 'ancestor' object button will do it anyway. */ - /* WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL); */ - } - } - } - } - } -} - -static void restrictbutton_view_cb(bContext *C, void *poin, void *poin2) -{ - Scene *scene = (Scene *)poin; - Object *ob = (Object *)poin2; - - if (!common_restrict_check(C, ob)) return; - - /* deselect objects that are invisible */ - if (ob->restrictflag & OB_RESTRICT_VIEW) { - /* Ouch! There is no backwards pointer from Object to Base, - * so have to do loop to find it. */ - ED_base_object_select(BKE_scene_base_find(scene, ob), BA_DESELECT); - } - - if (CTX_wm_window(C)->eventstate->ctrl) { - restrictbutton_recursive_child(C, scene, ob, OB_RESTRICT_VIEW, - (ob->restrictflag & OB_RESTRICT_VIEW) != 0, true, "hide"); - } - - WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene); - -} - -static void restrictbutton_sel_cb(bContext *C, void *poin, void *poin2) -{ - Scene *scene = (Scene *)poin; - Object *ob = (Object *)poin2; - - if (!common_restrict_check(C, ob)) return; - - /* if select restriction has just been turned on */ - if (ob->restrictflag & OB_RESTRICT_SELECT) { - /* Ouch! There is no backwards pointer from Object to Base, - * so have to do loop to find it. */ - ED_base_object_select(BKE_scene_base_find(scene, ob), BA_DESELECT); - } - - if (CTX_wm_window(C)->eventstate->ctrl) { - restrictbutton_recursive_child(C, scene, ob, OB_RESTRICT_SELECT, - (ob->restrictflag & OB_RESTRICT_SELECT) != 0, true, NULL); - } - - WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene); - -} - -static void restrictbutton_rend_cb(bContext *C, void *poin, void *poin2) -{ - Object *ob = (Object *)poin2; - - if (CTX_wm_window(C)->eventstate->ctrl) { - restrictbutton_recursive_child(C, (Scene *)poin, ob, OB_RESTRICT_RENDER, - (ob->restrictflag & OB_RESTRICT_RENDER) != 0, false, "hide_render"); - } - - WM_event_add_notifier(C, NC_SCENE | ND_OB_RENDER, poin); -} - static void restrictbutton_r_lay_cb(bContext *C, void *poin, void *UNUSED(poin2)) { WM_event_add_notifier(C, NC_SCENE | ND_RENDER_OPTIONS, poin); @@ -355,96 +248,32 @@ static void restrictbutton_gp_layer_flag_cb(bContext *C, void *UNUSED(poin), voi WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL); } -static int group_restrict_flag(Group *gr, int flag) +static void restrictbutton_collection_hide_cb(bContext *C, void *poin, void *poin2) { - GroupObject *gob; - -#ifdef USE_GROUP_SELECT - for (gob = gr->gobject.first; gob; gob = gob->next) { - if ((gob->ob->restrictflag & flag) == 0) - return 0; - } - return 1; -#else - /* weak but fast */ - if ((gob = gr->gobject.first)) - if ((gob->ob->restrictflag & flag) == 0) - return 0; - return 1; -#endif -} + Scene *scene = poin; + LayerCollection *collection = poin2; + SceneLayer *sl = BKE_scene_layer_find_from_collection(scene, collection); -static int group_select_flag(Group *gr) -{ - GroupObject *gob; - -#ifdef USE_GROUP_SELECT - for (gob = gr->gobject.first; gob; gob = gob->next) - if ((gob->ob->flag & SELECT)) - return 1; - - return 0; -#else - /* weak but fast */ - if ((gob = gr->gobject.first)) - if (gob->ob->flag & SELECT) - return 1; - return 0; -#endif + /* hide and deselect bases that are directly influenced by this LayerCollection */ + BKE_scene_layer_base_flag_recalculate(sl); + BKE_scene_layer_engine_settings_collection_recalculate(sl, collection); + WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene); + WM_event_add_notifier(C, NC_SCENE | ND_LAYER_CONTENT, NULL); } -void restrictbutton_gr_restrict_flag(void *poin, void *poin2, int flag) +static void restrictbutton_collection_hide_select_cb(bContext *C, void *poin, void *poin2) { - Scene *scene = (Scene *)poin; - GroupObject *gob; - Group *gr = (Group *)poin2; + Scene *scene = poin; + LayerCollection *collection = poin2; - if (group_restrict_flag(gr, flag)) { - for (gob = gr->gobject.first; gob; gob = gob->next) { - if (ID_IS_LINKED_DATABLOCK(gob->ob)) - continue; + if ((collection->flag & COLLECTION_SELECTABLE) == 0) { + SceneLayer *sl = BKE_scene_layer_find_from_collection(scene, collection); - gob->ob->restrictflag &= ~flag; - - if (flag == OB_RESTRICT_VIEW) - if (gob->ob->flag & SELECT) - ED_base_object_select(BKE_scene_base_find(scene, gob->ob), BA_DESELECT); - } + /* deselect bases that are directly influenced by this LayerCollection */ + BKE_scene_layer_base_flag_recalculate(sl); + WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, CTX_data_scene(C)); } - else { - for (gob = gr->gobject.first; gob; gob = gob->next) { - if (ID_IS_LINKED_DATABLOCK(gob->ob)) - continue; - - /* not in editmode */ - if (scene->obedit != gob->ob) { - gob->ob->restrictflag |= flag; - - if (ELEM(flag, OB_RESTRICT_SELECT, OB_RESTRICT_VIEW)) { - if ((gob->ob->flag & SELECT)) { - ED_base_object_select(BKE_scene_base_find(scene, gob->ob), BA_DESELECT); - } - } - } - } - } -} - -static void restrictbutton_gr_restrict_view(bContext *C, void *poin, void *poin2) -{ - restrictbutton_gr_restrict_flag(poin, poin2, OB_RESTRICT_VIEW); - WM_event_add_notifier(C, NC_GROUP, NULL); - DAG_id_type_tag(CTX_data_main(C), ID_OB); -} -static void restrictbutton_gr_restrict_select(bContext *C, void *poin, void *poin2) -{ - restrictbutton_gr_restrict_flag(poin, poin2, OB_RESTRICT_SELECT); - WM_event_add_notifier(C, NC_GROUP, NULL); -} -static void restrictbutton_gr_restrict_render(bContext *C, void *poin, void *poin2) -{ - restrictbutton_gr_restrict_flag(poin, poin2, OB_RESTRICT_RENDER); - WM_event_add_notifier(C, NC_GROUP, NULL); + WM_event_add_notifier(C, NC_SCENE | ND_LAYER_CONTENT, NULL); } static void restrictbutton_id_user_toggle(bContext *UNUSED(C), void *poin, void *UNUSED(poin2)) @@ -466,6 +295,7 @@ static void namebutton_cb(bContext *C, void *tsep, char *oldname) { SpaceOops *soops = CTX_wm_space_outliner(C); Scene *scene = CTX_data_scene(C); + SceneLayer *sl = CTX_data_scene_layer(C); Object *obedit = CTX_data_edit_object(C); BLI_mempool *ts = soops->treestore; TreeStoreElem *tselem = tsep; @@ -527,7 +357,7 @@ static void namebutton_cb(bContext *C, void *tsep, char *oldname) BLI_strncpy(newname, ebone->name, sizeof(ebone->name)); BLI_strncpy(ebone->name, oldname, sizeof(ebone->name)); ED_armature_bone_rename(obedit->data, oldname, newname); - WM_event_add_notifier(C, NC_OBJECT | ND_POSE, OBACT); + WM_event_add_notifier(C, NC_OBJECT | ND_POSE, OBACT_NEW); } break; } @@ -539,8 +369,8 @@ static void namebutton_cb(bContext *C, void *tsep, char *oldname) char newname[sizeof(bone->name)]; /* always make current object active */ - tree_element_active(C, scene, soops, te, OL_SETSEL_NORMAL, true); - ob = OBACT; + tree_element_active(C, scene, sl, soops, te, OL_SETSEL_NORMAL, true); + ob = OBACT_NEW; /* restore bone name */ BLI_strncpy(newname, bone->name, sizeof(bone->name)); @@ -556,8 +386,8 @@ static void namebutton_cb(bContext *C, void *tsep, char *oldname) char newname[sizeof(pchan->name)]; /* always make current pose-bone active */ - tree_element_active(C, scene, soops, te, OL_SETSEL_NORMAL, true); - ob = OBACT; + tree_element_active(C, scene, sl, soops, te, OL_SETSEL_NORMAL, true); + ob = OBACT_NEW; BLI_assert(ob->type == OB_ARMATURE); @@ -603,7 +433,6 @@ static void outliner_draw_restrictbuts(uiBlock *block, Scene *scene, ARegion *ar TreeElement *te; TreeStoreElem *tselem; Object *ob = NULL; - Group *gr = NULL; PropertyRNA *object_prop_hide, *object_prop_hide_select, *object_prop_hide_render; @@ -617,73 +446,8 @@ static void outliner_draw_restrictbuts(uiBlock *block, Scene *scene, ARegion *ar for (te = lb->first; te; te = te->next) { tselem = TREESTORE(te); if (te->ys + 2 * UI_UNIT_Y >= ar->v2d.cur.ymin && te->ys <= ar->v2d.cur.ymax) { - /* objects have toggle-able restriction flags */ - if (tselem->type == 0 && te->idcode == ID_OB) { - PointerRNA ptr; - - ob = (Object *)tselem->id; - RNA_pointer_create((ID *)ob, &RNA_Object, ob, &ptr); - - UI_block_emboss_set(block, UI_EMBOSS_NONE); - bt = uiDefIconButR_prop(block, UI_BTYPE_ICON_TOGGLE, 0, ICON_RESTRICT_VIEW_OFF, - (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_VIEWX), te->ys, UI_UNIT_X, UI_UNIT_Y, - &ptr, object_prop_hide, -1, 0, 0, -1, -1, - TIP_("Restrict viewport visibility (Ctrl - Recursive)")); - UI_but_func_set(bt, restrictbutton_view_cb, scene, ob); - UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK); - - bt = uiDefIconButR_prop(block, UI_BTYPE_ICON_TOGGLE, 0, ICON_RESTRICT_SELECT_OFF, - (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_SELECTX), te->ys, UI_UNIT_X, UI_UNIT_Y, - &ptr, object_prop_hide_select, -1, 0, 0, -1, -1, - TIP_("Restrict viewport selection (Ctrl - Recursive)")); - UI_but_func_set(bt, restrictbutton_sel_cb, scene, ob); - UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK); - - bt = uiDefIconButR_prop(block, UI_BTYPE_ICON_TOGGLE, 0, ICON_RESTRICT_RENDER_OFF, - (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_RENDERX), te->ys, UI_UNIT_X, UI_UNIT_Y, - &ptr, object_prop_hide_render, -1, 0, 0, -1, -1, - TIP_("Restrict rendering (Ctrl - Recursive)")); - UI_but_func_set(bt, restrictbutton_rend_cb, scene, ob); - UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK); - - UI_block_emboss_set(block, UI_EMBOSS); - - } - if (tselem->type == 0 && te->idcode == ID_GR) { - int restrict_bool; - int but_flag = UI_BUT_DRAG_LOCK; - gr = (Group *)tselem->id; - - if (ID_IS_LINKED_DATABLOCK(gr)) - but_flag |= UI_BUT_DISABLED; - - UI_block_emboss_set(block, UI_EMBOSS_NONE); - - restrict_bool = group_restrict_flag(gr, OB_RESTRICT_VIEW); - bt = uiDefIconBut(block, UI_BTYPE_ICON_TOGGLE, 0, restrict_bool ? ICON_RESTRICT_VIEW_ON : ICON_RESTRICT_VIEW_OFF, - (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_VIEWX), te->ys, UI_UNIT_X, UI_UNIT_Y, - NULL, 0, 0, 0, 0, TIP_("Restrict/Allow visibility in the 3D View")); - UI_but_func_set(bt, restrictbutton_gr_restrict_view, scene, gr); - UI_but_flag_enable(bt, but_flag); - - restrict_bool = group_restrict_flag(gr, OB_RESTRICT_SELECT); - bt = uiDefIconBut(block, UI_BTYPE_ICON_TOGGLE, 0, restrict_bool ? ICON_RESTRICT_SELECT_ON : ICON_RESTRICT_SELECT_OFF, - (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_SELECTX), te->ys, UI_UNIT_X, UI_UNIT_Y, - NULL, 0, 0, 0, 0, TIP_("Restrict/Allow selection in the 3D View")); - UI_but_func_set(bt, restrictbutton_gr_restrict_select, scene, gr); - UI_but_flag_enable(bt, but_flag); - - restrict_bool = group_restrict_flag(gr, OB_RESTRICT_RENDER); - bt = uiDefIconBut(block, UI_BTYPE_ICON_TOGGLE, 0, restrict_bool ? ICON_RESTRICT_RENDER_ON : ICON_RESTRICT_RENDER_OFF, - (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_RENDERX), te->ys, UI_UNIT_X, UI_UNIT_Y, - NULL, 0, 0, 0, 0, TIP_("Restrict/Allow renderability")); - UI_but_func_set(bt, restrictbutton_gr_restrict_render, scene, gr); - UI_but_flag_enable(bt, but_flag); - - UI_block_emboss_set(block, UI_EMBOSS); - } /* scene render layers and passes have toggle-able flags too! */ - else if (tselem->type == TSE_R_LAYER) { + if (tselem->type == TSE_R_LAYER) { UI_block_emboss_set(block, UI_EMBOSS_NONE); bt = uiDefIconButBitI(block, UI_BTYPE_ICON_TOGGLE_N, SCE_LAY_DISABLE, 0, ICON_CHECKBOX_HLT - 1, @@ -805,6 +569,27 @@ static void outliner_draw_restrictbuts(uiBlock *block, Scene *scene, ARegion *ar UI_block_emboss_set(block, UI_EMBOSS); } + else if (tselem->type == TSE_COLLECTION) { + LayerCollection *collection = te->directdata; + + UI_block_emboss_set(block, UI_EMBOSS_NONE); + + bt = uiDefIconButBitS(block, UI_BTYPE_ICON_TOGGLE_N, COLLECTION_VISIBLE, 0, ICON_RESTRICT_VIEW_OFF, + (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_VIEWX), te->ys, UI_UNIT_X, + UI_UNIT_Y, &collection->flag, 0, 0, 0, 0, + TIP_("Restrict/Allow 3D View visibility of objects in the collection")); + UI_but_func_set(bt, restrictbutton_collection_hide_cb, scene, collection); + UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK); + + bt = uiDefIconButBitS(block, UI_BTYPE_ICON_TOGGLE_N, COLLECTION_SELECTABLE, 0, ICON_RESTRICT_SELECT_OFF, + (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_SELECTX), te->ys, UI_UNIT_X, + UI_UNIT_Y, &collection->flag, 0, 0, 0, 0, + TIP_("Restrict/Allow 3D View selection of objects in the collection")); + UI_but_func_set(bt, restrictbutton_collection_hide_select_cb, scene, collection); + UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK); + + UI_block_emboss_set(block, UI_EMBOSS); + } } if (TSELEM_OPEN(tselem, soops)) outliner_draw_restrictbuts(block, scene, ar, soops, &te->subtree); @@ -878,6 +663,7 @@ static void outliner_draw_rnacols(ARegion *ar, int sizex) float miny = v2d->cur.ymin; if (miny < v2d->tot.ymin) miny = v2d->tot.ymin; + glLineWidth(1.0f); UI_ThemeColorShadeAlpha(TH_BACK, -15, -200); /* draw column separator lines */ @@ -987,7 +773,7 @@ static void tselem_draw_icon_uibut(struct DrawIconArg *arg, int icon) /* restrict column clip... it has been coded by simply overdrawing, doesnt work for buttons */ if (arg->x >= arg->xmax) { glEnable(GL_BLEND); - UI_icon_draw_aspect(arg->x, arg->y, icon, 1.0f / UI_DPI_FAC, arg->alpha); + UI_icon_draw_alpha(arg->x, arg->y, icon, arg->alpha); glDisable(GL_BLEND); } else { @@ -1050,189 +836,258 @@ static void tselem_draw_icon(uiBlock *block, int xmax, float x, float y, TreeSto arg.xb = x; /* for ui buttons */ arg.yb = y; arg.alpha = alpha; - + /* placement of icons, copied from interface_widgets.c */ aspect = (0.8f * UI_UNIT_Y) / ICON_DEFAULT_HEIGHT; arg.x = x = x + 4.0f * aspect; arg.y = y = y + 0.1f * UI_UNIT_Y; +#define ICON_DRAW(_icon) UI_icon_draw_alpha(x, y, _icon, alpha) + if (tselem->type) { switch (tselem->type) { case TSE_ANIM_DATA: - UI_icon_draw(x, y, ICON_ANIM_DATA); break; // xxx + ICON_DRAW(ICON_ANIM_DATA); /* XXX */ + break; case TSE_NLA: - UI_icon_draw(x, y, ICON_NLA); break; + ICON_DRAW(ICON_NLA); + break; case TSE_NLA_TRACK: - UI_icon_draw(x, y, ICON_NLA); break; // XXX + ICON_DRAW(ICON_NLA); /* XXX */ + break; case TSE_NLA_ACTION: - UI_icon_draw(x, y, ICON_ACTION); break; + ICON_DRAW(ICON_ACTION); + break; case TSE_DRIVER_BASE: - UI_icon_draw(x, y, ICON_DRIVER); break; + ICON_DRAW(ICON_DRIVER); + break; case TSE_DEFGROUP_BASE: - UI_icon_draw(x, y, ICON_GROUP_VERTEX); break; + ICON_DRAW(ICON_GROUP_VERTEX); + break; case TSE_BONE: case TSE_EBONE: - UI_icon_draw(x, y, ICON_BONE_DATA); break; + ICON_DRAW(ICON_BONE_DATA); + break; case TSE_CONSTRAINT_BASE: - UI_icon_draw(x, y, ICON_CONSTRAINT); break; + ICON_DRAW(ICON_CONSTRAINT); + break; case TSE_MODIFIER_BASE: - UI_icon_draw(x, y, ICON_MODIFIER); break; + ICON_DRAW(ICON_MODIFIER); + break; case TSE_LINKED_OB: - UI_icon_draw(x, y, ICON_OBJECT_DATA); break; + ICON_DRAW(ICON_OBJECT_DATA); + break; case TSE_LINKED_PSYS: - UI_icon_draw(x, y, ICON_PARTICLES); break; + ICON_DRAW(ICON_PARTICLES); + break; case TSE_MODIFIER: { Object *ob = (Object *)tselem->id; ModifierData *md = BLI_findlink(&ob->modifiers, tselem->nr); switch ((ModifierType)md->type) { - case eModifierType_Subsurf: - UI_icon_draw(x, y, ICON_MOD_SUBSURF); break; - case eModifierType_Armature: - UI_icon_draw(x, y, ICON_MOD_ARMATURE); break; - case eModifierType_Lattice: - UI_icon_draw(x, y, ICON_MOD_LATTICE); break; - case eModifierType_Curve: - UI_icon_draw(x, y, ICON_MOD_CURVE); break; - case eModifierType_Build: - UI_icon_draw(x, y, ICON_MOD_BUILD); break; - case eModifierType_Mirror: - UI_icon_draw(x, y, ICON_MOD_MIRROR); break; - case eModifierType_Decimate: - UI_icon_draw(x, y, ICON_MOD_DECIM); break; - case eModifierType_Wave: - UI_icon_draw(x, y, ICON_MOD_WAVE); break; - case eModifierType_Hook: - UI_icon_draw(x, y, ICON_HOOK); break; - case eModifierType_Softbody: - UI_icon_draw(x, y, ICON_MOD_SOFT); break; - case eModifierType_Boolean: - UI_icon_draw(x, y, ICON_MOD_BOOLEAN); break; - case eModifierType_ParticleSystem: - UI_icon_draw(x, y, ICON_MOD_PARTICLES); break; + case eModifierType_Subsurf: + ICON_DRAW(ICON_MOD_SUBSURF); + break; + case eModifierType_Armature: + ICON_DRAW(ICON_MOD_ARMATURE); + break; + case eModifierType_Lattice: + ICON_DRAW(ICON_MOD_LATTICE); + break; + case eModifierType_Curve: + ICON_DRAW(ICON_MOD_CURVE); + break; + case eModifierType_Build: + ICON_DRAW(ICON_MOD_BUILD); + break; + case eModifierType_Mirror: + ICON_DRAW(ICON_MOD_MIRROR); + break; + case eModifierType_Decimate: + ICON_DRAW(ICON_MOD_DECIM); + break; + case eModifierType_Wave: + ICON_DRAW(ICON_MOD_WAVE); + break; + case eModifierType_Hook: + ICON_DRAW(ICON_HOOK); + break; + case eModifierType_Softbody: + ICON_DRAW(ICON_MOD_SOFT); + break; + case eModifierType_Boolean: + ICON_DRAW(ICON_MOD_BOOLEAN); + break; + case eModifierType_ParticleSystem: + ICON_DRAW(ICON_MOD_PARTICLES); + break; case eModifierType_ParticleInstance: - UI_icon_draw(x, y, ICON_MOD_PARTICLES); break; + ICON_DRAW(ICON_MOD_PARTICLES); + break; case eModifierType_EdgeSplit: - UI_icon_draw(x, y, ICON_MOD_EDGESPLIT); break; + ICON_DRAW(ICON_MOD_EDGESPLIT); + break; case eModifierType_Array: - UI_icon_draw(x, y, ICON_MOD_ARRAY); break; + ICON_DRAW(ICON_MOD_ARRAY); + break; case eModifierType_UVProject: case eModifierType_UVWarp: /* TODO, get own icon */ - UI_icon_draw(x, y, ICON_MOD_UVPROJECT); break; + ICON_DRAW(ICON_MOD_UVPROJECT); + break; case eModifierType_Displace: - UI_icon_draw(x, y, ICON_MOD_DISPLACE); break; + ICON_DRAW(ICON_MOD_DISPLACE); + break; case eModifierType_Shrinkwrap: - UI_icon_draw(x, y, ICON_MOD_SHRINKWRAP); break; + ICON_DRAW(ICON_MOD_SHRINKWRAP); + break; case eModifierType_Cast: - UI_icon_draw(x, y, ICON_MOD_CAST); break; + ICON_DRAW(ICON_MOD_CAST); + break; case eModifierType_MeshDeform: - UI_icon_draw(x, y, ICON_MOD_MESHDEFORM); break; + ICON_DRAW(ICON_MOD_MESHDEFORM); + break; case eModifierType_Bevel: - UI_icon_draw(x, y, ICON_MOD_BEVEL); break; + ICON_DRAW(ICON_MOD_BEVEL); + break; case eModifierType_Smooth: case eModifierType_LaplacianSmooth: case eModifierType_CorrectiveSmooth: - UI_icon_draw(x, y, ICON_MOD_SMOOTH); break; + ICON_DRAW(ICON_MOD_SMOOTH); + break; case eModifierType_SimpleDeform: - UI_icon_draw(x, y, ICON_MOD_SIMPLEDEFORM); break; + ICON_DRAW(ICON_MOD_SIMPLEDEFORM); + break; case eModifierType_Mask: - UI_icon_draw(x, y, ICON_MOD_MASK); break; + ICON_DRAW(ICON_MOD_MASK); + break; case eModifierType_Cloth: - UI_icon_draw(x, y, ICON_MOD_CLOTH); break; + ICON_DRAW(ICON_MOD_CLOTH); + break; case eModifierType_Explode: - UI_icon_draw(x, y, ICON_MOD_EXPLODE); break; + ICON_DRAW(ICON_MOD_EXPLODE); + break; case eModifierType_Collision: case eModifierType_Surface: - UI_icon_draw(x, y, ICON_MOD_PHYSICS); break; + ICON_DRAW(ICON_MOD_PHYSICS); + break; case eModifierType_Fluidsim: - UI_icon_draw(x, y, ICON_MOD_FLUIDSIM); break; + ICON_DRAW(ICON_MOD_FLUIDSIM); + break; case eModifierType_Multires: - UI_icon_draw(x, y, ICON_MOD_MULTIRES); break; + ICON_DRAW(ICON_MOD_MULTIRES); + break; case eModifierType_Smoke: - UI_icon_draw(x, y, ICON_MOD_SMOKE); break; + ICON_DRAW(ICON_MOD_SMOKE); + break; case eModifierType_Solidify: - UI_icon_draw(x, y, ICON_MOD_SOLIDIFY); break; + ICON_DRAW(ICON_MOD_SOLIDIFY); + break; case eModifierType_Screw: - UI_icon_draw(x, y, ICON_MOD_SCREW); break; + ICON_DRAW(ICON_MOD_SCREW); + break; case eModifierType_Remesh: - UI_icon_draw(x, y, ICON_MOD_REMESH); break; + ICON_DRAW(ICON_MOD_REMESH); + break; case eModifierType_WeightVGEdit: case eModifierType_WeightVGMix: case eModifierType_WeightVGProximity: - UI_icon_draw(x, y, ICON_MOD_VERTEX_WEIGHT); break; + ICON_DRAW(ICON_MOD_VERTEX_WEIGHT); + break; case eModifierType_DynamicPaint: - UI_icon_draw(x, y, ICON_MOD_DYNAMICPAINT); break; + ICON_DRAW(ICON_MOD_DYNAMICPAINT); + break; case eModifierType_Ocean: - UI_icon_draw(x, y, ICON_MOD_OCEAN); break; + ICON_DRAW(ICON_MOD_OCEAN); + break; case eModifierType_Warp: - UI_icon_draw(x, y, ICON_MOD_WARP); break; + ICON_DRAW(ICON_MOD_WARP); + break; case eModifierType_Skin: - UI_icon_draw(x, y, ICON_MOD_SKIN); break; + ICON_DRAW(ICON_MOD_SKIN); + break; case eModifierType_Triangulate: - UI_icon_draw(x, y, ICON_MOD_TRIANGULATE); break; + ICON_DRAW(ICON_MOD_TRIANGULATE); + break; case eModifierType_MeshCache: - UI_icon_draw(x, y, ICON_MOD_MESHDEFORM); break; /* XXX, needs own icon */ + ICON_DRAW(ICON_MOD_MESHDEFORM); /* XXX, needs own icon */ + break; case eModifierType_MeshSequenceCache: - UI_icon_draw(x, y, ICON_MOD_MESHDEFORM); break; /* XXX, needs own icon */ + ICON_DRAW(ICON_MOD_MESHDEFORM); /* XXX, needs own icon */ + break; case eModifierType_Wireframe: - UI_icon_draw(x, y, ICON_MOD_WIREFRAME); break; + ICON_DRAW(ICON_MOD_WIREFRAME); + break; case eModifierType_LaplacianDeform: - UI_icon_draw(x, y, ICON_MOD_MESHDEFORM); break; /* XXX, needs own icon */ + ICON_DRAW(ICON_MOD_MESHDEFORM); /* XXX, needs own icon */ + break; case eModifierType_DataTransfer: - UI_icon_draw(x, y, ICON_MOD_DATA_TRANSFER); break; + ICON_DRAW(ICON_MOD_DATA_TRANSFER); + break; case eModifierType_NormalEdit: - UI_icon_draw(x, y, ICON_MOD_NORMALEDIT); break; + ICON_DRAW(ICON_MOD_NORMALEDIT); + break; /* Default */ case eModifierType_None: case eModifierType_ShapeKey: case NUM_MODIFIER_TYPES: - UI_icon_draw(x, y, ICON_DOT); break; + ICON_DRAW(ICON_DOT); + break; } break; } case TSE_POSE_BASE: - UI_icon_draw(x, y, ICON_ARMATURE_DATA); break; + ICON_DRAW(ICON_ARMATURE_DATA); + break; case TSE_POSE_CHANNEL: - UI_icon_draw(x, y, ICON_BONE_DATA); break; + ICON_DRAW(ICON_BONE_DATA); + break; case TSE_PROXY: - UI_icon_draw(x, y, ICON_GHOST); break; + ICON_DRAW(ICON_GHOST); + break; case TSE_R_LAYER_BASE: - UI_icon_draw(x, y, ICON_RENDERLAYERS); break; + ICON_DRAW(ICON_RENDERLAYERS); + break; case TSE_R_LAYER: - UI_icon_draw(x, y, ICON_RENDERLAYERS); break; + ICON_DRAW(ICON_RENDERLAYERS); + break; case TSE_LINKED_LAMP: - UI_icon_draw(x, y, ICON_LAMP_DATA); break; + ICON_DRAW(ICON_LAMP_DATA); + break; case TSE_LINKED_MAT: - UI_icon_draw(x, y, ICON_MATERIAL_DATA); break; + ICON_DRAW(ICON_MATERIAL_DATA); + break; case TSE_POSEGRP_BASE: - UI_icon_draw(x, y, ICON_GROUP_BONE); break; + ICON_DRAW(ICON_GROUP_BONE); + break; case TSE_SEQUENCE: if (te->idcode == SEQ_TYPE_MOVIE) - UI_icon_draw(x, y, ICON_SEQUENCE); + ICON_DRAW(ICON_SEQUENCE); else if (te->idcode == SEQ_TYPE_META) - UI_icon_draw(x, y, ICON_DOT); + ICON_DRAW(ICON_DOT); else if (te->idcode == SEQ_TYPE_SCENE) - UI_icon_draw(x, y, ICON_SCENE); + ICON_DRAW(ICON_SCENE); else if (te->idcode == SEQ_TYPE_SOUND_RAM) - UI_icon_draw(x, y, ICON_SOUND); + ICON_DRAW(ICON_SOUND); else if (te->idcode == SEQ_TYPE_IMAGE) - UI_icon_draw(x, y, ICON_IMAGE_COL); + ICON_DRAW(ICON_IMAGE_COL); else - UI_icon_draw(x, y, ICON_PARTICLES); + ICON_DRAW(ICON_PARTICLES); break; case TSE_SEQ_STRIP: - UI_icon_draw(x, y, ICON_LIBRARY_DATA_DIRECT); + ICON_DRAW(ICON_LIBRARY_DATA_DIRECT); break; case TSE_SEQUENCE_DUP: - UI_icon_draw(x, y, ICON_OBJECT_DATA); + ICON_DRAW(ICON_OBJECT_DATA); break; case TSE_RNA_STRUCT: if (RNA_struct_is_ID(te->rnaptr.type)) { arg.id = (ID *)te->rnaptr.data; tselem_draw_icon_uibut(&arg, RNA_struct_ui_icon(te->rnaptr.type)); } - else - UI_icon_draw(x, y, RNA_struct_ui_icon(te->rnaptr.type)); + else { + int icon = RNA_struct_ui_icon(te->rnaptr.type); + ICON_DRAW(icon); + } break; /* Removed the icons from outliner. Need a better structure with Layers, Palettes and Colors */ #if 0 @@ -1241,7 +1096,8 @@ static void tselem_draw_icon(uiBlock *block, int xmax, float x, float y, TreeSto break; #endif default: - UI_icon_draw(x, y, ICON_DOT); break; + ICON_DRAW(ICON_DOT); + break; } } else if (tselem->id) { @@ -1346,17 +1202,18 @@ static void tselem_draw_icon(uiBlock *block, int xmax, float x, float y, TreeSto } } } + +#undef ICON_DRAW } -static void outliner_draw_iconrow(bContext *C, uiBlock *block, Scene *scene, SpaceOops *soops, ListBase *lb, int level, - int xmax, int *offsx, int ys) +static void outliner_draw_iconrow(bContext *C, uiBlock *block, Scene *scene, SceneLayer *sl, SpaceOops *soops, + ListBase *lb, int level, int xmax, int *offsx, int ys, float alpha_fac) { TreeElement *te; TreeStoreElem *tselem; eOLDrawState active; for (te = lb->first; te; te = te->next) { - /* exit drawing early */ if ((*offsx) - UI_UNIT_X > xmax) break; @@ -1369,34 +1226,37 @@ static void outliner_draw_iconrow(bContext *C, uiBlock *block, Scene *scene, Spa /* active blocks get white circle */ if (tselem->type == 0) { if (te->idcode == ID_OB) { - active = (OBACT == (Object *)tselem->id) ? OL_DRAWSEL_NORMAL : OL_DRAWSEL_NONE; + active = (OBACT_NEW == (Object *)tselem->id) ? OL_DRAWSEL_NORMAL : OL_DRAWSEL_NONE; } else if (scene->obedit && scene->obedit->data == tselem->id) { active = OL_DRAWSEL_NORMAL; } else { - active = tree_element_active(C, scene, soops, te, OL_SETSEL_NONE, false); + active = tree_element_active(C, scene, sl, soops, te, OL_SETSEL_NONE, false); } } else { - active = tree_element_type_active(NULL, scene, soops, te, tselem, OL_SETSEL_NONE, false); + active = tree_element_type_active(NULL, scene, sl, soops, te, tselem, OL_SETSEL_NONE, false); } if (active != OL_DRAWSEL_NONE) { float ufac = UI_UNIT_X / 20.0f; + float color[4] = {1.0f, 1.0f, 1.0f, 0.4f}; UI_draw_roundbox_corner_set(UI_CNR_ALL); - glColor4ub(255, 255, 255, 100); + color[3] *= alpha_fac; + UI_draw_roundbox( (float) *offsx - 1.0f * ufac, (float)ys + 1.0f * ufac, (float)*offsx + UI_UNIT_X - 2.0f * ufac, (float)ys + UI_UNIT_Y - ufac, - (float)UI_UNIT_Y / 2.0f - ufac); + (float)UI_UNIT_Y / 2.0f - ufac, + color); glEnable(GL_BLEND); /* roundbox disables */ } - tselem_draw_icon(block, xmax, (float)*offsx, (float)ys, tselem, te, 0.5f); + tselem_draw_icon(block, xmax, (float)*offsx, (float)ys, tselem, te, 0.5f * alpha_fac); te->xs = *offsx; te->ys = ys; te->xend = (short)*offsx + UI_UNIT_X; @@ -1407,7 +1267,7 @@ static void outliner_draw_iconrow(bContext *C, uiBlock *block, Scene *scene, Spa /* this tree element always has same amount of branches, so don't draw */ if (tselem->type != TSE_R_LAYER) - outliner_draw_iconrow(C, block, scene, soops, &te->subtree, level + 1, xmax, offsx, ys); + outliner_draw_iconrow(C, block, scene, sl, soops, &te->subtree, level + 1, xmax, offsx, ys, alpha_fac); } } @@ -1416,11 +1276,14 @@ static void outliner_draw_iconrow(bContext *C, uiBlock *block, Scene *scene, Spa static void outliner_set_coord_tree_element(TreeElement *te, int startx, int starty) { TreeElement *ten; - - /* store coord and continue, we need coordinates for elements outside view too */ - te->xs = startx; - te->ys = starty; - + + /* closed items may be displayed in row of parent, don't change their coordinate! */ + if ((te->flag & TE_ICONROW) == 0) { + /* store coord and continue, we need coordinates for elements outside view too */ + te->xs = startx; + te->ys = starty; + } + for (ten = te->subtree.first; ten; ten = ten->next) { outliner_set_coord_tree_element(ten, startx + UI_UNIT_X, starty); } @@ -1428,24 +1291,28 @@ static void outliner_set_coord_tree_element(TreeElement *te, int startx, int sta static void outliner_draw_tree_element( - bContext *C, uiBlock *block, const uiFontStyle *fstyle, Scene *scene, ARegion *ar, SpaceOops *soops, - TreeElement *te, int startx, int *starty, TreeElement **te_edit) + bContext *C, uiBlock *block, const uiFontStyle *fstyle, Scene *scene, SceneLayer *sl, + ARegion *ar, SpaceOops *soops, TreeElement *te, bool draw_grayed_out, + int startx, int *starty, TreeElement **te_edit, TreeElement **te_floating) { - TreeElement *ten; TreeStoreElem *tselem; float ufac = UI_UNIT_X / 20.0f; int offsx = 0; eOLDrawState active = OL_DRAWSEL_NONE; - + float color[4]; tselem = TREESTORE(te); if (*starty + 2 * UI_UNIT_Y >= ar->v2d.cur.ymin && *starty <= ar->v2d.cur.ymax) { + const float alpha_fac = draw_grayed_out ? 0.5f : 1.0f; + const float alpha = 0.5f * alpha_fac; int xmax = ar->v2d.cur.xmax; - unsigned char alpha = 128; - + if ((tselem->flag & TSE_TEXTBUT) && (*te_edit == NULL)) { *te_edit = te; } + if ((te->drag_data != NULL) && (*te_floating == NULL)) { + *te_floating = te; + } /* icons can be ui buts, we don't want it to overlap with restrict */ if ((soops->flag & SO_HIDE_RESTRICTCOLS) == 0) @@ -1453,50 +1320,24 @@ static void outliner_draw_tree_element( glEnable(GL_BLEND); - /* start by highlighting search matches - * we don't expand items when searching in the datablocks but we - * still want to highlight any filter matches. - */ - if ((SEARCHING_OUTLINER(soops) || (soops->outlinevis == SO_DATABLOCKS && soops->search_string[0] != 0)) && - (tselem->flag & TSE_SEARCHMATCH)) - { - char col[4]; - UI_GetThemeColorType4ubv(TH_MATCH, SPACE_OUTLINER, col); - col[3] = alpha; - glColor4ubv((GLubyte *)col); - glRecti(startx, *starty + 1, ar->v2d.cur.xmax, *starty + UI_UNIT_Y - 1); - } - /* colors for active/selected data */ if (tselem->type == 0) { - if (te->idcode == ID_SCE) { if (tselem->id == (ID *)scene) { - glColor4ub(255, 255, 255, alpha); - active = OL_DRAWSEL_ACTIVE; - } - } - else if (te->idcode == ID_GR) { - Group *gr = (Group *)tselem->id; - if (group_select_flag(gr)) { - char col[4]; - UI_GetThemeColorType4ubv(TH_SELECT, SPACE_VIEW3D, col); - col[3] = alpha; - glColor4ubv((GLubyte *)col); - + rgba_float_args_set(color, 1.0f, 1.0f, 1.0f, alpha); active = OL_DRAWSEL_ACTIVE; } } else if (te->idcode == ID_OB) { Object *ob = (Object *)tselem->id; - if (ob == OBACT || (ob->flag & SELECT)) { + if (ob == OBACT_NEW || (ob->flag & SELECT)) { char col[4] = {0, 0, 0, 0}; /* outliner active ob: always white text, circle color now similar to view3d */ active = OL_DRAWSEL_ACTIVE; - if (ob == OBACT) { + if (ob == OBACT_NEW) { if (ob->flag & SELECT) { UI_GetThemeColorType4ubv(TH_ACTIVE, SPACE_VIEW3D, col); col[3] = alpha; @@ -1508,27 +1349,26 @@ static void outliner_draw_tree_element( UI_GetThemeColorType4ubv(TH_SELECT, SPACE_VIEW3D, col); col[3] = alpha; } - - glColor4ubv((GLubyte *)col); + rgba_float_args_set(color, (float)col[0] / 255, (float)col[1] / 255, (float)col[2] / 255, alpha); } } else if (scene->obedit && scene->obedit->data == tselem->id) { - glColor4ub(255, 255, 255, alpha); + rgba_float_args_set(color, 1.0f, 1.0f, 1.0f, alpha); active = OL_DRAWSEL_ACTIVE; } else { - if (tree_element_active(C, scene, soops, te, OL_SETSEL_NONE, false)) { - glColor4ub(220, 220, 255, alpha); + if (tree_element_active(C, scene, sl, soops, te, OL_SETSEL_NONE, false)) { + rgba_float_args_set(color, 0.85f, 0.85f, 1.0f, alpha); active = OL_DRAWSEL_ACTIVE; } } } else { - if (tree_element_type_active(NULL, scene, soops, te, tselem, OL_SETSEL_NONE, false) != OL_DRAWSEL_NONE) { + if (tree_element_type_active(NULL, scene, sl, soops, te, tselem, OL_SETSEL_NONE, false) != OL_DRAWSEL_NONE) { active = OL_DRAWSEL_ACTIVE; } - glColor4ub(220, 220, 255, alpha); + rgba_float_args_set(color, 0.85f, 0.85f, 1.0f, alpha); } /* active circle */ @@ -1539,7 +1379,7 @@ static void outliner_draw_tree_element( (float)*starty + 1.0f * ufac, (float)startx + 2.0f * UI_UNIT_X - 2.0f * ufac, (float)*starty + UI_UNIT_Y - 1.0f * ufac, - UI_UNIT_Y / 2.0f - 1.0f * ufac); + UI_UNIT_Y / 2.0f - 1.0f * ufac, color); glEnable(GL_BLEND); /* roundbox disables it */ te->flag |= TE_ACTIVE; // for lookup in display hierarchies @@ -1552,55 +1392,60 @@ static void outliner_draw_tree_element( icon_x = startx; else icon_x = startx + 5 * ufac; - + // icons a bit higher if (TSELEM_OPEN(tselem, soops)) - UI_icon_draw((float)icon_x, (float)*starty + 2 * ufac, ICON_DISCLOSURE_TRI_DOWN); + UI_icon_draw_alpha((float)icon_x, (float)*starty + 2 * ufac, ICON_DISCLOSURE_TRI_DOWN, + alpha_fac); else - UI_icon_draw((float)icon_x, (float)*starty + 2 * ufac, ICON_DISCLOSURE_TRI_RIGHT); + UI_icon_draw_alpha((float)icon_x, (float)*starty + 2 * ufac, ICON_DISCLOSURE_TRI_RIGHT, + alpha_fac); } offsx += UI_UNIT_X; /* datatype icon */ if (!(ELEM(tselem->type, TSE_RNA_PROPERTY, TSE_RNA_ARRAY_ELEM))) { - - tselem_draw_icon(block, xmax, (float)startx + offsx, (float)*starty, tselem, te, 1.0f); - + tselem_draw_icon(block, xmax, (float)startx + offsx, (float)*starty, tselem, te, alpha_fac); offsx += UI_UNIT_X; } else offsx += 2 * ufac; if (tselem->type == 0 && ID_IS_LINKED_DATABLOCK(tselem->id)) { - glPixelTransferf(GL_ALPHA_SCALE, 0.5f); if (tselem->id->tag & LIB_TAG_MISSING) { - UI_icon_draw((float)startx + offsx, (float)*starty + 2 * ufac, ICON_LIBRARY_DATA_BROKEN); + UI_icon_draw_alpha((float)startx + offsx, (float)*starty + 2 * ufac, ICON_LIBRARY_DATA_BROKEN, + alpha_fac); } else if (tselem->id->tag & LIB_TAG_INDIRECT) { - UI_icon_draw((float)startx + offsx, (float)*starty + 2 * ufac, ICON_LIBRARY_DATA_INDIRECT); + UI_icon_draw_alpha((float)startx + offsx, (float)*starty + 2 * ufac, ICON_LIBRARY_DATA_INDIRECT, + alpha_fac); } else { - UI_icon_draw((float)startx + offsx, (float)*starty + 2 * ufac, ICON_LIBRARY_DATA_DIRECT); + UI_icon_draw_alpha((float)startx + offsx, (float)*starty + 2 * ufac, ICON_LIBRARY_DATA_DIRECT, + alpha_fac); } - glPixelTransferf(GL_ALPHA_SCALE, 1.0f); offsx += UI_UNIT_X; } glDisable(GL_BLEND); /* name */ if ((tselem->flag & TSE_TEXTBUT) == 0) { + unsigned char text_col[4]; + if (active == OL_DRAWSEL_NORMAL) { - UI_ThemeColor(TH_TEXT_HI); + UI_GetThemeColor4ubv(TH_TEXT_HI, text_col); } else if (ELEM(tselem->type, TSE_RNA_PROPERTY, TSE_RNA_ARRAY_ELEM)) { - UI_ThemeColorBlend(TH_BACK, TH_TEXT, 0.75f); + UI_GetThemeColorBlend3ubv(TH_BACK, TH_TEXT, 0.75f, text_col); + text_col[3] = 255; } else { - UI_ThemeColor(TH_TEXT); + UI_GetThemeColor4ubv(TH_TEXT, text_col); } + text_col[3] *= alpha_fac; - UI_fontstyle_draw_simple(fstyle, startx + offsx, *starty + 5 * ufac, te->name); + UI_fontstyle_draw_simple(fstyle, startx + offsx, *starty + 5 * ufac, te->name, text_col); } offsx += (int)(UI_UNIT_X + UI_fontstyle_string_width(fstyle, te->name)); @@ -1611,24 +1456,33 @@ static void outliner_draw_tree_element( if (tselem->type == 0 && te->idcode == ID_SCE) { /* pass */ } + /* this tree element always has same amount of branches, so don't draw */ else if (tselem->type != TSE_R_LAYER) { - /* this tree element always has same amount of branches, so don't draw */ - int tempx = startx + offsx; - - /* divider */ - UI_ThemeColorShade(TH_BACK, -40); - glRecti(tempx - 10.0f * ufac, - *starty + 4.0f * ufac, - tempx - 8.0f * ufac, - *starty + UI_UNIT_Y - 4.0f * ufac); - + glEnable(GL_BLEND); - glPixelTransferf(GL_ALPHA_SCALE, 0.5); - - outliner_draw_iconrow(C, block, scene, soops, &te->subtree, 0, xmax, &tempx, *starty); - - glPixelTransferf(GL_ALPHA_SCALE, 1.0); + + /* divider */ + { + VertexFormat *format = immVertexFormat(); + unsigned int pos = add_attrib(format, "pos", GL_INT, 2, CONVERT_INT_TO_FLOAT); + unsigned char col[4]; + + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + UI_GetThemeColorShade4ubv(TH_BACK, -40, col); + col[3] *= alpha_fac; + + immUniformColor4ubv(col); + immRecti(pos, tempx - 10.0f * ufac, + *starty + 4.0f * ufac, + tempx - 8.0f * ufac, + *starty + UI_UNIT_Y - 4.0f * ufac); + immUnbindProgram(); + } + + outliner_draw_iconrow(C, block, scene, sl, soops, &te->subtree, 0, xmax, &tempx, + *starty, alpha_fac); + glDisable(GL_BLEND); } } @@ -1638,16 +1492,20 @@ static void outliner_draw_tree_element( te->xs = startx; te->ys = *starty; te->xend = startx + offsx; - + if (TSELEM_OPEN(tselem, soops)) { *starty -= UI_UNIT_Y; - for (ten = te->subtree.first; ten; ten = ten->next) { - outliner_draw_tree_element(C, block, fstyle, scene, ar, soops, ten, startx + UI_UNIT_X, starty, te_edit); + for (TreeElement *ten = te->subtree.first; ten; ten = ten->next) { + /* check if element needs to be drawn grayed out, but also gray out + * childs of a grayed out parent (pass on draw_grayed_out to childs) */ + bool draw_childs_grayed_out = draw_grayed_out || (ten->drag_data != NULL); + outliner_draw_tree_element(C, block, fstyle, scene, sl, ar, soops, ten, draw_childs_grayed_out, + startx + UI_UNIT_X, starty, te_edit, te_floating); } } else { - for (ten = te->subtree.first; ten; ten = ten->next) { + for (TreeElement *ten = te->subtree.first; ten; ten = ten->next) { outliner_set_coord_tree_element(ten, startx, *starty); } @@ -1655,115 +1513,269 @@ static void outliner_draw_tree_element( } } -static void outliner_draw_hierarchy(SpaceOops *soops, ListBase *lb, int startx, int *starty) +/** + * Count how many visible childs (and open grandchilds, great-grandchilds, ...) \a te has. + */ +static int outliner_count_visible_childs(const SpaceOops *soops, const TreeElement *te) +{ + TreeStoreElem *tselem = TREESTORE(te); + int current_count = 0; + + if (TSELEM_OPEN(tselem, soops)) { + for (TreeElement *te_child = te->subtree.first; te_child; te_child = te_child->next) { + current_count += outliner_count_visible_childs(soops, te_child); + current_count++; + } + } + + return current_count; +} + +static void outliner_draw_tree_element_floating(const SpaceOops *soops, const ARegion *ar, + const TreeElement *te_floating) +{ + const TreeElement *te_insert = te_floating->drag_data->insert_te; + const ListBase *lb_parent = te_floating->parent ? &te_floating->parent->subtree : &soops->tree; + const TreeElement *te_insert_fallback = te_insert ? te_insert : lb_parent->first; + const int line_width = 2; + + unsigned int pos = add_attrib(immVertexFormat(), "pos", GL_FLOAT, 2, KEEP_FLOAT); + int coord_y = (te_insert ? te_insert->ys : (te_insert_fallback->ys + UI_UNIT_Y)) - (int)(line_width * 0.5f); + unsigned char col[4]; + + if (te_insert == te_floating) { + /* don't draw anything */ + return; + } + + if (te_insert) { + coord_y -= UI_UNIT_Y * outliner_count_visible_childs(soops, te_insert); + } + + UI_GetThemeColorShade4ubv(TH_BACK, -40, col); + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + immUniformColor4ubv(col); + glLineWidth(line_width); + + immBegin(PRIM_LINE_STRIP, 2); + immVertex2f(pos, 0, coord_y); + immVertex2f(pos, ar->v2d.cur.xmax, coord_y); + immEnd(); + + immUnbindProgram(); +} + +static void outliner_draw_hierarchy_lines_recursive(unsigned pos, SpaceOops *soops, ListBase *lb, int startx, + const unsigned char col[4], bool draw_grayed_out, + int *starty) { TreeElement *te; TreeStoreElem *tselem; int y1, y2; - - if (BLI_listbase_is_empty(lb)) return; - + + if (BLI_listbase_is_empty(lb)) { + return; + } + y1 = y2 = *starty; /* for vertical lines between objects */ for (te = lb->first; te; te = te->next) { + bool draw_childs_grayed_out = draw_grayed_out || (te->drag_data != NULL); y2 = *starty; tselem = TREESTORE(te); - + + immUniformColor4ub(UNPACK3(col), col[3] * (draw_childs_grayed_out ? 0.5f : 1.0f)); + /* horizontal line? */ if (tselem->type == 0 && (te->idcode == ID_OB || te->idcode == ID_SCE)) - glRecti(startx, *starty, startx + UI_UNIT_X, *starty - 1); + immRecti(pos, startx, *starty, startx + UI_UNIT_X, *starty - 1); *starty -= UI_UNIT_Y; if (TSELEM_OPEN(tselem, soops)) - outliner_draw_hierarchy(soops, &te->subtree, startx + UI_UNIT_X, starty); + outliner_draw_hierarchy_lines_recursive(pos, soops, &te->subtree, startx + UI_UNIT_X, + col, draw_childs_grayed_out, starty); } - + + immUniformColor4ub(UNPACK3(col), col[3] * (draw_grayed_out ? 0.5f : 1.0f)); + /* vertical line */ te = lb->last; if (te->parent || lb->first != lb->last) { tselem = TREESTORE(te); - if (tselem->type == 0 && te->idcode == ID_OB) { - - glRecti(startx, y1 + UI_UNIT_Y, startx + 1, y2); - } + if (tselem->type == 0 && te->idcode == ID_OB) + immRecti(pos, startx, y1 + UI_UNIT_Y, startx + 1, y2); } } +static void outliner_draw_hierarchy_lines(SpaceOops *soops, ListBase *lb, int startx, int *starty) +{ + VertexFormat *format = immVertexFormat(); + unsigned int pos = add_attrib(format, "pos", GL_INT, 2, CONVERT_INT_TO_FLOAT); + unsigned char col[4]; + + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + UI_GetThemeColorBlend3ubv(TH_BACK, TH_TEXT, 0.4f, col); + col[3] = 255; + + glEnable(GL_BLEND); + outliner_draw_hierarchy_lines_recursive(pos, soops, lb, startx, col, false, starty); + glDisable(GL_BLEND); + + immUnbindProgram(); +} + static void outliner_draw_struct_marks(ARegion *ar, SpaceOops *soops, ListBase *lb, int *starty) { TreeElement *te; TreeStoreElem *tselem; - + for (te = lb->first; te; te = te->next) { tselem = TREESTORE(te); /* selection status */ if (TSELEM_OPEN(tselem, soops)) - if (tselem->type == TSE_RNA_STRUCT) - glRecti(0, *starty + 1, (int)ar->v2d.cur.xmax, *starty + UI_UNIT_Y - 1); + if (tselem->type == TSE_RNA_STRUCT) { + VertexFormat *format = immVertexFormat(); + unsigned pos = add_attrib(format, "pos", GL_INT, 2, CONVERT_INT_TO_FLOAT); + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + immThemeColorShadeAlpha(TH_BACK, -15, -200); + immRecti(pos, 0, *starty + 1, (int)ar->v2d.cur.xmax, *starty + UI_UNIT_Y - 1); + immUnbindProgram(); + } *starty -= UI_UNIT_Y; if (TSELEM_OPEN(tselem, soops)) { outliner_draw_struct_marks(ar, soops, &te->subtree, starty); - if (tselem->type == TSE_RNA_STRUCT) - fdrawline(0, (float)*starty + UI_UNIT_Y, ar->v2d.cur.xmax, (float)*starty + UI_UNIT_Y); + if (tselem->type == TSE_RNA_STRUCT) { + VertexFormat *format = immVertexFormat(); + unsigned pos = add_attrib(format, "pos", GL_FLOAT, 2, KEEP_FLOAT); + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + immThemeColorShadeAlpha(TH_BACK, -15, -200); + + immBegin(GL_LINES, 2); + immVertex2f(pos, 0, (float)*starty + UI_UNIT_Y); + immVertex2f(pos, ar->v2d.cur.xmax, (float)*starty + UI_UNIT_Y); + immEnd(); + + immUnbindProgram(); + } } } } -static void outliner_draw_selection(ARegion *ar, SpaceOops *soops, ListBase *lb, int *starty) +static void outliner_draw_highlights_recursive( + unsigned pos, const ARegion *ar, const SpaceOops *soops, const ListBase *lb, + const float col_selection[4], const float col_highlight[4], const float col_searchmatch[4], + int start_x, int *io_start_y) { - TreeElement *te; - TreeStoreElem *tselem; - - for (te = lb->first; te; te = te->next) { - tselem = TREESTORE(te); - + const bool is_searching = SEARCHING_OUTLINER(soops) || + (soops->outlinevis == SO_DATABLOCKS && soops->search_string[0] != 0); + + for (TreeElement *te = lb->first; te; te = te->next) { + const TreeStoreElem *tselem = TREESTORE(te); + const int start_y = *io_start_y; + /* selection status */ if (tselem->flag & TSE_SELECTED) { - glRecti(0, *starty + 1, (int)ar->v2d.cur.xmax, *starty + UI_UNIT_Y - 1); + immUniformColor4fv(col_selection); + immRecti(pos, 0, start_y + 1, (int)ar->v2d.cur.xmax, start_y + UI_UNIT_Y - 1); + } + + /* search match highlights + * we don't expand items when searching in the datablocks but we + * still want to highlight any filter matches. */ + if (is_searching && (tselem->flag & TSE_SEARCHMATCH)) { + immUniformColor4fv(col_searchmatch); + immRecti(pos, start_x, start_y + 1, ar->v2d.cur.xmax, start_y + UI_UNIT_Y - 1); + } + + /* mouse hover highlights */ + if ((tselem->flag & TSE_HIGHLIGHTED) || (te->drag_data != NULL)) { + immUniformColor4fv(col_highlight); + immRecti(pos, 0, start_y + 1, (int)ar->v2d.cur.xmax, start_y + UI_UNIT_Y - 1); + } + + *io_start_y -= UI_UNIT_Y; + if (TSELEM_OPEN(tselem, soops)) { + outliner_draw_highlights_recursive( + pos, ar, soops, &te->subtree, col_selection, col_highlight, col_searchmatch, + start_x + UI_UNIT_X, io_start_y); } - *starty -= UI_UNIT_Y; - if (TSELEM_OPEN(tselem, soops)) outliner_draw_selection(ar, soops, &te->subtree, starty); } } +static void outliner_draw_highlights(ARegion *ar, SpaceOops *soops, int startx, int *starty) +{ + const float col_highlight[4] = {1.0f, 1.0f, 1.0f, 0.13f}; + float col_selection[4], col_searchmatch[4]; + + UI_GetThemeColor3fv(TH_SELECT_HIGHLIGHT, col_selection); + col_selection[3] = 1.0f; /* no alpha */ + UI_GetThemeColor4fv(TH_MATCH, col_searchmatch); + col_searchmatch[3] = 0.5f; + + glEnable(GL_BLEND); + VertexFormat *format = immVertexFormat(); + unsigned pos = add_attrib(format, "pos", GL_INT, 2, CONVERT_INT_TO_FLOAT); + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + outliner_draw_highlights_recursive(pos, ar, soops, &soops->tree, col_selection, col_highlight, col_searchmatch, + startx, starty); + immUnbindProgram(); + glDisable(GL_BLEND); +} -static void outliner_draw_tree(bContext *C, uiBlock *block, Scene *scene, ARegion *ar, - SpaceOops *soops, TreeElement **te_edit) +static void outliner_draw_tree( + bContext *C, uiBlock *block, Scene *scene, SceneLayer *sl, ARegion *ar, + SpaceOops *soops, const bool has_restrict_icons, + TreeElement **te_edit) { const uiFontStyle *fstyle = UI_FSTYLE_WIDGET; - TreeElement *te; + TreeElement *te_floating = NULL; int starty, startx; - float col[3]; - + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); // only once - + if (ELEM(soops->outlinevis, SO_DATABLOCKS, SO_USERDEF)) { /* struct marks */ - UI_ThemeColorShadeAlpha(TH_BACK, -15, -200); - //UI_ThemeColorShade(TH_BACK, -20); starty = (int)ar->v2d.tot.ymax - UI_UNIT_Y - OL_Y_OFFSET; outliner_draw_struct_marks(ar, soops, &soops->tree, &starty); } - - /* always draw selection fill before hierarchy */ - UI_GetThemeColor3fv(TH_SELECT_HIGHLIGHT, col); - glColor3fv(col); + + /* draw highlights before hierarchy */ starty = (int)ar->v2d.tot.ymax - UI_UNIT_Y - OL_Y_OFFSET; - outliner_draw_selection(ar, soops, &soops->tree, &starty); - + startx = 0; + outliner_draw_highlights(ar, soops, startx, &starty); + + /* set scissor so tree elements or lines can't overlap restriction icons */ + GLfloat scissor[4] = {0}; + if (has_restrict_icons) { + int mask_x = BLI_rcti_size_x(&ar->v2d.mask) - (int)OL_TOGW + 1; + CLAMP_MIN(mask_x, 0); + + glGetFloatv(GL_SCISSOR_BOX, scissor); + glScissor(ar->winrct.xmin, ar->winrct.ymin, mask_x, ar->winy); + } + // gray hierarchy lines - UI_ThemeColorBlend(TH_BACK, TH_TEXT, 0.4f); + starty = (int)ar->v2d.tot.ymax - UI_UNIT_Y / 2 - OL_Y_OFFSET; startx = 6; - outliner_draw_hierarchy(soops, &soops->tree, startx, &starty); - + outliner_draw_hierarchy_lines(soops, &soops->tree, startx, &starty); + // items themselves starty = (int)ar->v2d.tot.ymax - UI_UNIT_Y - OL_Y_OFFSET; startx = 0; - for (te = soops->tree.first; te; te = te->next) { - outliner_draw_tree_element(C, block, fstyle, scene, ar, soops, te, startx, &starty, te_edit); + for (TreeElement *te = soops->tree.first; te; te = te->next) { + outliner_draw_tree_element(C, block, fstyle, scene, sl, ar, soops, te, te->drag_data != NULL, + startx, &starty, te_edit, &te_floating); + } + if (te_floating) { + outliner_draw_tree_element_floating(soops, ar, te_floating); + } + + if (has_restrict_icons) { + /* reset scissor */ + glScissor(UNPACK4(scissor)); } } @@ -1772,34 +1784,37 @@ static void outliner_back(ARegion *ar) { int ystart; - UI_ThemeColorShade(TH_BACK, 6); ystart = (int)ar->v2d.tot.ymax; ystart = UI_UNIT_Y * (ystart / (UI_UNIT_Y)) - OL_Y_OFFSET; - - while (ystart + 2 * UI_UNIT_Y > ar->v2d.cur.ymin) { - glRecti(0, ystart, (int)ar->v2d.cur.xmax, ystart + UI_UNIT_Y); - ystart -= 2 * UI_UNIT_Y; + + VertexFormat *format = immVertexFormat(); + unsigned pos = add_attrib(format, "pos", GL_FLOAT, 2, KEEP_FLOAT); + + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + immUniformThemeColorShade(TH_BACK, 6); + + const float x1 = 0.0f, x2 = ar->v2d.cur.xmax; + float y1 = ystart, y2; + int tot = (int)floor(ystart - ar->v2d.cur.ymin + 2 * UI_UNIT_Y) / (2 * UI_UNIT_Y); + + if (tot > 0) { + immBegin(GL_QUADS, 4 * tot); + while (tot--) { + y1 -= 2 * UI_UNIT_Y; + y2 = y1 + UI_UNIT_Y; + immVertex2f(pos, x1, y1); + immVertex2f(pos, x2, y1); + immVertex2f(pos, x2, y2); + immVertex2f(pos, x1, y2); + } + immEnd(); } + immUnbindProgram(); } static void outliner_draw_restrictcols(ARegion *ar) { - int ystart; - - /* background underneath */ - UI_ThemeColor(TH_BACK); - glRecti((int)(ar->v2d.cur.xmax - OL_TOGW), - (int)(ar->v2d.cur.ymin - 1), (int)ar->v2d.cur.xmax, (int)ar->v2d.cur.ymax); - - UI_ThemeColorShade(TH_BACK, 6); - ystart = (int)ar->v2d.tot.ymax; - ystart = UI_UNIT_Y * (ystart / (UI_UNIT_Y)) - OL_Y_OFFSET; - - while (ystart + 2 * UI_UNIT_Y > ar->v2d.cur.ymin) { - glRecti((int)ar->v2d.cur.xmax - OL_TOGW, ystart, (int)ar->v2d.cur.xmax, ystart + UI_UNIT_Y); - ystart -= 2 * UI_UNIT_Y; - } - + glLineWidth(1.0f); UI_ThemeColorShadeAlpha(TH_BACK, -15, -200); /* view */ @@ -1828,14 +1843,16 @@ void draw_outliner(const bContext *C) { Main *mainvar = CTX_data_main(C); Scene *scene = CTX_data_scene(C); + SceneLayer *sl = CTX_data_scene_layer(C); ARegion *ar = CTX_wm_region(C); View2D *v2d = &ar->v2d; SpaceOops *soops = CTX_wm_space_outliner(C); uiBlock *block; int sizey = 0, sizex = 0, sizex_rna = 0; TreeElement *te_edit = NULL; + bool has_restrict_icons; - outliner_build_tree(mainvar, scene, soops); // always + outliner_build_tree(mainvar, scene, sl, soops); // always /* get extents of data */ outliner_height(soops, &soops->tree, &sizey); @@ -1855,6 +1872,7 @@ void draw_outliner(const bContext *C) /* get width of data (for setting 'tot' rect, this is column 1 + column 2 + a bit extra) */ sizex = sizex_rna + OL_RNA_COL_SIZEX + 50; + has_restrict_icons = false; } else { /* width must take into account restriction columns (if visible) so that entries will still be visible */ @@ -1866,7 +1884,8 @@ void draw_outliner(const bContext *C) // XXX this isn't that great yet... if ((soops->flag & SO_HIDE_RESTRICTCOLS) == 0) sizex += OL_TOGW * 3; - + + has_restrict_icons = !(soops->flag & SO_HIDE_RESTRICTCOLS); } /* adds vertical offset */ @@ -1883,19 +1902,19 @@ void draw_outliner(const bContext *C) /* draw outliner stuff (background, hierarchy lines and names) */ outliner_back(ar); block = UI_block_begin(C, ar, __func__, UI_EMBOSS); - outliner_draw_tree((bContext *)C, block, scene, ar, soops, &te_edit); + outliner_draw_tree((bContext *)C, block, scene, sl, ar, soops, has_restrict_icons, &te_edit); if (ELEM(soops->outlinevis, SO_DATABLOCKS, SO_USERDEF)) { /* draw rna buttons */ outliner_draw_rnacols(ar, sizex_rna); outliner_draw_rnabuts(block, ar, soops, sizex_rna, &soops->tree); } - else if ((soops->outlinevis == SO_ID_ORPHANS) && !(soops->flag & SO_HIDE_RESTRICTCOLS)) { + else if ((soops->outlinevis == SO_ID_ORPHANS) && has_restrict_icons) { /* draw user toggle columns */ outliner_draw_restrictcols(ar); outliner_draw_userbuts(block, ar, soops, &soops->tree); } - else if (!(soops->flag & SO_HIDE_RESTRICTCOLS)) { + else if (has_restrict_icons) { /* draw restriction columns */ outliner_draw_restrictcols(ar); outliner_draw_restrictbuts(block, scene, ar, soops, &soops->tree); diff --git a/source/blender/editors/space_outliner/outliner_edit.c b/source/blender/editors/space_outliner/outliner_edit.c index 345ac353c11..5f3931a4a77 100644 --- a/source/blender/editors/space_outliner/outliner_edit.c +++ b/source/blender/editors/space_outliner/outliner_edit.c @@ -54,6 +54,7 @@ #include "BKE_depsgraph.h" #include "BKE_global.h" #include "BKE_idcode.h" +#include "BKE_layer.h" #include "BKE_library.h" #include "BKE_library_query.h" #include "BKE_library_remap.h" @@ -148,8 +149,95 @@ TreeElement *outliner_dropzone_find(const SpaceOops *soops, const float fmval[2] return NULL; } +/** + * Try to find an item under y-coordinate \a view_co_y (view-space). + * \note Recursive + */ +TreeElement *outliner_find_item_at_y(const SpaceOops *soops, const ListBase *tree, float view_co_y) +{ + for (TreeElement *te_iter = tree->first; te_iter; te_iter = te_iter->next) { + if (view_co_y < (te_iter->ys + UI_UNIT_Y)) { + if (view_co_y > te_iter->ys) { + /* co_y is inside this element */ + return te_iter; + } + else if (TSELEM_OPEN(te_iter->store_elem, soops)) { + /* co_y is lower than current element, possibly inside children */ + TreeElement *te_sub = outliner_find_item_at_y(soops, &te_iter->subtree, view_co_y); + if (te_sub) { + return te_sub; + } + } + } + } + + return NULL; +} + +/** + * Collapsed items can show their children as click-able icons. This function tries to find + * such an icon that represents the child item at x-coordinate \a view_co_x (view-space). + * + * \return a hovered child item or \a parent_te (if no hovered child found). + */ +TreeElement *outliner_find_item_at_x_in_row(const SpaceOops *soops, const TreeElement *parent_te, float view_co_x) +{ + if (!TSELEM_OPEN(TREESTORE(parent_te), soops)) { /* if parent_te is opened, it doesn't show childs in row */ + /* no recursion, items can only display their direct children in the row */ + for (TreeElement *child_te = parent_te->subtree.first; + child_te && view_co_x >= child_te->xs; /* don't look further if co_x is smaller than child position*/ + child_te = child_te->next) + { + if ((child_te->flag & TE_ICONROW) && (view_co_x > child_te->xs) && (view_co_x < child_te->xend)) { + return child_te; + } + } + } + + /* return parent if no child is hovered */ + return (TreeElement *)parent_te; +} + + /* ************************************************************** */ -/* Click Activated */ + +/* Highlight --------------------------------------------------- */ + +static int outliner_highlight_update(bContext *C, wmOperator *UNUSED(op), const wmEvent *event) +{ + ARegion *ar = CTX_wm_region(C); + SpaceOops *soops = CTX_wm_space_outliner(C); + const float my = UI_view2d_region_to_view_y(&ar->v2d, event->mval[1]); + + TreeElement *hovered_te = outliner_find_item_at_y(soops, &soops->tree, my); + bool changed = false; + + if (!hovered_te || !(hovered_te->store_elem->flag & TSE_HIGHLIGHTED)) { + changed = outliner_set_flag(&soops->tree, TSE_HIGHLIGHTED, false); + if (hovered_te) { + hovered_te->store_elem->flag |= TSE_HIGHLIGHTED; + changed = true; + } + } + + if (changed) { + soops->storeflag |= SO_TREESTORE_REDRAW; /* only needs to redraw, no rebuild */ + ED_region_tag_redraw(ar); + } + + return (OPERATOR_FINISHED | OPERATOR_PASS_THROUGH); +} + +void OUTLINER_OT_highlight_update(wmOperatorType *ot) +{ + ot->name = "Update Highlight"; + ot->idname = "OUTLINER_OT_highlight_update"; + ot->description = "Update the item highlight based on the current mouse position"; + + ot->invoke = outliner_highlight_update; + + ot->poll = ED_operator_outliner_active; +} /* Toggle Open/Closed ------------------------------------------- */ @@ -216,7 +304,8 @@ void OUTLINER_OT_item_openclose(wmOperatorType *ot) /* Rename --------------------------------------------------- */ -static void do_item_rename(ARegion *ar, TreeElement *te, TreeStoreElem *tselem, ReportList *reports) +static void do_item_rename(const Scene *scene, ARegion *ar, TreeElement *te, TreeStoreElem *tselem, + ReportList *reports) { /* can't rename rna datablocks entries or listbases */ if (ELEM(tselem->type, TSE_RNA_STRUCT, TSE_RNA_PROPERTY, TSE_RNA_ARRAY_ELEM, TSE_ID_BASE)) { @@ -230,6 +319,11 @@ static void do_item_rename(ARegion *ar, TreeElement *te, TreeStoreElem *tselem, else if (ELEM(tselem->type, TSE_SEQUENCE, TSE_SEQ_STRIP, TSE_SEQUENCE_DUP)) { BKE_report(reports, RPT_WARNING, "Cannot edit sequence name"); } + else if ((tselem->type == TSE_COLLECTION) && + (((LayerCollection *)te->directdata)->scene_collection == BKE_collection_master(scene))) + { + BKE_report(reports, RPT_WARNING, "Cannot edit name of master collection"); + } else if (ID_IS_LINKED_DATABLOCK(tselem->id)) { BKE_report(reports, RPT_WARNING, "Cannot edit external libdata"); } @@ -243,28 +337,29 @@ static void do_item_rename(ARegion *ar, TreeElement *te, TreeStoreElem *tselem, } void item_rename_cb( - bContext *C, ReportList *reports, Scene *UNUSED(scene), TreeElement *te, + bContext *C, ReportList *reports, Scene *scene, TreeElement *te, TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data)) { ARegion *ar = CTX_wm_region(C); - do_item_rename(ar, te, tselem, reports); + do_item_rename(scene, ar, te, tselem, reports); } -static int do_outliner_item_rename(ReportList *reports, ARegion *ar, TreeElement *te, const float mval[2]) +static int do_outliner_item_rename(const Scene *scene, ReportList *reports, ARegion *ar, TreeElement *te, + const float mval[2]) { if (mval[1] > te->ys && mval[1] < te->ys + UI_UNIT_Y) { TreeStoreElem *tselem = TREESTORE(te); /* click on name */ if (mval[0] > te->xs + UI_UNIT_X * 2 && mval[0] < te->xend) { - do_item_rename(ar, te, tselem, reports); + do_item_rename(scene, ar, te, tselem, reports); return 1; } return 0; } for (te = te->subtree.first; te; te = te->next) { - if (do_outliner_item_rename(reports, ar, te, mval)) return 1; + if (do_outliner_item_rename(scene, reports, ar, te, mval)) return 1; } return 0; } @@ -280,7 +375,7 @@ static int outliner_item_rename(bContext *C, wmOperator *op, const wmEvent *even UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &fmval[0], &fmval[1]); for (te = soops->tree.first; te; te = te->next) { - if (do_outliner_item_rename(op->reports, ar, te, fmval)) { + if (do_outliner_item_rename(CTX_data_scene(C), op->reports, ar, te, fmval)) { changed = true; break; } @@ -740,17 +835,34 @@ int outliner_has_one_flag(ListBase *lb, short flag, const int curlevel) return 0; } -void outliner_set_flag(ListBase *lb, short flag, short set) +/** + * Set or unset \a flag for all outliner elements in \a lb and sub-trees. + * \return if any flag was modified. + */ +bool outliner_set_flag(ListBase *lb, short flag, short set) { TreeElement *te; TreeStoreElem *tselem; - + bool changed = false; + bool has_flag; + for (te = lb->first; te; te = te->next) { tselem = TREESTORE(te); - if (set == 0) tselem->flag &= ~flag; - else tselem->flag |= flag; - outliner_set_flag(&te->subtree, flag, set); + has_flag = (tselem->flag & flag); + if (set == 0) { + if (has_flag) { + tselem->flag &= ~flag; + changed = true; + } + } + else if (!has_flag) { + tselem->flag |= flag; + changed = true; + } + changed |= outliner_set_flag(&te->subtree, flag, set); } + + return changed; } /* Restriction Columns ------------------------------- */ @@ -778,181 +890,6 @@ int common_restrict_check(bContext *C, Object *ob) } /* =============================================== */ -/* Restriction toggles */ - -/* Toggle Visibility ---------------------------------------- */ - -void object_toggle_visibility_cb( - bContext *C, ReportList *reports, Scene *scene, TreeElement *te, - TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data)) -{ - Base *base = (Base *)te->directdata; - Object *ob = (Object *)tselem->id; - - if (ID_IS_LINKED_DATABLOCK(tselem->id)) { - BKE_report(reports, RPT_WARNING, "Cannot edit external libdata"); - return; - } - - /* add check for edit mode */ - if (!common_restrict_check(C, ob)) return; - - if (base || (base = BKE_scene_base_find(scene, ob))) { - if ((base->object->restrictflag ^= OB_RESTRICT_VIEW)) { - ED_base_object_select(base, BA_DESELECT); - } - } -} - -void group_toggle_visibility_cb( - bContext *UNUSED(C), ReportList *UNUSED(reports), Scene *scene, TreeElement *UNUSED(te), - TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data)) -{ - Group *group = (Group *)tselem->id; - restrictbutton_gr_restrict_flag(scene, group, OB_RESTRICT_VIEW); -} - -static int outliner_toggle_visibility_exec(bContext *C, wmOperator *op) -{ - Main *bmain = CTX_data_main(C); - SpaceOops *soops = CTX_wm_space_outliner(C); - Scene *scene = CTX_data_scene(C); - ARegion *ar = CTX_wm_region(C); - - outliner_do_object_operation(C, op->reports, scene, soops, &soops->tree, object_toggle_visibility_cb); - - DAG_id_type_tag(bmain, ID_OB); - WM_event_add_notifier(C, NC_SCENE | ND_OB_VISIBLE, scene); - ED_region_tag_redraw(ar); - - return OPERATOR_FINISHED; -} - -void OUTLINER_OT_visibility_toggle(wmOperatorType *ot) -{ - /* identifiers */ - ot->name = "Toggle Visibility"; - ot->idname = "OUTLINER_OT_visibility_toggle"; - ot->description = "Toggle the visibility of selected items"; - - /* callbacks */ - ot->exec = outliner_toggle_visibility_exec; - ot->poll = ED_operator_outliner_active_no_editobject; - - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; -} - -/* Toggle Selectability ---------------------------------------- */ - -void object_toggle_selectability_cb( - bContext *UNUSED(C), ReportList *reports, Scene *scene, TreeElement *te, - TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data)) -{ - Base *base = (Base *)te->directdata; - - if (ID_IS_LINKED_DATABLOCK(tselem->id)) { - BKE_report(reports, RPT_WARNING, "Cannot edit external libdata"); - return; - } - - if (base == NULL) base = BKE_scene_base_find(scene, (Object *)tselem->id); - if (base) { - base->object->restrictflag ^= OB_RESTRICT_SELECT; - } -} - -void group_toggle_selectability_cb( - bContext *UNUSED(C), ReportList *UNUSED(reports), Scene *scene, TreeElement *UNUSED(te), - TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data)) -{ - Group *group = (Group *)tselem->id; - restrictbutton_gr_restrict_flag(scene, group, OB_RESTRICT_SELECT); -} - -static int outliner_toggle_selectability_exec(bContext *C, wmOperator *op) -{ - SpaceOops *soops = CTX_wm_space_outliner(C); - Scene *scene = CTX_data_scene(C); - ARegion *ar = CTX_wm_region(C); - - outliner_do_object_operation(C, op->reports, scene, soops, &soops->tree, object_toggle_selectability_cb); - - WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene); - ED_region_tag_redraw(ar); - - return OPERATOR_FINISHED; -} - -void OUTLINER_OT_selectability_toggle(wmOperatorType *ot) -{ - /* identifiers */ - ot->name = "Toggle Selectability"; - ot->idname = "OUTLINER_OT_selectability_toggle"; - ot->description = "Toggle the selectability"; - - /* callbacks */ - ot->exec = outliner_toggle_selectability_exec; - ot->poll = ED_operator_outliner_active_no_editobject; - - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; -} - -/* Toggle Renderability ---------------------------------------- */ - -void object_toggle_renderability_cb( - bContext *UNUSED(C), ReportList *reports, Scene *scene, TreeElement *te, - TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data)) -{ - Base *base = (Base *)te->directdata; - - if (ID_IS_LINKED_DATABLOCK(tselem->id)) { - BKE_report(reports, RPT_WARNING, "Cannot edit external libdata"); - return; - } - - if (base == NULL) base = BKE_scene_base_find(scene, (Object *)tselem->id); - if (base) { - base->object->restrictflag ^= OB_RESTRICT_RENDER; - } -} - -void group_toggle_renderability_cb( - bContext *UNUSED(C), ReportList *UNUSED(reports), Scene *scene, TreeElement *UNUSED(te), - TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data)) -{ - Group *group = (Group *)tselem->id; - restrictbutton_gr_restrict_flag(scene, group, OB_RESTRICT_RENDER); -} - -static int outliner_toggle_renderability_exec(bContext *C, wmOperator *op) -{ - Main *bmain = CTX_data_main(C); - SpaceOops *soops = CTX_wm_space_outliner(C); - Scene *scene = CTX_data_scene(C); - - outliner_do_object_operation(C, op->reports, scene, soops, &soops->tree, object_toggle_renderability_cb); - - DAG_id_type_tag(bmain, ID_OB); - WM_event_add_notifier(C, NC_SCENE | ND_OB_RENDER, scene); - - return OPERATOR_FINISHED; -} - -void OUTLINER_OT_renderability_toggle(wmOperatorType *ot) -{ - /* identifiers */ - ot->name = "Toggle Renderability"; - ot->idname = "OUTLINER_OT_renderability_toggle"; - ot->description = "Toggle the renderability of selected items"; - - /* callbacks */ - ot->exec = outliner_toggle_renderability_exec; - ot->poll = ED_operator_outliner_active; - - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; -} - -/* =============================================== */ /* Outliner setting toggles */ /* Toggle Expanded (Outliner) ---------------------------------------- */ @@ -1073,14 +1010,14 @@ static int outliner_open_back(TreeElement *te) static int outliner_show_active_exec(bContext *C, wmOperator *UNUSED(op)) { SpaceOops *so = CTX_wm_space_outliner(C); - Scene *scene = CTX_data_scene(C); + SceneLayer *sl = CTX_data_scene_layer(C); ARegion *ar = CTX_wm_region(C); View2D *v2d = &ar->v2d; TreeElement *te; int xdelta, ytop; - Object *obact = OBACT; + Object *obact = OBACT_NEW; if (!obact) return OPERATOR_CANCELLED; @@ -2241,8 +2178,6 @@ static int scene_drop_invoke(bContext *C, wmOperator *op, const wmEvent *event) te = outliner_dropzone_find(soops, fmval, false); if (te) { - Base *base; - RNA_string_set(op->ptr, "scene", te->name); scene = (Scene *)BKE_libblock_find_name(ID_SCE, te->name); @@ -2253,16 +2188,26 @@ static int scene_drop_invoke(bContext *C, wmOperator *op, const wmEvent *event) return OPERATOR_CANCELLED; } - base = ED_object_scene_link(scene, ob); - - if (base == NULL) { + if (BKE_scene_has_object(scene, ob)) { return OPERATOR_CANCELLED; } - if (scene == CTX_data_scene(C)) { - /* when linking to an inactive scene don't touch the layer */ - ob->lay = base->lay; - ED_base_object_select(base, BA_SELECT); + SceneCollection *sc; + if (scene != CTX_data_scene(C)) { + /* when linking to an inactive scene link to the master collection */ + sc = BKE_collection_master(scene); + } + else { + sc = CTX_data_scene_collection(C); + } + + BKE_collection_object_add(scene, sc, ob); + + for (SceneLayer *sl = scene->render_layers.first; sl; sl = sl->next) { + Base *base = BKE_scene_layer_base_find(sl, ob); + if (base) { + ED_object_base_select(base, BA_SELECT); + } } DAG_relations_tag_update(bmain); @@ -2357,7 +2302,6 @@ static int group_link_invoke(bContext *C, wmOperator *op, const wmEvent *event) Main *bmain = CTX_data_main(C); Group *group = NULL; Object *ob = NULL; - Scene *scene = CTX_data_scene(C); SpaceOops *soops = CTX_wm_space_outliner(C); ARegion *ar = CTX_wm_region(C); TreeElement *te = NULL; @@ -2387,7 +2331,7 @@ static int group_link_invoke(bContext *C, wmOperator *op, const wmEvent *event) return OPERATOR_CANCELLED; } - BKE_group_object_add(group, ob, scene, NULL); + BKE_group_object_add(group, ob); WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob); return OPERATOR_FINISHED; diff --git a/source/blender/editors/space_outliner/outliner_intern.h b/source/blender/editors/space_outliner/outliner_intern.h index ccc52f2dba8..6a4d53449e9 100644 --- a/source/blender/editors/space_outliner/outliner_intern.h +++ b/source/blender/editors/space_outliner/outliner_intern.h @@ -37,14 +37,23 @@ /* internal exports only */ struct wmOperatorType; +struct TreeElement; struct TreeStoreElem; struct bContext; struct Scene; +struct SceneLayer; struct ID; struct Object; struct bPoseChannel; struct EditBone; +/** + * Callback type for reinserting elements at a different position, used to allow user customizable element order. + * Passing scene right now, may be better to allow some custom data. + */ +typedef void (*TreeElementReinsertFunc)(const struct Scene *scene, struct TreeElement *insert_element, + struct TreeElement *insert_after); + typedef struct TreeElement { struct TreeElement *next, *prev, *parent; ListBase subtree; @@ -57,7 +66,15 @@ typedef struct TreeElement { const char *name; void *directdata; // Armature Bones, Base, Sequence, Strip... PointerRNA rnaptr; // RNA Pointer -} TreeElement; + + /* callbacks */ + TreeElementReinsertFunc reinsert; + + struct { + /* the element after which we may insert the dragged one (NULL to insert at top) */ + struct TreeElement *insert_te; + } *drag_data; +} TreeElement; #define TREESTORE_ID_TYPE(_id) \ (ELEM(GS((_id)->name), ID_SCE, ID_LI, ID_OB, ID_ME, ID_CU, ID_MB, ID_NT, ID_MA, ID_TE, ID_IM, ID_LT, ID_LA, ID_CA) || \ @@ -65,10 +82,14 @@ typedef struct TreeElement { ELEM(GS((_id)->name), ID_SCR, ID_WM, ID_TXT, ID_VF, ID_SO, ID_CF, ID_PAL)) /* Only in 'blendfile' mode ... :/ */ /* TreeElement->flag */ -#define TE_ACTIVE 1 -#define TE_ICONROW 2 -#define TE_LAZY_CLOSED 4 -#define TE_FREE_NAME 8 +enum { + TE_ACTIVE = (1 << 0), + /* Closed items display their children as icon within the row. TE_ICONROW is for + * these child-items that are visible but only within the row of the closed parent. */ + TE_ICONROW = (1 << 1), + TE_LAZY_CLOSED = (1 << 2), + TE_FREE_NAME = (1 << 3), +}; /* button events */ #define OL_NAMEBUTTON 1 @@ -137,7 +158,7 @@ TreeElement *outliner_find_posechannel(ListBase *lb, const struct bPoseChannel * TreeElement *outliner_find_editbone(ListBase *lb, const struct EditBone *ebone); struct ID *outliner_search_back(SpaceOops *soops, TreeElement *te, short idcode); -void outliner_build_tree(struct Main *mainvar, struct Scene *scene, struct SpaceOops *soops); +void outliner_build_tree(struct Main *mainvar, struct Scene *scene, struct SceneLayer *sl, struct SpaceOops *soops); /* outliner_draw.c ---------------------------------------------- */ @@ -146,11 +167,11 @@ void restrictbutton_gr_restrict_flag(void *poin, void *poin2, int flag); /* outliner_select.c -------------------------------------------- */ eOLDrawState tree_element_type_active( - struct bContext *C, struct Scene *scene, struct SpaceOops *soops, + struct bContext *C, struct Scene *scene, struct SceneLayer *sl, struct SpaceOops *soops, TreeElement *te, TreeStoreElem *tselem, const eOLSetState set, bool recursive); -eOLDrawState tree_element_active(struct bContext *C, struct Scene *scene, SpaceOops *soops, +eOLDrawState tree_element_active(struct bContext *C, struct Scene *scene, struct SceneLayer *sl, SpaceOops *soops, TreeElement *te, const eOLSetState set, const bool handle_all_types); -int outliner_item_do_activate(struct bContext *C, int x, int y, bool extend, bool recursive); +int outliner_item_activate_or_toggle_closed(struct bContext *C, int x, int y, bool extend, bool recursive); /* outliner_edit.c ---------------------------------------------- */ typedef void (*outliner_operation_cb)( @@ -167,7 +188,7 @@ void outliner_do_object_operation( int common_restrict_check(struct bContext *C, struct Object *ob); int outliner_has_one_flag(ListBase *lb, short flag, const int curlevel); -void outliner_set_flag(ListBase *lb, short flag, short set); +bool outliner_set_flag(ListBase *lb, short flag, short set); void object_toggle_visibility_cb( struct bContext *C, struct ReportList *reports, struct Scene *scene, @@ -208,8 +229,14 @@ void id_remap_cb( struct TreeStoreElem *tsep, struct TreeStoreElem *tselem, void *user_data); TreeElement *outliner_dropzone_find(const struct SpaceOops *soops, const float fmval[2], const bool children); + +TreeElement *outliner_find_item_at_y(const SpaceOops *soops, const ListBase *tree, float view_co_y); +TreeElement *outliner_find_item_at_x_in_row(const SpaceOops *soops, const TreeElement *parent_te, float view_co_x); + /* ...................................................... */ +void OUTLINER_OT_highlight_update(struct wmOperatorType *ot); + void OUTLINER_OT_item_activate(struct wmOperatorType *ot); void OUTLINER_OT_item_openclose(struct wmOperatorType *ot); void OUTLINER_OT_item_rename(struct wmOperatorType *ot); @@ -229,10 +256,6 @@ void OUTLINER_OT_expanded_toggle(struct wmOperatorType *ot); void OUTLINER_OT_scroll_page(struct wmOperatorType *ot); -void OUTLINER_OT_renderability_toggle(struct wmOperatorType *ot); -void OUTLINER_OT_selectability_toggle(struct wmOperatorType *ot); -void OUTLINER_OT_visibility_toggle(struct wmOperatorType *ot); - void OUTLINER_OT_keyingset_add_selected(struct wmOperatorType *ot); void OUTLINER_OT_keyingset_remove_selected(struct wmOperatorType *ot); @@ -261,10 +284,25 @@ void OUTLINER_OT_animdata_operation(struct wmOperatorType *ot); void OUTLINER_OT_action_set(struct wmOperatorType *ot); void OUTLINER_OT_constraint_operation(struct wmOperatorType *ot); void OUTLINER_OT_modifier_operation(struct wmOperatorType *ot); +void OUTLINER_OT_collection_operation(struct wmOperatorType *ot); /* ---------------------------------------------------------------- */ /* outliner_ops.c */ void outliner_operatortypes(void); void outliner_keymap(struct wmKeyConfig *keyconf); +/* outliner_collections.c */ + +void OUTLINER_OT_collection_delete(struct wmOperatorType *ot); +void OUTLINER_OT_collection_select(struct wmOperatorType *ot); +void OUTLINER_OT_collection_link(struct wmOperatorType *ot); +void OUTLINER_OT_collection_unlink(struct wmOperatorType *ot); +void OUTLINER_OT_collection_new(struct wmOperatorType *ot); +void OUTLINER_OT_collection_override_new(struct wmOperatorType *ot); +void OUTLINER_OT_collection_objects_add(struct wmOperatorType *ot); +void OUTLINER_OT_collection_objects_remove(struct wmOperatorType *ot); +void OUTLINER_OT_collection_objects_select(struct wmOperatorType *ot); +void OUTLINER_OT_collection_objects_deselect(struct wmOperatorType *ot); + + #endif /* __OUTLINER_INTERN_H__ */ diff --git a/source/blender/editors/space_outliner/outliner_ops.c b/source/blender/editors/space_outliner/outliner_ops.c index 776717c8443..d94ccde57e5 100644 --- a/source/blender/editors/space_outliner/outliner_ops.c +++ b/source/blender/editors/space_outliner/outliner_ops.c @@ -28,25 +28,208 @@ * \ingroup spoutliner */ -#include "DNA_space_types.h" +#include "BKE_context.h" +#include "BLI_math.h" + +#include "ED_screen.h" + +#include "MEM_guardedalloc.h" #include "RNA_access.h" +#include "UI_interface.h" +#include "UI_view2d.h" + #include "WM_api.h" #include "WM_types.h" #include "outliner_intern.h" +enum { + OUTLINER_ITEM_DRAG_CANCEL, + OUTLINER_ITEM_DRAG_CONFIRM, +}; + +typedef struct OutlinerItemDrag { + TreeElement *dragged_te; + int init_mouse_xy[2]; +} OutlinerItemDrag; + +static int outliner_item_drag_drop_poll(bContext *C) +{ + SpaceOops *soops = CTX_wm_space_outliner(C); + return ED_operator_outliner_active(C) && + (soops->flag & SO_SKIP_SORT_ALPHA) && + /* Only collection display mode supported for now. Others need more design work */ + ELEM(soops->outlinevis, SO_COLLECTIONS); +} + +static TreeElement *outliner_item_drag_element_find(SpaceOops *soops, ARegion *ar, const wmEvent *event) +{ + const float my = UI_view2d_region_to_view_y(&ar->v2d, event->mval[1]); + return outliner_find_item_at_y(soops, &soops->tree, my); +} + +static OutlinerItemDrag *outliner_item_drag_data_create(TreeElement *dragged_te, const int mouse_xy[2]) +{ + OutlinerItemDrag *drag_data = MEM_mallocN(sizeof(*drag_data), __func__); + + drag_data->dragged_te = dragged_te; + copy_v2_v2_int(drag_data->init_mouse_xy, mouse_xy); + + return drag_data; +} + +static void outliner_item_drag_end(OutlinerItemDrag *op_drag_data) +{ + MEM_SAFE_FREE(op_drag_data->dragged_te->drag_data); + MEM_freeN(op_drag_data); +} + +static void outliner_item_drag_handle(OutlinerItemDrag *op_drag_data, ARegion *ar, const wmEvent *event) +{ + TreeElement *dragged_te = op_drag_data->dragged_te; + const int delta_mouse_y = event->y - op_drag_data->init_mouse_xy[1]; + const int cmp_coord = (int)UI_view2d_region_to_view_y(&ar->v2d, event->mval[1]); + + /* by default we don't change the item position */ + dragged_te->drag_data->insert_te = dragged_te; + + if (delta_mouse_y > 0) { + for (TreeElement *te = dragged_te->prev; te && (cmp_coord >= (te->ys + (UI_UNIT_Y * 0.5f))); te = te->prev) { + /* will be NULL if we want to insert as first element */ + dragged_te->drag_data->insert_te = te->prev; + } + } + else { + for (TreeElement *te = dragged_te->next; te && (cmp_coord <= (te->ys + (UI_UNIT_Y * 0.5f))); te = te->next) { + dragged_te->drag_data->insert_te = te; + } + } +} + +static bool outliner_item_drag_drop_apply(const Scene *scene, OutlinerItemDrag *op_drag_data) +{ + TreeElement *dragged_te = op_drag_data->dragged_te; + TreeElement *insert_after = dragged_te->drag_data->insert_te; + + if (insert_after == dragged_te) { + /* No need to do anything */ + return false; + } + + if (dragged_te->reinsert) { + /* Not sure yet what the best way to handle reordering elements of different types + * (and stored in different lists). For collection display mode this is enough. */ + if (!insert_after || (insert_after->reinsert == dragged_te->reinsert)) { + dragged_te->reinsert(scene, dragged_te, insert_after); + } + } + + return true; +} + +static int outliner_item_drag_drop_modal(bContext *C, wmOperator *op, const wmEvent *event) +{ + ARegion *ar = CTX_wm_region(C); + SpaceOops *soops = CTX_wm_space_outliner(C); + OutlinerItemDrag *op_drag_data = op->customdata; + int retval = OPERATOR_RUNNING_MODAL; + bool redraw = false; + bool skip_rebuild = true; + + switch (event->type) { + case EVT_MODAL_MAP: + if (event->val == OUTLINER_ITEM_DRAG_CONFIRM) { + outliner_item_drag_drop_apply(CTX_data_scene(C), op_drag_data); + skip_rebuild = false; + retval = OPERATOR_FINISHED; + } + else if (event->val == OUTLINER_ITEM_DRAG_CANCEL) { + retval = OPERATOR_CANCELLED; + } + else { + BLI_assert(0); + } + WM_event_add_mousemove(C); /* update highlight */ + outliner_item_drag_end(op_drag_data); + redraw = true; + break; + case MOUSEMOVE: + outliner_item_drag_handle(op_drag_data, ar, event); + redraw = true; + break; + } + + if (skip_rebuild) { + soops->storeflag |= SO_TREESTORE_REDRAW; /* only needs to redraw, no rebuild */ + } + if (redraw) { + ED_region_tag_redraw(ar); + } + + return retval; +} + +static int outliner_item_drag_drop_invoke(bContext *C, wmOperator *op, const wmEvent *event) +{ + ARegion *ar = CTX_wm_region(C); + SpaceOops *soops = CTX_wm_space_outliner(C); + TreeElement *te = outliner_item_drag_element_find(soops, ar, event); + + if (!te) { + return (OPERATOR_FINISHED | OPERATOR_PASS_THROUGH); + } + + + op->customdata = outliner_item_drag_data_create(te, &event->x); + te->drag_data = MEM_callocN(sizeof(*te->drag_data), __func__); + /* by default we don't change the item position */ + te->drag_data->insert_te = te; + /* unset highlighted tree element, dragged one will be highlighted instead */ + outliner_set_flag(&soops->tree, TSE_HIGHLIGHTED, false); + + soops->storeflag |= SO_TREESTORE_REDRAW; /* only needs to redraw, no rebuild */ + ED_region_tag_redraw(ar); + + WM_event_add_modal_handler(C, op); + + return OPERATOR_RUNNING_MODAL; +} + +/** + * Notes about Outliner Item Drag 'n Drop: + * Right now only collections display mode is supported. But ideally all/most modes would support this. There are + * just some open design questions that have to be answered: do we want to allow mixing order of different data types + * (like render-layers and objects)? Would that be a purely visual change or would that have any other effect? ... + */ +static void OUTLINER_OT_item_drag_drop(wmOperatorType *ot) +{ + ot->name = "Drag and Drop Item"; + ot->idname = "OUTLINER_OT_item_drag_drop"; + ot->description = "Change the hierarchical position of an item by repositioning it using drag and drop"; + + ot->invoke = outliner_item_drag_drop_invoke; + ot->modal = outliner_item_drag_drop_modal; + + ot->poll = outliner_item_drag_drop_poll; + + ot->flag = OPTYPE_UNDO; +} + + /* ************************** registration **********************************/ void outliner_operatortypes(void) { + WM_operatortype_append(OUTLINER_OT_highlight_update); WM_operatortype_append(OUTLINER_OT_item_activate); WM_operatortype_append(OUTLINER_OT_select_border); WM_operatortype_append(OUTLINER_OT_item_openclose); WM_operatortype_append(OUTLINER_OT_item_rename); + WM_operatortype_append(OUTLINER_OT_item_drag_drop); WM_operatortype_append(OUTLINER_OT_operation); WM_operatortype_append(OUTLINER_OT_scene_operation); WM_operatortype_append(OUTLINER_OT_object_operation); @@ -61,6 +244,7 @@ void outliner_operatortypes(void) WM_operatortype_append(OUTLINER_OT_action_set); WM_operatortype_append(OUTLINER_OT_constraint_operation); WM_operatortype_append(OUTLINER_OT_modifier_operation); + WM_operatortype_append(OUTLINER_OT_collection_operation); WM_operatortype_append(OUTLINER_OT_show_one_level); WM_operatortype_append(OUTLINER_OT_show_active); @@ -70,10 +254,6 @@ void outliner_operatortypes(void) WM_operatortype_append(OUTLINER_OT_selected_toggle); WM_operatortype_append(OUTLINER_OT_expanded_toggle); - WM_operatortype_append(OUTLINER_OT_renderability_toggle); - WM_operatortype_append(OUTLINER_OT_selectability_toggle); - WM_operatortype_append(OUTLINER_OT_visibility_toggle); - WM_operatortype_append(OUTLINER_OT_keyingset_add_selected); WM_operatortype_append(OUTLINER_OT_keyingset_remove_selected); @@ -87,13 +267,57 @@ void outliner_operatortypes(void) WM_operatortype_append(OUTLINER_OT_scene_drop); WM_operatortype_append(OUTLINER_OT_material_drop); WM_operatortype_append(OUTLINER_OT_group_link); + + /* collections */ + WM_operatortype_append(OUTLINER_OT_collection_delete); + WM_operatortype_append(OUTLINER_OT_collection_select); + WM_operatortype_append(OUTLINER_OT_collection_link); + WM_operatortype_append(OUTLINER_OT_collection_unlink); + WM_operatortype_append(OUTLINER_OT_collection_new); + WM_operatortype_append(OUTLINER_OT_collection_override_new); + WM_operatortype_append(OUTLINER_OT_collection_objects_add); + WM_operatortype_append(OUTLINER_OT_collection_objects_remove); + WM_operatortype_append(OUTLINER_OT_collection_objects_select); + WM_operatortype_append(OUTLINER_OT_collection_objects_deselect); +} + +static wmKeyMap *outliner_item_drag_drop_modal_keymap(wmKeyConfig *keyconf) +{ + static EnumPropertyItem modal_items[] = { + {OUTLINER_ITEM_DRAG_CANCEL, "CANCEL", 0, "Cancel", ""}, + {OUTLINER_ITEM_DRAG_CONFIRM, "CONFIRM", 0, "Confirm/Drop", ""}, + {0, NULL, 0, NULL, NULL} + }; + const char *map_name = "Outliner Item Drap 'n Drop Modal Map"; + + wmKeyMap *keymap = WM_modalkeymap_get(keyconf, map_name); + + /* this function is called for each spacetype, only needs to add map once */ + if (keymap && keymap->modal_items) + return NULL; + + keymap = WM_modalkeymap_add(keyconf, map_name, modal_items); + + /* items for modal map */ + WM_modalkeymap_add_item(keymap, ESCKEY, KM_PRESS, KM_ANY, 0, OUTLINER_ITEM_DRAG_CANCEL); + WM_modalkeymap_add_item(keymap, RIGHTMOUSE, KM_PRESS, KM_ANY, 0, OUTLINER_ITEM_DRAG_CANCEL); + + WM_modalkeymap_add_item(keymap, LEFTMOUSE, KM_RELEASE, KM_ANY, 0, OUTLINER_ITEM_DRAG_CONFIRM); + WM_modalkeymap_add_item(keymap, RETKEY, KM_RELEASE, KM_ANY, 0, OUTLINER_ITEM_DRAG_CONFIRM); + WM_modalkeymap_add_item(keymap, PADENTER, KM_RELEASE, KM_ANY, 0, OUTLINER_ITEM_DRAG_CONFIRM); + + WM_modalkeymap_assign(keymap, "OUTLINER_OT_item_drag_drop"); + + return keymap; } void outliner_keymap(wmKeyConfig *keyconf) { wmKeyMap *keymap = WM_keymap_find(keyconf, "Outliner", SPACE_OUTLINER, 0); wmKeyMapItem *kmi; - + + WM_keymap_add_item(keymap, "OUTLINER_OT_highlight_update", MOUSEMOVE, KM_ANY, KM_ANY, 0); + WM_keymap_add_item(keymap, "OUTLINER_OT_item_rename", LEFTMOUSE, KM_DBL_CLICK, 0, 0); kmi = WM_keymap_add_item(keymap, "OUTLINER_OT_item_activate", LEFTMOUSE, KM_CLICK, 0, 0); @@ -123,6 +347,8 @@ void outliner_keymap(wmKeyConfig *keyconf) WM_keymap_add_item(keymap, "OUTLINER_OT_item_rename", LEFTMOUSE, KM_PRESS, KM_CTRL, 0); WM_keymap_add_item(keymap, "OUTLINER_OT_operation", RIGHTMOUSE, KM_PRESS, 0, 0); + WM_keymap_add_item(keymap, "OUTLINER_OT_item_drag_drop", EVT_TWEAK_L, KM_ANY, 0, 0); + WM_keymap_add_item(keymap, "OUTLINER_OT_show_hierarchy", HOMEKEY, KM_PRESS, 0, 0); WM_keymap_add_item(keymap, "OUTLINER_OT_show_active", PERIODKEY, KM_PRESS, 0, 0); @@ -140,11 +366,6 @@ void outliner_keymap(wmKeyConfig *keyconf) WM_keymap_verify_item(keymap, "OUTLINER_OT_selected_toggle", AKEY, KM_PRESS, 0, 0); WM_keymap_verify_item(keymap, "OUTLINER_OT_expanded_toggle", AKEY, KM_PRESS, KM_SHIFT, 0); - WM_keymap_verify_item(keymap, "OUTLINER_OT_renderability_toggle", RKEY, KM_PRESS, 0, 0); - WM_keymap_verify_item(keymap, "OUTLINER_OT_selectability_toggle", SKEY, KM_PRESS, 0, 0); - WM_keymap_verify_item(keymap, "OUTLINER_OT_visibility_toggle", VKEY, KM_PRESS, 0, 0); - - /* keying sets - only for databrowse */ WM_keymap_verify_item(keymap, "OUTLINER_OT_keyingset_add_selected", KKEY, KM_PRESS, 0, 0); WM_keymap_verify_item(keymap, "OUTLINER_OT_keyingset_remove_selected", KKEY, KM_PRESS, KM_ALT, 0); @@ -154,5 +375,7 @@ void outliner_keymap(wmKeyConfig *keyconf) WM_keymap_verify_item(keymap, "OUTLINER_OT_drivers_add_selected", DKEY, KM_PRESS, 0, 0); WM_keymap_verify_item(keymap, "OUTLINER_OT_drivers_delete_selected", DKEY, KM_PRESS, KM_ALT, 0); + + outliner_item_drag_drop_modal_keymap(keyconf); } diff --git a/source/blender/editors/space_outliner/outliner_select.c b/source/blender/editors/space_outliner/outliner_select.c index 89df471990a..85b4c33c3f1 100644 --- a/source/blender/editors/space_outliner/outliner_select.c +++ b/source/blender/editors/space_outliner/outliner_select.c @@ -46,6 +46,7 @@ #include "BKE_context.h" #include "BKE_depsgraph.h" #include "BKE_object.h" +#include "BKE_layer.h" #include "BKE_scene.h" #include "BKE_sequencer.h" #include "BKE_armature.h" @@ -68,61 +69,12 @@ #include "outliner_intern.h" -/* ****************************************************** */ -/* Outliner Selection (gray-blue highlight for rows) */ - -static int outliner_select(SpaceOops *soops, ListBase *lb, int *index, short *selecting) -{ - TreeElement *te; - TreeStoreElem *tselem; - bool changed = false; - - for (te = lb->first; te && *index >= 0; te = te->next, (*index)--) { - tselem = TREESTORE(te); - - /* if we've encountered the right item, set its 'Outliner' selection status */ - if (*index == 0) { - /* this should be the last one, so no need to do anything with index */ - if ((te->flag & TE_ICONROW) == 0) { - /* -1 value means toggle testing for now... */ - if (*selecting == -1) { - if (tselem->flag & TSE_SELECTED) - *selecting = 0; - else - *selecting = 1; - } - - /* set selection */ - if (*selecting) - tselem->flag |= TSE_SELECTED; - else - tselem->flag &= ~TSE_SELECTED; - - changed |= true; - } - } - else if (TSELEM_OPEN(tselem, soops)) { - /* Only try selecting sub-elements if we haven't hit the right element yet - * - * Hack warning: - * Index must be reduced before supplying it to the sub-tree to try to do - * selection, however, we need to increment it again for the next loop to - * function correctly - */ - (*index)--; - changed |= outliner_select(soops, &te->subtree, index, selecting); - (*index)++; - } - } - - return changed; -} /* ****************************************************** */ /* Outliner Element Selection/Activation on Click */ static eOLDrawState tree_element_active_renderlayer( - bContext *C, TreeElement *te, TreeStoreElem *tselem, const eOLSetState set) + bContext *C, Scene *UNUSED(scene), SceneLayer *UNUSED(sl), TreeElement *te, TreeStoreElem *tselem, const eOLSetState set) { Scene *sce; @@ -148,7 +100,7 @@ static eOLDrawState tree_element_active_renderlayer( */ static void do_outliner_object_select_recursive(Scene *scene, Object *ob_parent, bool select) { - Base *base; + BaseLegacy *base; for (base = FIRSTBASE; base; base = base->next) { Object *ob = base->object; @@ -184,7 +136,7 @@ static void do_outliner_ebone_select_recursive(bArmature *arm, EditBone *ebone_p } static eOLDrawState tree_element_set_active_object( - bContext *C, Scene *scene, SpaceOops *soops, + bContext *C, Scene *scene, SceneLayer *sl, SpaceOops *soops, TreeElement *te, const eOLSetState set, bool recursive) { TreeStoreElem *tselem = TREESTORE(te); @@ -198,7 +150,7 @@ static eOLDrawState tree_element_set_active_object( } else { ob = (Object *)outliner_search_back(soops, te, ID_OB); - if (ob == OBACT) { + if (ob == OBACT_NEW) { return OL_DRAWSEL_NONE; } } @@ -218,15 +170,15 @@ static eOLDrawState tree_element_set_active_object( if (base) { if (set == OL_SETSEL_EXTEND) { /* swap select */ - if (base->flag & SELECT) - ED_base_object_select(base, BA_DESELECT); + if (base->flag & BASE_SELECTED) + ED_object_base_select(base, BA_DESELECT); else - ED_base_object_select(base, BA_SELECT); + ED_object_base_select(base, BA_SELECT); } else { /* deleselect all */ - BKE_scene_base_deselect_all(scene); - ED_base_object_select(base, BA_SELECT); + BKE_scene_layer_base_deselect_all(sl); + ED_object_base_select(base, BA_SELECT); } if (recursive) { @@ -235,7 +187,7 @@ static eOLDrawState tree_element_set_active_object( } if (C) { - ED_base_object_activate(C, base); /* adds notifier */ + ED_object_base_activate(C, base); /* adds notifier */ WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene); } } @@ -247,7 +199,7 @@ static eOLDrawState tree_element_set_active_object( } static eOLDrawState tree_element_active_material( - bContext *C, Scene *scene, SpaceOops *soops, + bContext *C, Scene *UNUSED(scene), SceneLayer *sl, SpaceOops *soops, TreeElement *te, const eOLSetState set) { TreeElement *tes; @@ -256,7 +208,7 @@ static eOLDrawState tree_element_active_material( /* we search for the object parent */ ob = (Object *)outliner_search_back(soops, te, ID_OB); // note: ob->matbits can be NULL when a local object points to a library mesh. - if (ob == NULL || ob != OBACT || ob->matbits == NULL) { + if (ob == NULL || ob != OBACT_NEW || ob->matbits == NULL) { return OL_DRAWSEL_NONE; /* just paranoia */ } @@ -300,12 +252,12 @@ static eOLDrawState tree_element_active_material( } static eOLDrawState tree_element_active_texture( - bContext *C, Scene *scene, SpaceOops *UNUSED(soops), + bContext *C, Scene *scene, SceneLayer *sl, SpaceOops *UNUSED(soops), TreeElement *te, const eOLSetState set) { TreeElement *tep; TreeStoreElem /* *tselem,*/ *tselemp; - Object *ob = OBACT; + Object *ob = OBACT_NEW; SpaceButs *sbuts = NULL; if (ob == NULL) { @@ -387,14 +339,14 @@ static eOLDrawState tree_element_active_texture( static eOLDrawState tree_element_active_lamp( - bContext *UNUSED(C), Scene *scene, SpaceOops *soops, + bContext *UNUSED(C), Scene *UNUSED(scene), SceneLayer *sl, SpaceOops *soops, TreeElement *te, const eOLSetState set) { Object *ob; /* we search for the object parent */ ob = (Object *)outliner_search_back(soops, te, ID_OB); - if (ob == NULL || ob != OBACT) { + if (ob == NULL || ob != OBACT_NEW) { /* just paranoia */ return OL_DRAWSEL_NONE; } @@ -410,7 +362,7 @@ static eOLDrawState tree_element_active_lamp( } static eOLDrawState tree_element_active_camera( - bContext *UNUSED(C), Scene *scene, SpaceOops *soops, + bContext *UNUSED(C), Scene *scene, SceneLayer *UNUSED(sl), SpaceOops *soops, TreeElement *te, const eOLSetState set) { Object *ob = (Object *)outliner_search_back(soops, te, ID_OB); @@ -423,7 +375,7 @@ static eOLDrawState tree_element_active_camera( } static eOLDrawState tree_element_active_world( - bContext *C, Scene *scene, SpaceOops *UNUSED(soops), + bContext *C, Scene *scene, SceneLayer *UNUSED(sl), SpaceOops *UNUSED(soops), TreeElement *te, const eOLSetState set) { TreeElement *tep; @@ -456,7 +408,7 @@ static eOLDrawState tree_element_active_world( } static eOLDrawState tree_element_active_defgroup( - bContext *C, Scene *scene, TreeElement *te, TreeStoreElem *tselem, const eOLSetState set) + bContext *C, SceneLayer *sl, TreeElement *te, TreeStoreElem *tselem, const eOLSetState set) { Object *ob; @@ -470,7 +422,7 @@ static eOLDrawState tree_element_active_defgroup( WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, ob); } else { - if (ob == OBACT) + if (ob == OBACT_NEW) if (ob->actdef == te->index + 1) { return OL_DRAWSEL_NORMAL; } @@ -479,7 +431,7 @@ static eOLDrawState tree_element_active_defgroup( } static eOLDrawState tree_element_active_posegroup( - bContext *C, Scene *scene, TreeElement *te, TreeStoreElem *tselem, const eOLSetState set) + bContext *C, Scene *UNUSED(scene), SceneLayer *sl, TreeElement *te, TreeStoreElem *tselem, const eOLSetState set) { Object *ob = (Object *)tselem->id; @@ -490,7 +442,7 @@ static eOLDrawState tree_element_active_posegroup( } } else { - if (ob == OBACT && ob->pose) { + if (ob == OBACT_NEW && ob->pose) { if (ob->pose->active_group == te->index + 1) { return OL_DRAWSEL_NORMAL; } @@ -500,7 +452,7 @@ static eOLDrawState tree_element_active_posegroup( } static eOLDrawState tree_element_active_posechannel( - bContext *C, Scene *scene, TreeElement *te, TreeStoreElem *tselem, const eOLSetState set, bool recursive) + bContext *C, Scene *UNUSED(scene), SceneLayer *sl, TreeElement *te, TreeStoreElem *tselem, const eOLSetState set, bool recursive) { Object *ob = (Object *)tselem->id; bArmature *arm = ob->data; @@ -534,7 +486,7 @@ static eOLDrawState tree_element_active_posechannel( } } else { - if (ob == OBACT && ob->pose) { + if (ob == OBACT_NEW && ob->pose) { if (pchan->bone->flag & BONE_SELECTED) { return OL_DRAWSEL_NORMAL; } @@ -544,14 +496,14 @@ static eOLDrawState tree_element_active_posechannel( } static eOLDrawState tree_element_active_bone( - bContext *C, Scene *scene, TreeElement *te, TreeStoreElem *tselem, const eOLSetState set, bool recursive) + bContext *C, SceneLayer *sl, TreeElement *te, TreeStoreElem *tselem, const eOLSetState set, bool recursive) { bArmature *arm = (bArmature *)tselem->id; Bone *bone = te->directdata; if (set != OL_SETSEL_NONE) { if (!(bone->flag & BONE_HIDDEN_P)) { - Object *ob = OBACT; + Object *ob = OBACT_NEW; if (ob) { if (set != OL_SETSEL_EXTEND) { /* single select forces all other bones to get unselected */ @@ -580,7 +532,7 @@ static eOLDrawState tree_element_active_bone( } } else { - Object *ob = OBACT; + Object *ob = OBACT_NEW; if (ob && ob->data == arm) { if (bone->flag & BONE_SELECTED) { @@ -653,7 +605,7 @@ static eOLDrawState tree_element_active_ebone( } static eOLDrawState tree_element_active_modifier( - bContext *C, TreeElement *UNUSED(te), TreeStoreElem *tselem, const eOLSetState set) + bContext *C, Scene *UNUSED(scene), SceneLayer *UNUSED(sl), TreeElement *UNUSED(te), TreeStoreElem *tselem, const eOLSetState set) { if (set != OL_SETSEL_NONE) { Object *ob = (Object *)tselem->id; @@ -681,7 +633,7 @@ static eOLDrawState tree_element_active_psys( } static int tree_element_active_constraint( - bContext *C, TreeElement *UNUSED(te), TreeStoreElem *tselem, const eOLSetState set) + bContext *C, Scene *UNUSED(scene), SceneLayer *UNUSED(sl), TreeElement *UNUSED(te), TreeStoreElem *tselem, const eOLSetState set) { if (set != OL_SETSEL_NONE) { Object *ob = (Object *)tselem->id; @@ -694,7 +646,7 @@ static int tree_element_active_constraint( } static eOLDrawState tree_element_active_text( - bContext *UNUSED(C), Scene *UNUSED(scene), SpaceOops *UNUSED(soops), + bContext *UNUSED(C), Scene *UNUSED(scene), SceneLayer *UNUSED(sl), SpaceOops *UNUSED(soops), TreeElement *UNUSED(te), int UNUSED(set)) { // XXX removed @@ -702,10 +654,10 @@ static eOLDrawState tree_element_active_text( } static eOLDrawState tree_element_active_pose( - bContext *C, Scene *scene, TreeElement *UNUSED(te), TreeStoreElem *tselem, const eOLSetState set) + bContext *C, Scene *scene, SceneLayer *sl, TreeElement *UNUSED(te), TreeStoreElem *tselem, const eOLSetState set) { Object *ob = (Object *)tselem->id; - Base *base = BKE_scene_base_find(scene, ob); + Base *base = BKE_scene_layer_base_find(sl, ob); if (set != OL_SETSEL_NONE) { if (scene->obedit) @@ -786,7 +738,7 @@ static eOLDrawState tree_element_active_sequence_dup( } static eOLDrawState tree_element_active_keymap_item( - bContext *UNUSED(C), TreeElement *te, TreeStoreElem *UNUSED(tselem), const eOLSetState set) + bContext *UNUSED(C), Scene *UNUSED(scene), SceneLayer *UNUSED(sl), TreeElement *te, TreeStoreElem *UNUSED(tselem), const eOLSetState set) { wmKeyMapItem *kmi = te->directdata; @@ -802,10 +754,27 @@ static eOLDrawState tree_element_active_keymap_item( return OL_DRAWSEL_NONE; } +static eOLDrawState tree_element_active_collection( + bContext *C, TreeElement *te, TreeStoreElem *UNUSED(tselem), const eOLSetState set) +{ + if (set != OL_SETSEL_NONE) { + SceneLayer *sl = CTX_data_scene_layer(C); + LayerCollection *lc = te->directdata; + const int collection_index = BKE_layer_collection_findindex(sl, lc); + + BLI_assert(collection_index >= 0); + sl->active_collection = collection_index; + WM_main_add_notifier(NC_SCENE | ND_LAYER, NULL); + return OL_DRAWSEL_ACTIVE; + } + + return OL_DRAWSEL_NONE; +} + /* ---------------------------------------------- */ /* generic call for ID data check or make/check active in UI */ -eOLDrawState tree_element_active(bContext *C, Scene *scene, SpaceOops *soops, TreeElement *te, +eOLDrawState tree_element_active(bContext *C, Scene *scene, SceneLayer *sl, SpaceOops *soops, TreeElement *te, const eOLSetState set, const bool handle_all_types) { switch (te->idcode) { @@ -813,21 +782,21 @@ eOLDrawState tree_element_active(bContext *C, Scene *scene, SpaceOops *soops, Tr * selection. See do_outliner_item_activate. */ case ID_OB: if (handle_all_types) { - return tree_element_set_active_object(C, scene, soops, te, set, false); + return tree_element_set_active_object(C, scene, sl, soops, te, set, false); } break; case ID_MA: - return tree_element_active_material(C, scene, soops, te, set); + return tree_element_active_material(C, scene, sl, soops, te, set); case ID_WO: - return tree_element_active_world(C, scene, soops, te, set); + return tree_element_active_world(C, scene, sl, soops, te, set); case ID_LA: - return tree_element_active_lamp(C, scene, soops, te, set); + return tree_element_active_lamp(C, scene, sl, soops, te, set); case ID_TE: - return tree_element_active_texture(C, scene, soops, te, set); + return tree_element_active_texture(C, scene, sl, soops, te, set); case ID_TXT: - return tree_element_active_text(C, scene, soops, te, set); + return tree_element_active_text(C, scene, sl, soops, te, set); case ID_CA: - return tree_element_active_camera(C, scene, soops, te, set); + return tree_element_active_camera(C, scene, sl, soops, te, set); } return OL_DRAWSEL_NONE; } @@ -838,211 +807,216 @@ eOLDrawState tree_element_active(bContext *C, Scene *scene, SpaceOops *soops, Tr * \note Context can be NULL when ``(set == OL_SETSEL_NONE)`` */ eOLDrawState tree_element_type_active( - bContext *C, Scene *scene, SpaceOops *soops, + bContext *C, Scene *scene, SceneLayer *sl, SpaceOops *soops, TreeElement *te, TreeStoreElem *tselem, const eOLSetState set, bool recursive) { switch (tselem->type) { case TSE_DEFGROUP: - return tree_element_active_defgroup(C, scene, te, tselem, set); + return tree_element_active_defgroup(C, sl, te, tselem, set); case TSE_BONE: - return tree_element_active_bone(C, scene, te, tselem, set, recursive); + return tree_element_active_bone(C, sl, te, tselem, set, recursive); case TSE_EBONE: return tree_element_active_ebone(C, scene, te, tselem, set, recursive); case TSE_MODIFIER: - return tree_element_active_modifier(C, te, tselem, set); + return tree_element_active_modifier(C, scene, sl, te, tselem, set); case TSE_LINKED_OB: if (set != OL_SETSEL_NONE) { - tree_element_set_active_object(C, scene, soops, te, set, false); + tree_element_set_active_object(C, scene, sl, soops, te, set, false); } - else if (tselem->id == (ID *)OBACT) { + else if (tselem->id == (ID *)OBACT_NEW) { return OL_DRAWSEL_NORMAL; } break; case TSE_LINKED_PSYS: return tree_element_active_psys(C, scene, te, tselem, set); case TSE_POSE_BASE: - return tree_element_active_pose(C, scene, te, tselem, set); + return tree_element_active_pose(C, scene, sl, te, tselem, set); case TSE_POSE_CHANNEL: - return tree_element_active_posechannel(C, scene, te, tselem, set, recursive); + return tree_element_active_posechannel(C, scene, sl, te, tselem, set, recursive); case TSE_CONSTRAINT: - return tree_element_active_constraint(C, te, tselem, set); + return tree_element_active_constraint(C, scene, sl, te, tselem, set); case TSE_R_LAYER: - return tree_element_active_renderlayer(C, te, tselem, set); + return tree_element_active_renderlayer(C, scene, sl, te, tselem, set); case TSE_POSEGRP: - return tree_element_active_posegroup(C, scene, te, tselem, set); + return tree_element_active_posegroup(C, scene, sl, te, tselem, set); case TSE_SEQUENCE: return tree_element_active_sequence(C, scene, te, tselem, set); case TSE_SEQUENCE_DUP: return tree_element_active_sequence_dup(scene, te, tselem, set); case TSE_KEYMAP_ITEM: - return tree_element_active_keymap_item(C, te, tselem, set); + return tree_element_active_keymap_item(C, scene, sl, te, tselem, set); case TSE_GP_LAYER: - //return tree_element_active_gplayer(C, scene, te, tselem, set); + //return tree_element_active_gplayer(C, scene, s, te, tselem, set); break; - + case TSE_COLLECTION: + return tree_element_active_collection(C, te, tselem, set); } return OL_DRAWSEL_NONE; } /* ================================================ */ -static bool do_outliner_item_activate(bContext *C, Scene *scene, ARegion *ar, SpaceOops *soops, - TreeElement *te, bool extend, bool recursive, const float mval[2]) +static void outliner_item_activate( + bContext *C, SpaceOops *soops, TreeElement *te, + const bool extend, const bool recursive) { - - if (mval[1] > te->ys && mval[1] < te->ys + UI_UNIT_Y) { - TreeStoreElem *tselem = TREESTORE(te); - bool openclose = false; - - /* open close icon */ - if ((te->flag & TE_ICONROW) == 0) { // hidden icon, no open/close - if (mval[0] > te->xs && mval[0] < te->xs + UI_UNIT_X) - openclose = true; - } - - if (openclose) { - /* all below close/open? */ - if (extend) { - tselem->flag &= ~TSE_CLOSED; - outliner_set_flag(&te->subtree, TSE_CLOSED, !outliner_has_one_flag(&te->subtree, TSE_CLOSED, 1)); - } - else { - if (tselem->flag & TSE_CLOSED) tselem->flag &= ~TSE_CLOSED; - else tselem->flag |= TSE_CLOSED; - + Scene *scene = CTX_data_scene(C); + SceneLayer *sl = CTX_data_scene_layer(C); + TreeStoreElem *tselem = TREESTORE(te); + + /* always makes active object, except for some specific types. + * Note about TSE_EBONE: In case of a same ID_AR datablock shared among several objects, we do not want + * to switch out of edit mode (see T48328 for details). */ + if (!ELEM(tselem->type, TSE_SEQUENCE, TSE_SEQ_STRIP, TSE_SEQUENCE_DUP, TSE_EBONE, TSE_COLLECTION)) { + tree_element_set_active_object(C, scene, sl, soops, te, + (extend && tselem->type == 0) ? OL_SETSEL_EXTEND : OL_SETSEL_NORMAL, + recursive && tselem->type == 0); + } + + if (tselem->type == 0) { // the lib blocks + /* editmode? */ + if (te->idcode == ID_SCE) { + if (scene != (Scene *)tselem->id) { + ED_screen_set_scene(C, CTX_wm_screen(C), (Scene *)tselem->id); } - - return true; } - /* name and first icon */ - else if (mval[0] > te->xs + UI_UNIT_X && mval[0] < te->xend) { - - /* always makes active object, except for some specific types. - * Note about TSE_EBONE: In case of a same ID_AR datablock shared among several objects, we do not want - * to switch out of edit mode (see T48328 for details). */ - if (!ELEM(tselem->type, TSE_SEQUENCE, TSE_SEQ_STRIP, TSE_SEQUENCE_DUP, TSE_EBONE)) { - tree_element_set_active_object(C, scene, soops, te, - (extend && tselem->type == 0) ? OL_SETSEL_EXTEND : OL_SETSEL_NORMAL, - recursive && tselem->type == 0); - } + else if (te->idcode == ID_GR) { + Group *gr = (Group *)tselem->id; + GroupObject *gob; - if (tselem->type == 0) { // the lib blocks - /* editmode? */ - if (te->idcode == ID_SCE) { - if (scene != (Scene *)tselem->id) { - ED_screen_set_scene(C, CTX_wm_screen(C), (Scene *)tselem->id); - } - } - else if (te->idcode == ID_GR) { - Group *gr = (Group *)tselem->id; - GroupObject *gob; - - if (extend) { - int sel = BA_SELECT; - for (gob = gr->gobject.first; gob; gob = gob->next) { - if (gob->ob->flag & SELECT) { - sel = BA_DESELECT; - break; - } - } - - for (gob = gr->gobject.first; gob; gob = gob->next) { - ED_base_object_select(BKE_scene_base_find(scene, gob->ob), sel); - } - } - else { - BKE_scene_base_deselect_all(scene); - - for (gob = gr->gobject.first; gob; gob = gob->next) { - if ((gob->ob->flag & SELECT) == 0) - ED_base_object_select(BKE_scene_base_find(scene, gob->ob), BA_SELECT); - } + if (extend) { + int sel = BA_SELECT; + for (gob = gr->gobject.first; gob; gob = gob->next) { + if (gob->ob->flag & SELECT) { + sel = BA_DESELECT; + break; } - - WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene); - } - else if (ELEM(te->idcode, ID_ME, ID_CU, ID_MB, ID_LT, ID_AR)) { - WM_operator_name_call(C, "OBJECT_OT_editmode_toggle", WM_OP_INVOKE_REGION_WIN, NULL); - } - else { // rest of types - tree_element_active(C, scene, soops, te, OL_SETSEL_NORMAL, false); } + for (gob = gr->gobject.first; gob; gob = gob->next) { + ED_object_base_select(BKE_scene_layer_base_find(sl, gob->ob), sel); + } } else { - tree_element_type_active(C, scene, soops, te, tselem, - extend ? OL_SETSEL_EXTEND : OL_SETSEL_NORMAL, - recursive); + BKE_scene_layer_base_deselect_all(sl); + + for (gob = gr->gobject.first; gob; gob = gob->next) { + Base *base = BKE_scene_layer_base_find(sl, gob->ob); + if ((base->flag & BASE_SELECTED) == 0) { + ED_object_base_select(base, BA_SELECT); + } + } } - return true; + WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene); } - } - - for (te = te->subtree.first; te; te = te->next) { - if (do_outliner_item_activate(C, scene, ar, soops, te, extend, recursive, mval)) { - return true; + else if (ELEM(te->idcode, ID_ME, ID_CU, ID_MB, ID_LT, ID_AR)) { + WM_operator_name_call(C, "OBJECT_OT_editmode_toggle", WM_OP_INVOKE_REGION_WIN, NULL); } + else { // rest of types + tree_element_active(C, scene, sl, soops, te, OL_SETSEL_NORMAL, false); + } + + } + else { + tree_element_type_active(C, scene, sl, soops, te, tselem, + extend ? OL_SETSEL_EXTEND : OL_SETSEL_NORMAL, + recursive); + } +} + +/** + * \param extend: Don't deselect other items, only modify \a te. + * \param toggle: Select \a te when not selected, deselect when selected. + */ +static void outliner_item_select(SpaceOops *soops, const TreeElement *te, const bool extend, const bool toggle) +{ + TreeStoreElem *tselem = TREESTORE(te); + const short new_flag = toggle ? (tselem->flag ^ TSE_SELECTED) : (tselem->flag | TSE_SELECTED); + + if (extend == false) { + outliner_set_flag(&soops->tree, TSE_SELECTED, false); } - return false; + tselem->flag = new_flag; } -int outliner_item_do_activate(bContext *C, int x, int y, bool extend, bool recursive) +static void outliner_item_toggle_closed(TreeElement *te, const bool toggle_children) +{ + TreeStoreElem *tselem = TREESTORE(te); + if (toggle_children) { + tselem->flag &= ~TSE_CLOSED; + + const bool all_opened = !outliner_has_one_flag(&te->subtree, TSE_CLOSED, 1); + outliner_set_flag(&te->subtree, TSE_CLOSED, all_opened); + } + else { + tselem->flag ^= TSE_CLOSED; + } +} + +static bool outliner_item_is_co_within_close_toggle(TreeElement *te, float view_co_x) +{ + return ((te->flag & TE_ICONROW) == 0) && (view_co_x > te->xs) && (view_co_x < te->xs + UI_UNIT_X); +} + +static bool outliner_is_co_within_restrict_columns(const SpaceOops *soops, const ARegion *ar, float view_co_x) +{ + return (!ELEM(soops->outlinevis, SO_DATABLOCKS, SO_USERDEF) && + !(soops->flag & SO_HIDE_RESTRICTCOLS) && + (view_co_x > ar->v2d.cur.xmax - OL_TOG_RESTRICT_VIEWX)); +} + +int outliner_item_activate_or_toggle_closed(bContext *C, int x, int y, bool extend, bool recursive) { - Scene *scene = CTX_data_scene(C); ARegion *ar = CTX_wm_region(C); SpaceOops *soops = CTX_wm_space_outliner(C); TreeElement *te; - float fmval[2]; + float view_mval[2]; + bool changed = false, rebuild_tree = false; - UI_view2d_region_to_view(&ar->v2d, x, y, &fmval[0], &fmval[1]); + UI_view2d_region_to_view(&ar->v2d, x, y, &view_mval[0], &view_mval[1]); - if (!ELEM(soops->outlinevis, SO_DATABLOCKS, SO_USERDEF) && - !(soops->flag & SO_HIDE_RESTRICTCOLS) && - (fmval[0] > ar->v2d.cur.xmax - OL_TOG_RESTRICT_VIEWX)) - { + if (outliner_is_co_within_restrict_columns(soops, ar, view_mval[0])) { return OPERATOR_CANCELLED; } - for (te = soops->tree.first; te; te = te->next) { - if (do_outliner_item_activate(C, scene, ar, soops, te, extend, recursive, fmval)) break; + if (!(te = outliner_find_item_at_y(soops, &soops->tree, view_mval[1]))) { + /* skip */ } - - if (te) { - ED_undo_push(C, "Outliner click event"); + else if (outliner_item_is_co_within_close_toggle(te, view_mval[0])) { + outliner_item_toggle_closed(te, extend); + changed = true; + rebuild_tree = true; } else { - short selecting = -1; - int row; - - /* get row number - 100 here is just a dummy value since we don't need the column */ - UI_view2d_listview_view_to_cell(&ar->v2d, 1000, UI_UNIT_Y, 0.0f, OL_Y_OFFSET, - fmval[0], fmval[1], NULL, &row); - - /* select relevant row */ - if (outliner_select(soops, &soops->tree, &row, &selecting)) { - + /* the row may also contain children, if one is hovered we want this instead of current te */ + TreeElement *activate_te = outliner_find_item_at_x_in_row(soops, te, view_mval[0]); + + outliner_item_select(soops, activate_te, extend, extend); + outliner_item_activate(C, soops, activate_te, extend, recursive); + changed = true; + } + + if (changed) { + if (!rebuild_tree) { + /* only needs to redraw, no rebuild */ soops->storeflag |= SO_TREESTORE_REDRAW; - - /* no need for undo push here, only changing outliner data which is - * scene level - campbell */ - /* ED_undo_push(C, "Outliner selection event"); */ } + ED_undo_push(C, "Outliner selection change"); + ED_region_tag_redraw(ar); } - - ED_region_tag_redraw(ar); return OPERATOR_FINISHED; } /* event can enterkey, then it opens/closes */ -static int outliner_item_activate(bContext *C, wmOperator *op, const wmEvent *event) +static int outliner_item_activate_invoke(bContext *C, wmOperator *op, const wmEvent *event) { bool extend = RNA_boolean_get(op->ptr, "extend"); bool recursive = RNA_boolean_get(op->ptr, "recursive"); int x = event->mval[0]; int y = event->mval[1]; - return outliner_item_do_activate(C, x, y, extend, recursive); + return outliner_item_activate_or_toggle_closed(C, x, y, extend, recursive); } void OUTLINER_OT_item_activate(wmOperatorType *ot) @@ -1051,7 +1025,7 @@ void OUTLINER_OT_item_activate(wmOperatorType *ot) ot->idname = "OUTLINER_OT_item_activate"; ot->description = "Handle mouse clicks to activate/select items"; - ot->invoke = outliner_item_activate; + ot->invoke = outliner_item_activate_invoke; ot->poll = ED_operator_outliner_active; diff --git a/source/blender/editors/space_outliner/outliner_tools.c b/source/blender/editors/space_outliner/outliner_tools.c index 4eda7977622..320e38e82be 100644 --- a/source/blender/editors/space_outliner/outliner_tools.c +++ b/source/blender/editors/space_outliner/outliner_tools.c @@ -56,6 +56,7 @@ #include "BKE_depsgraph.h" #include "BKE_fcurve.h" #include "BKE_group.h" +#include "BKE_layer.h" #include "BKE_library.h" #include "BKE_library_query.h" #include "BKE_library_remap.h" @@ -360,15 +361,15 @@ void OUTLINER_OT_scene_operation(wmOperatorType *ot) /* ******************************************** */ static void object_select_cb( - bContext *UNUSED(C), ReportList *UNUSED(reports), Scene *scene, TreeElement *te, + bContext *C, ReportList *UNUSED(reports), Scene *UNUSED(scene), TreeElement *UNUSED(te), TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data)) { - Base *base = (Base *)te->directdata; - - if (base == NULL) base = BKE_scene_base_find(scene, (Object *)tselem->id); - if (base && ((base->object->restrictflag & OB_RESTRICT_VIEW) == 0)) { - base->flag |= SELECT; - base->object->flag |= SELECT; + SceneLayer *sl = CTX_data_scene_layer(C); + Object *ob = (Object *)tselem->id; + Base *base = BKE_scene_layer_base_find(sl, ob); + + if (base && ((base->flag & BASE_VISIBLED) != 0)) { + base->flag |= BASE_SELECTED; } } @@ -380,51 +381,48 @@ static void object_select_hierarchy_cb( wmWindow *win = CTX_wm_window(C); int x = win->eventstate->mval[0]; int y = win->eventstate->mval[1]; - outliner_item_do_activate(C, x, y, true, true); + outliner_item_activate_or_toggle_closed(C, x, y, true, true); } static void object_deselect_cb( - bContext *UNUSED(C), ReportList *UNUSED(reports), Scene *scene, TreeElement *te, + bContext *C, ReportList *UNUSED(reports), Scene *UNUSED(scene), TreeElement *UNUSED(te), TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data)) { - Base *base = (Base *)te->directdata; - - if (base == NULL) base = BKE_scene_base_find(scene, (Object *)tselem->id); + SceneLayer *sl = CTX_data_scene_layer(C); + Object *ob = (Object *)tselem->id; + Base *base = BKE_scene_layer_base_find(sl, ob); + if (base) { - base->flag &= ~SELECT; - base->object->flag &= ~SELECT; + base->flag &= ~BASE_SELECTED; } } static void object_delete_cb( - bContext *C, ReportList *reports, Scene *scene, TreeElement *te, + bContext *C, ReportList *reports, Scene *scene, TreeElement *UNUSED(te), TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data)) { - Base *base = (Base *)te->directdata; - - if (base == NULL) - base = BKE_scene_base_find(scene, (Object *)tselem->id); - if (base) { + Object *ob = (Object *)tselem->id; + if (ob) { Main *bmain = CTX_data_main(C); - if (base->object->id.tag & LIB_TAG_INDIRECT) { - BKE_reportf(reports, RPT_WARNING, "Cannot delete indirectly linked object '%s'", base->object->id.name + 2); + if (ob->id.tag & LIB_TAG_INDIRECT) { + BKE_reportf(reports, RPT_WARNING, "Cannot delete indirectly linked object '%s'", ob->id.name + 2); return; } - else if (BKE_library_ID_is_indirectly_used(bmain, base->object) && - ID_REAL_USERS(base->object) <= 1 && ID_EXTRA_USERS(base->object) == 0) + else if (BKE_library_ID_is_indirectly_used(bmain, ob) && + ID_REAL_USERS(ob) <= 1 && ID_EXTRA_USERS(ob) == 0) { BKE_reportf(reports, RPT_WARNING, "Cannot delete object '%s' from scene '%s', indirectly used objects need at least one user", - base->object->id.name + 2, scene->id.name + 2); + ob->id.name + 2, scene->id.name + 2); return; } // check also library later - if (scene->obedit == base->object) + if (scene->obedit == ob) ED_object_editmode_exit(C, EM_FREEDATA | EM_FREEUNDO | EM_WAITCURSOR | EM_DO_UNDO); - ED_base_object_free_and_unlink(CTX_data_main(C), scene, base); + ED_base_object_free_and_unlink(CTX_data_main(C), scene, ob); /* leave for ED_outliner_id_unref to handle */ #if 0 te->directdata = NULL; @@ -520,7 +518,7 @@ static void group_linkobs2scene_cb( { Group *group = (Group *)tselem->id; GroupObject *gob; - Base *base; + BaseLegacy *base; for (gob = group->gobject.first; gob; gob = gob->next) { base = BKE_scene_base_find(scene, gob->ob); @@ -530,7 +528,7 @@ static void group_linkobs2scene_cb( id_us_plus(&gob->ob->id); } base->object->flag |= SELECT; - base->flag |= SELECT; + base->flag_legacy |= SELECT; } } @@ -650,6 +648,14 @@ typedef enum eOutliner_PropModifierOps { OL_MODIFIER_OP_DELETE } eOutliner_PropModifierOps; +typedef enum eOutliner_PropCollectionOps { + OL_COLLECTION_OP_OBJECTS_ADD = 1, + OL_COLLECTION_OP_OBJECTS_REMOVE, + OL_COLLECTION_OP_COLLECTION_NEW, + OL_COLLECTION_OP_COLLECTION_DEL, + OL_COLLECTION_OP_COLLECTION_UNLINK, +} eOutliner_PropCollectionOps; + static void pchan_cb(int event, TreeElement *te, TreeStoreElem *UNUSED(tselem), void *UNUSED(arg)) { bPoseChannel *pchan = (bPoseChannel *)te->directdata; @@ -800,6 +806,61 @@ static void modifier_cb(int event, TreeElement *te, TreeStoreElem *UNUSED(tselem } } +static void collection_cb(int event, TreeElement *te, TreeStoreElem *UNUSED(tselem), void *Carg) +{ + bContext *C = (bContext *)Carg; + Scene *scene = CTX_data_scene(C); + LayerCollection *lc = te->directdata; + SceneCollection *sc = lc->scene_collection; + + if (event == OL_COLLECTION_OP_OBJECTS_ADD) { + CTX_DATA_BEGIN (C, Object *, ob, selected_objects) + { + BKE_collection_object_add(scene, sc, ob); + } + CTX_DATA_END; + + WM_event_add_notifier(C, NC_SCENE | ND_LAYER, scene); + } + else if (event == OL_COLLECTION_OP_OBJECTS_REMOVE) { + Main *bmain = CTX_data_main(C); + + CTX_DATA_BEGIN (C, Object *, ob, selected_objects) + { + BKE_collection_object_remove(bmain, scene, sc, ob, true); + } + CTX_DATA_END; + + WM_event_add_notifier(C, NC_SCENE | ND_LAYER, scene); + te->store_elem->flag &= ~TSE_SELECTED; + } + else if (event == OL_COLLECTION_OP_COLLECTION_NEW) { + BKE_collection_add(scene, sc, NULL); + WM_event_add_notifier(C, NC_SCENE | ND_LAYER, scene); + } + else if (event == OL_COLLECTION_OP_COLLECTION_UNLINK) { + SceneLayer *sl = CTX_data_scene_layer(C); + + if (BLI_findindex(&sl->layer_collections, lc) == -1) { + /* we can't unlink if the layer collection wasn't directly linked */ + TODO_LAYER_OPERATORS; /* this shouldn't be in the menu in those cases */ + } + else { + BKE_collection_unlink(sl, lc); + WM_event_add_notifier(C, NC_SCENE | ND_LAYER, scene); + } + } + else if (event == OL_COLLECTION_OP_COLLECTION_DEL) { + if (BKE_collection_remove(scene, sc)) { + WM_event_add_notifier(C, NC_SCENE | ND_LAYER, scene); + } + else { + /* we can't remove the master collection */ + TODO_LAYER_OPERATORS; /* this shouldn't be in the menu in those cases */ + } + } +} + static void outliner_do_data_operation(SpaceOops *soops, int type, int event, ListBase *lb, void (*operation_cb)(int, TreeElement *, TreeStoreElem *, void *), void *arg) @@ -820,9 +881,9 @@ static void outliner_do_data_operation(SpaceOops *soops, int type, int event, Li } } -static Base *outline_delete_hierarchy(bContext *C, ReportList *reports, Scene *scene, Base *base) +static BaseLegacy *outline_delete_hierarchy(bContext *C, ReportList *reports, Scene *scene, BaseLegacy *base) { - Base *child_base, *base_next; + BaseLegacy *child_base, *base_next; Object *parent; if (!base) { @@ -852,7 +913,7 @@ static Base *outline_delete_hierarchy(bContext *C, ReportList *reports, Scene *s base->object->id.name + 2, scene->id.name + 2); return base_next; } - ED_base_object_free_and_unlink(CTX_data_main(C), scene, base); + ED_base_object_free_and_unlink(CTX_data_main(C), scene, base->object); return base_next; } @@ -860,6 +921,7 @@ static void object_delete_hierarchy_cb( bContext *C, ReportList *reports, Scene *scene, TreeElement *te, TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data)) { +#if 0 Base *base = (Base *)te->directdata; Object *obedit = scene->obedit; @@ -882,6 +944,15 @@ static void object_delete_hierarchy_cb( } WM_event_add_notifier(C, NC_SCENE | ND_OB_ACTIVE, scene); +#else + (void) C; + (void) scene; + (void) te; + (void) tselem; + (void) outline_delete_hierarchy; + BKE_reportf(reports, RPT_ERROR, "Delete from outliner not supported at the moment"); + TODO_LAYER_BASE +#endif } /* **************************************** */ @@ -985,21 +1056,6 @@ static int outliner_object_operation_exec(bContext *C, wmOperator *op) outliner_do_object_operation(C, op->reports, scene, soops, &soops->tree, id_local_cb); str = "Localized Objects"; } - else if (event == OL_OP_TOGVIS) { - outliner_do_object_operation(C, op->reports, scene, soops, &soops->tree, object_toggle_visibility_cb); - str = "Toggle Visibility"; - WM_event_add_notifier(C, NC_SCENE | ND_OB_VISIBLE, scene); - } - else if (event == OL_OP_TOGSEL) { - outliner_do_object_operation(C, op->reports, scene, soops, &soops->tree, object_toggle_selectability_cb); - str = "Toggle Selectability"; - WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene); - } - else if (event == OL_OP_TOGREN) { - outliner_do_object_operation(C, op->reports, scene, soops, &soops->tree, object_toggle_renderability_cb); - str = "Toggle Renderability"; - WM_event_add_notifier(C, NC_SCENE | ND_OB_RENDER, scene); - } else if (event == OL_OP_RENAME) { outliner_do_object_operation(C, op->reports, scene, soops, &soops->tree, item_rename_cb); str = "Rename Object"; @@ -1095,15 +1151,6 @@ static int outliner_group_operation_exec(bContext *C, wmOperator *op) case OL_GROUPOP_REMAP: outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, id_remap_cb, NULL); break; - case OL_GROUPOP_TOGVIS: - outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, group_toggle_visibility_cb, NULL); - break; - case OL_GROUPOP_TOGSEL: - outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, group_toggle_selectability_cb, NULL); - break; - case OL_GROUPOP_TOGREN: - outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, group_toggle_renderability_cb, NULL); - break; case OL_GROUPOP_RENAME: outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, item_rename_cb, NULL); break; @@ -1739,6 +1786,52 @@ void OUTLINER_OT_modifier_operation(wmOperatorType *ot) /* ******************** */ +static EnumPropertyItem prop_collection_op_types[] = { + {OL_COLLECTION_OP_OBJECTS_ADD, "OBJECTS_ADD", ICON_ZOOMIN, "Add Selected", "Add selected objects to collection"}, + {OL_COLLECTION_OP_OBJECTS_REMOVE, "OBJECTS_REMOVE", ICON_X, "Remove Selected", "Remove selected objects from collection"}, + {OL_COLLECTION_OP_COLLECTION_NEW, "COLLECTION_NEW", ICON_NEW, "New Collection", "Add a new nested collection"}, + {OL_COLLECTION_OP_COLLECTION_UNLINK, "COLLECTION_UNLINK", ICON_UNLINKED, "Unlink", "Unlink collection"}, + {OL_COLLECTION_OP_COLLECTION_DEL, "COLLECTION_NEW", ICON_X, "Delete Collection", "Delete the collection"}, + {0, NULL, 0, NULL, NULL} +}; + +static int outliner_collection_operation_exec(bContext *C, wmOperator *op) +{ + SpaceOops *soops = CTX_wm_space_outliner(C); + int scenelevel = 0, objectlevel = 0, idlevel = 0, datalevel = 0; + eOutliner_PropCollectionOps event; + + event = RNA_enum_get(op->ptr, "type"); + set_operation_types(soops, &soops->tree, &scenelevel, &objectlevel, &idlevel, &datalevel); + + outliner_do_data_operation(soops, datalevel, event, &soops->tree, collection_cb, C); + + outliner_cleanup_tree(soops); + + ED_undo_push(C, "Collection operation"); + + return OPERATOR_FINISHED; +} + +void OUTLINER_OT_collection_operation(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Outliner Collection Operation"; + ot->idname = "OUTLINER_OT_collection_operation"; + ot->description = ""; + + /* callbacks */ + ot->invoke = WM_menu_invoke; + ot->exec = outliner_collection_operation_exec; + ot->poll = ED_operator_outliner_active; + + ot->flag = 0; + + ot->prop = RNA_def_enum(ot->srna, "type", prop_collection_op_types, 0, "Collection Operation", ""); +} + +/* ******************** */ + // XXX: select linked is for RNA structs only static EnumPropertyItem prop_data_op_types[] = { {OL_DOP_SELECT, "SELECT", 0, "Select", ""}, @@ -1913,6 +2006,9 @@ static int do_outliner_operation_event(bContext *C, ARegion *ar, SpaceOops *soop else if (datalevel == TSE_MODIFIER) { WM_operator_name_call(C, "OUTLINER_OT_modifier_operation", WM_OP_INVOKE_REGION_WIN, NULL); } + else if (datalevel == TSE_COLLECTION) { + WM_operator_name_call(C, "OUTLINER_OT_collection_operation", WM_OP_INVOKE_REGION_WIN, NULL); + } else { WM_operator_name_call(C, "OUTLINER_OT_data_operation", WM_OP_INVOKE_REGION_WIN, NULL); } diff --git a/source/blender/editors/space_outliner/outliner_tree.c b/source/blender/editors/space_outliner/outliner_tree.c index ec46c5df9a0..11b25f7fc87 100644 --- a/source/blender/editors/space_outliner/outliner_tree.c +++ b/source/blender/editors/space_outliner/outliner_tree.c @@ -63,6 +63,7 @@ #include "BKE_fcurve.h" #include "BKE_main.h" +#include "BKE_layer.h" #include "BKE_library.h" #include "BKE_modifier.h" #include "BKE_sequencer.h" @@ -83,6 +84,9 @@ # include "BLI_math_base.h" /* M_PI */ #endif +/* prototypes */ +static void outliner_make_hierarchy(ListBase *lb); + /* ********************************************************* */ /* Persistent Data */ @@ -903,8 +907,8 @@ static TreeElement *outliner_add_element(SpaceOops *soops, ListBase *lb, void *i id = TREESTORE(parent)->id; } - /* One exception */ - if (type == TSE_ID_BASE) { + /* exceptions */ + if (ELEM(type, TSE_ID_BASE, TSE_COLLECTION)) { /* pass */ } else if (id == NULL) { @@ -941,6 +945,9 @@ static TreeElement *outliner_add_element(SpaceOops *soops, ListBase *lb, void *i else if (type == TSE_GP_LAYER) { /* pass */ } + else if (type == TSE_COLLECTION) { + /* pass */ + } else if (type == TSE_ID_BASE) { /* pass */ } @@ -1370,6 +1377,39 @@ static void outliner_add_orphaned_datablocks(Main *mainvar, SpaceOops *soops) } } +static void outliner_collections_reorder(const Scene *scene, TreeElement *insert_element, TreeElement *insert_after) +{ + SceneLayer *sl = BKE_scene_layer_render_active(scene); + LayerCollection *insert_coll = insert_element->directdata; + LayerCollection *insert_after_coll = insert_after ? insert_after->directdata : NULL; + + BKE_layer_collection_reinsert_after(scene, sl, insert_coll, insert_after_coll); +} + +static void outliner_add_collections_recursive(SpaceOops *soops, ListBase *tree, Scene *scene, + ListBase *layer_collections, TreeElement *parent_ten) +{ + for (LayerCollection *collection = layer_collections->first; collection; collection = collection->next) { + TreeElement *ten = outliner_add_element(soops, tree, scene, parent_ten, TSE_COLLECTION, 0); + + ten->name = collection->scene_collection->name; + ten->directdata = collection; + ten->reinsert = outliner_collections_reorder; + + for (LinkData *link = collection->object_bases.first; link; link = link->next) { + outliner_add_element(soops, &ten->subtree, ((Base *)link->data)->object, NULL, 0, 0); + } + outliner_make_hierarchy(&ten->subtree); + + outliner_add_collections_recursive(soops, &ten->subtree, scene, &collection->layer_collections, ten); + } +} + +static void outliner_add_collections(SpaceOops *soops, SceneLayer *layer, Scene *scene) +{ + outliner_add_collections_recursive(soops, &soops->tree, scene, &layer->layer_collections, NULL); +} + /* ======================================================= */ /* Generic Tree Building helpers - order these are called is top to bottom */ @@ -1483,18 +1523,15 @@ static void outliner_sort(ListBase *lb) { TreeElement *te; TreeStoreElem *tselem; - int totelem = 0; te = lb->last; if (te == NULL) return; tselem = TREESTORE(te); - + /* sorting rules; only object lists, ID lists, or deformgroups */ - if ( ELEM(tselem->type, TSE_DEFGROUP, TSE_ID_BASE) || (tselem->type == 0 && te->idcode == ID_OB)) { - - /* count first */ - for (te = lb->first; te; te = te->next) totelem++; - + if (ELEM(tselem->type, TSE_DEFGROUP, TSE_ID_BASE) || (tselem->type == 0 && te->idcode == ID_OB)) { + int totelem = BLI_listbase_count(lb); + if (totelem > 1) { tTreeSort *tear = MEM_mallocN(totelem * sizeof(tTreeSort), "tree sort array"); tTreeSort *tp = tear; @@ -1619,9 +1656,8 @@ static int outliner_filter_tree(SpaceOops *soops, ListBase *lb) /* Main entry point for building the tree data-structure that the outliner represents */ // TODO: split each mode into its own function? -void outliner_build_tree(Main *mainvar, Scene *scene, SpaceOops *soops) +void outliner_build_tree(Main *mainvar, Scene *scene, SceneLayer *sl, SpaceOops *soops) { - Base *base; TreeElement *te = NULL, *ten; TreeStoreElem *tselem; int show_opened = !soops->treestore || !BLI_mempool_count(soops->treestore); /* on first view, we open scenes */ @@ -1702,31 +1738,40 @@ void outliner_build_tree(Main *mainvar, Scene *scene, SpaceOops *soops) tselem = TREESTORE(te); if (sce == scene && show_opened) tselem->flag &= ~TSE_CLOSED; - - for (base = sce->base.first; base; base = base->next) { - ten = outliner_add_element(soops, &te->subtree, base->object, te, 0, 0); - ten->directdata = base; + + FOREACH_SCENE_OBJECT(scene, ob) + { + ten = outliner_add_element(soops, &te->subtree, ob, te, 0, 0); } + FOREACH_SCENE_OBJECT_END + outliner_make_hierarchy(&te->subtree); + /* clear id.newid, to prevent objects be inserted in wrong scenes (parent in other scene) */ - for (base = sce->base.first; base; base = base->next) base->object->id.newid = NULL; + FOREACH_SCENE_OBJECT(scene, ob) + { + ob->id.newid = NULL; + } + FOREACH_SCENE_OBJECT_END } } else if (soops->outlinevis == SO_CUR_SCENE) { outliner_add_scene_contents(soops, &soops->tree, scene, NULL); - - for (base = scene->base.first; base; base = base->next) { - ten = outliner_add_element(soops, &soops->tree, base->object, NULL, 0, 0); - ten->directdata = base; + + FOREACH_SCENE_OBJECT(scene, ob) + { + ten = outliner_add_element(soops, &soops->tree, ob, NULL, 0, 0); } + FOREACH_SCENE_OBJECT_END outliner_make_hierarchy(&soops->tree); } else if (soops->outlinevis == SO_VISIBLE) { - for (base = scene->base.first; base; base = base->next) { - if (base->lay & scene->lay) - outliner_add_element(soops, &soops->tree, base->object, NULL, 0, 0); + FOREACH_VISIBLE_OBJECT(sl, ob) + { + outliner_add_element(soops, &soops->tree, ob, NULL, 0, 0); } + FOREACH_VISIBLE_OBJECT_END outliner_make_hierarchy(&soops->tree); } else if (soops->outlinevis == SO_GROUPS) { @@ -1739,7 +1784,6 @@ void outliner_build_tree(Main *mainvar, Scene *scene, SpaceOops *soops) for (go = group->gobject.first; go; go = go->next) { ten = outliner_add_element(soops, &te->subtree, go->ob, te, 0, 0); - ten->directdata = NULL; /* eh, why? */ } outliner_make_hierarchy(&te->subtree); /* clear id.newid, to prevent objects be inserted in wrong scenes (parent in other scene) */ @@ -1748,26 +1792,24 @@ void outliner_build_tree(Main *mainvar, Scene *scene, SpaceOops *soops) } } else if (soops->outlinevis == SO_SAME_TYPE) { - Object *ob = OBACT; - if (ob) { - for (base = scene->base.first; base; base = base->next) { - if (base->object->type == ob->type) { - ten = outliner_add_element(soops, &soops->tree, base->object, NULL, 0, 0); - ten->directdata = base; + Object *ob_active = OBACT_NEW; + if (ob_active) { + FOREACH_SCENE_OBJECT(scene, ob) + { + if (ob->type == ob_active->type) { + ten = outliner_add_element(soops, &soops->tree, ob, NULL, 0, 0); } } + FOREACH_SCENE_OBJECT_END outliner_make_hierarchy(&soops->tree); } } else if (soops->outlinevis == SO_SELECTED) { - for (base = scene->base.first; base; base = base->next) { - if (base->lay & scene->lay) { - if (base->flag & SELECT) { - ten = outliner_add_element(soops, &soops->tree, base->object, NULL, 0, 0); - ten->directdata = base; - } - } + FOREACH_SELECTED_OBJECT(sl, ob) + { + ten = outliner_add_element(soops, &soops->tree, ob, NULL, 0, 0); } + FOREACH_SELECTED_OBJECT_END outliner_make_hierarchy(&soops->tree); } else if (soops->outlinevis == SO_SEQUENCE) { @@ -1821,14 +1863,14 @@ void outliner_build_tree(Main *mainvar, Scene *scene, SpaceOops *soops) else if (soops->outlinevis == SO_ID_ORPHANS) { outliner_add_orphaned_datablocks(mainvar, soops); } + else if (soops->outlinevis == SO_COLLECTIONS) { + outliner_add_collections(soops, BKE_scene_layer_context_active(scene), scene); + } else { - ten = outliner_add_element(soops, &soops->tree, OBACT, NULL, 0, 0); - if (ten) ten->directdata = BASACT; + ten = outliner_add_element(soops, &soops->tree, OBACT_NEW, NULL, 0, 0); } - if ((soops->flag & SO_SKIP_SORT_ALPHA) == 0) { - outliner_sort(&soops->tree); - } + outliner_sort(&soops->tree); outliner_filter_tree(soops, &soops->tree); BKE_main_id_clear_newpoins(mainvar); diff --git a/source/blender/editors/space_sequencer/sequencer_draw.c b/source/blender/editors/space_sequencer/sequencer_draw.c index e1768e4aedc..d13d2be068b 100644 --- a/source/blender/editors/space_sequencer/sequencer_draw.c +++ b/source/blender/editors/space_sequencer/sequencer_draw.c @@ -59,6 +59,7 @@ #include "BIF_glutil.h" #include "GPU_basic_shader.h" +#include "GPU_immediate.h" #include "ED_anim_api.h" #include "ED_gpencil.h" @@ -190,25 +191,35 @@ void color3ubv_from_seq(Scene *curscene, Sequence *seq, unsigned char col[3]) } } -static void drawseqwave(const bContext *C, SpaceSeq *sseq, Scene *scene, Sequence *seq, float x1, float y1, float x2, float y2, float stepsize) +static void drawseqwave(View2D *v2d, const bContext *C, SpaceSeq *sseq, Scene *scene, Sequence *seq, + float x1, float y1, float x2, float y2, float stepsize, unsigned int pos) { /* * x1 is the starting x value to draw the wave, * x2 the end x value, same for y1 and y2 * stepsize is width of a pixel. */ + + /* offset x1 and x2 values, to match view min/max, if strip is out of bounds */ + int x1_offset = max_ff(v2d->cur.xmin, x1); + int x2_offset = min_ff(v2d->cur.xmax + 1.0f, x2); + if (seq->sound && ((sseq->flag & SEQ_ALL_WAVEFORMS) || (seq->flag & SEQ_AUDIO_DRAW_WAVEFORM))) { - int i, j, pos; - int length = floor((x2 - x1) / stepsize) + 1; - float ymid = (y1 + y2) / 2; - float yscale = (y2 - y1) / 2; + int i, j, p; + int length = floor((x2_offset - x1_offset) / stepsize) + 1; + float ymid = (y1 + y2) / 2.0f; + float yscale = (y2 - y1) / 2.0f; float samplestep; float startsample, endsample; float value1, value2; bSound *sound = seq->sound; SoundWaveform *waveform; - + + if (length < 2) { + return; + } + if (!sound->spinlock) { sound->spinlock = MEM_mallocN(sizeof(SpinLock), "sound_spinlock"); BLI_spin_init(sound->spinlock); @@ -241,21 +252,27 @@ static void drawseqwave(const bContext *C, SpaceSeq *sseq, Scene *scene, Sequenc endsample = ceil((seq->startofs + seq->anim_startofs + seq->enddisp - seq->startdisp) / FPS * SOUND_WAVE_SAMPLES_PER_SECOND); samplestep = (endsample - startsample) * stepsize / (x2 - x1); - if (length > floor((waveform->length - startsample) / samplestep)) - length = floor((waveform->length - startsample) / samplestep); + length = min_ii(floor((waveform->length - startsample) / samplestep), length); + + if (length < 2) { + return; + } + + immUniformColor4f(1.0f, 1.0f, 1.0f, 0.5); - glColor4f(1.0f, 1.0f, 1.0f, 0.5); glEnable(GL_BLEND); - glBegin(GL_TRIANGLE_STRIP); + + immBegin(GL_TRIANGLE_STRIP, length * 2); + for (i = 0; i < length; i++) { - float sampleoffset = startsample + i * samplestep; - pos = sampleoffset; + float sampleoffset = startsample + ((x1_offset - x1) / stepsize + i) * samplestep; + p = sampleoffset; - value1 = waveform->data[pos * 3]; - value2 = waveform->data[pos * 3 + 1]; + value1 = waveform->data[p * 3]; + value2 = waveform->data[p * 3 + 1]; if (samplestep > 1.0f) { - for (j = pos + 1; (j < waveform->length) && (j < pos + samplestep); j++) { + for (j = p + 1; (j < waveform->length) && (j < p + samplestep); j++) { if (value1 > waveform->data[j * 3]) value1 = waveform->data[j * 3]; @@ -265,34 +282,20 @@ static void drawseqwave(const bContext *C, SpaceSeq *sseq, Scene *scene, Sequenc } else { /* use simple linear interpolation */ - float f = sampleoffset - pos; - value1 = (1.0f - f) * value1 + f * waveform->data[pos * 3 + 3]; - value2 = (1.0f - f) * value2 + f * waveform->data[pos * 3 + 4]; + float f = sampleoffset - p; + value1 = (1.0f - f) * value1 + f * waveform->data[p * 3 + 3]; + value2 = (1.0f - f) * value2 + f * waveform->data[p * 3 + 4]; } - glVertex2f(x1 + i * stepsize, ymid + value1 * yscale); - glVertex2f(x1 + i * stepsize, ymid + value2 * yscale); + immVertex2f(pos, x1_offset + i * stepsize, ymid + value1 * yscale); + immVertex2f(pos, x1_offset + i * stepsize, ymid + value2 * yscale); } - glEnd(); - glDisable(GL_BLEND); - } -} -static void drawmeta_stipple(int value) -{ - if (value) { - GPU_basic_shader_bind(GPU_SHADER_STIPPLE | GPU_SHADER_USE_COLOR); - GPU_basic_shader_stipple(GPU_SHADER_STIPPLE_HALFTONE); - - glEnable(GL_LINE_STIPPLE); - glLineStipple(1, 0x8888); - } - else { - GPU_basic_shader_bind(GPU_SHADER_USE_COLOR); - glDisable(GL_LINE_STIPPLE); + immEnd(); + + glDisable(GL_BLEND); } } - static void drawmeta_contents(Scene *scene, Sequence *seqm, float x1, float y1, float x2, float y2) { /* note: this used to use SEQ_BEGIN/SEQ_END, but it messes up the @@ -325,9 +328,6 @@ static void drawmeta_contents(Scene *scene, Sequence *seqm, float x1, float y1, glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - if (seqm->flag & SEQ_MUTE) - drawmeta_stipple(1); - for (seq = seqbase->first; seq; seq = seq->next) { chan_min = min_ii(chan_min, seq->machine); chan_max = max_ii(chan_max, seq->machine); @@ -338,6 +338,10 @@ static void drawmeta_contents(Scene *scene, Sequence *seqm, float x1, float y1, col[3] = 196; /* alpha, used for all meta children */ + unsigned int pos = add_attrib(immVertexFormat(), "pos", GL_FLOAT, 2, KEEP_FLOAT); + + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + for (seq = seqbase->first; seq; seq = seq->next) { const int startdisp = seq->startdisp + offset; const int enddisp = seq->enddisp + offset; @@ -348,12 +352,16 @@ static void drawmeta_contents(Scene *scene, Sequence *seqm, float x1, float y1, float x2_chan = enddisp; float y1_chan, y2_chan; - if ((seqm->flag & SEQ_MUTE) == 0 && (seq->flag & SEQ_MUTE)) - drawmeta_stipple(1); - color3ubv_from_seq(scene, seq, col); - glColor4ubv(col); + if ((seqm->flag & SEQ_MUTE) || (seq->flag & SEQ_MUTE)) { + col[3] = 64; + } + else { + col[3] = 196; + } + + immUniformColor4ubv(col); /* clamp within parent sequence strip bounds */ if (x1_chan < x1) x1_chan = x1; @@ -362,20 +370,12 @@ static void drawmeta_contents(Scene *scene, Sequence *seqm, float x1, float y1, y1_chan = y1 + y_chan + (draw_height * SEQ_STRIP_OFSBOTTOM); y2_chan = y1 + y_chan + (draw_height * SEQ_STRIP_OFSTOP); - glRectf(x1_chan, y1_chan, x2_chan, y2_chan); - - UI_GetColorPtrShade3ubv(col, col, -30); - glColor4ubv(col); - fdrawbox(x1_chan, y1_chan, x2_chan, y2_chan); - - if ((seqm->flag & SEQ_MUTE) == 0 && (seq->flag & SEQ_MUTE)) - drawmeta_stipple(0); + immRectf(pos, x1_chan, y1_chan, x2_chan, y2_chan); } } - if (seqm->flag & SEQ_MUTE) - drawmeta_stipple(0); - + immUnbindProgram(); + glDisable(GL_BLEND); } @@ -391,7 +391,7 @@ static float draw_seq_handle_size_get_clamped(Sequence *seq, const float pixelx) } /* draw a handle, for each end of a sequence strip */ -static void draw_seq_handle(View2D *v2d, Sequence *seq, const float handsize_clamped, const short direction) +static void draw_seq_handle(View2D *v2d, Sequence *seq, const float handsize_clamped, const short direction, unsigned int pos) { float v1[2], v2[2], v3[2], rx1 = 0, rx2 = 0; //for triangles and rect float x1, x2, y1, y2; @@ -433,21 +433,31 @@ static void draw_seq_handle(View2D *v2d, Sequence *seq, const float handsize_cla glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - if (seq->flag & whichsel) glColor4ub(0, 0, 0, 80); - else if (seq->flag & SELECT) glColor4ub(255, 255, 255, 30); - else glColor4ub(0, 0, 0, 22); - - glRectf(rx1, y1, rx2, y2); - - if (seq->flag & whichsel) glColor4ub(255, 255, 255, 200); - else glColor4ub(0, 0, 0, 50); + if (seq->flag & whichsel) { + immUniformColor4ub(0, 0, 0, 80); + } + else if (seq->flag & SELECT) { + immUniformColor4ub(255, 255, 255, 30); + } + else { + immUniformColor4ub(0, 0, 0, 22); + } - glEnable(GL_POLYGON_SMOOTH); - glBegin(GL_TRIANGLES); - glVertex2fv(v1); glVertex2fv(v2); glVertex2fv(v3); - glEnd(); + immRectf(pos, rx1, y1, rx2, y2); - glDisable(GL_POLYGON_SMOOTH); + if (seq->flag & whichsel) { + immUniformColor4ub(255, 255, 255, 200); + } + else { + immUniformColor4ub(0, 0, 0, 50); + } + + immBegin(GL_TRIANGLES, 3); + immVertex2fv(pos, v1); + immVertex2fv(pos, v2); + immVertex2fv(pos, v3); + immEnd(); + glDisable(GL_BLEND); } @@ -585,67 +595,10 @@ static void draw_seq_text(View2D *v2d, SpaceSeq *sseq, Sequence *seq, float x1, UI_view2d_text_cache_add_rectf(v2d, &rect, str, str_len, col); } -/* draws a shaded strip, made from gradient + flat color + gradient */ -void draw_shadedstrip(Sequence *seq, unsigned char col[3], float x1, float y1, float x2, float y2) +static void draw_sequence_extensions(Scene *scene, ARegion *ar, Sequence *seq, unsigned int pos) { - float ymid1, ymid2; - - if (seq->flag & SEQ_MUTE) { - GPU_basic_shader_bind(GPU_SHADER_STIPPLE | GPU_SHADER_USE_COLOR); - GPU_basic_shader_stipple(GPU_SHADER_STIPPLE_HALFTONE); - } - - ymid1 = (y2 - y1) * 0.25f + y1; - ymid2 = (y2 - y1) * 0.65f + y1; - - glBegin(GL_QUADS); - - if (seq->flag & SEQ_INVALID_EFFECT) { col[0] = 255; col[1] = 0; col[2] = 255; } - else if (seq->flag & SELECT) UI_GetColorPtrShade3ubv(col, col, -50); - /* else UI_GetColorPtrShade3ubv(col, col, 0); */ /* DO NOTHING */ - - glColor3ubv(col); - - glVertex2f(x1, y1); - glVertex2f(x2, y1); - - if (seq->flag & SEQ_INVALID_EFFECT) { col[0] = 255; col[1] = 0; col[2] = 255; } - else if (seq->flag & SELECT) UI_GetColorPtrBlendShade3ubv(col, col, col, 0.0, 5); - else UI_GetColorPtrShade3ubv(col, col, -5); - - glColor3ubv((GLubyte *)col); - - glVertex2f(x2, ymid1); - glVertex2f(x1, ymid1); - - glEnd(); - - glRectf(x1, ymid1, x2, ymid2); - - glBegin(GL_QUADS); - - glVertex2f(x1, ymid2); - glVertex2f(x2, ymid2); - - if (seq->flag & SELECT) UI_GetColorPtrShade3ubv(col, col, -15); - else UI_GetColorPtrShade3ubv(col, col, 25); - - glColor3ubv((GLubyte *)col); - - glVertex2f(x2, y2); - glVertex2f(x1, y2); - - glEnd(); - - if (seq->flag & SEQ_MUTE) { - GPU_basic_shader_bind(GPU_SHADER_USE_COLOR); - } -} - -void draw_sequence_extensions(Scene *scene, ARegion *ar, Sequence *seq) -{ - float x1, x2, y1, y2, pixely, a; - unsigned char col[3], blendcol[3]; + float x1, x2, y1, y2, pixely; + unsigned char col[4], blendcol[3]; View2D *v2d = &ar->v2d; x1 = seq->startdisp; @@ -659,90 +612,82 @@ void draw_sequence_extensions(Scene *scene, ARegion *ar, Sequence *seq) if (pixely <= 0) return; /* can happen when the view is split/resized */ blendcol[0] = blendcol[1] = blendcol[2] = 120; - - if (seq->startofs) { + + if (seq->startofs || seq->endofs) { glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); color3ubv_from_seq(scene, seq, col); - + if (seq->flag & SELECT) { - UI_GetColorPtrBlendShade3ubv(col, blendcol, col, 0.3, -40); - glColor4ub(col[0], col[1], col[2], 170); + UI_GetColorPtrShade3ubv(col, col, -50); + } + + if (seq->flag & SEQ_MUTE) { + col[3] = 64; } else { - UI_GetColorPtrBlendShade3ubv(col, blendcol, col, 0.6, 0); - glColor4ub(col[0], col[1], col[2], 110); + if (seq->flag & SELECT) { + col[3] = 170; + } + else { + col[3] = 80; + } } - - glRectf((float)(seq->start), y1 - SEQ_STRIP_OFSBOTTOM, x1, y1); - - if (seq->flag & SELECT) glColor4ub(col[0], col[1], col[2], 255); - else glColor4ub(col[0], col[1], col[2], 160); - - fdrawbox((float)(seq->start), y1 - SEQ_STRIP_OFSBOTTOM, x1, y1); //outline - - glDisable(GL_BLEND); + } + + if (seq->startofs) { + immUniformColor4ubv(col); + immRectf(pos, (float)(seq->start), y1 - SEQ_STRIP_OFSBOTTOM, x1, y1); + + immUniformColor4ub(col[0], col[1], col[2], col[3] + 50); + + imm_draw_line_box(pos, (float)(seq->start), y1 - SEQ_STRIP_OFSBOTTOM, x1, y1); /* outline */ } if (seq->endofs) { + immUniformColor4ubv(col); + immRectf(pos, x2, y2, (float)(seq->start + seq->len), y2 + SEQ_STRIP_OFSBOTTOM); + + immUniformColor4ub(col[0], col[1], col[2], col[3] + 50); + + imm_draw_line_box(pos, x2, y2, (float)(seq->start + seq->len), y2 + SEQ_STRIP_OFSBOTTOM); /* outline */ + } + + if (seq->startofs || seq->endofs) { + glDisable(GL_BLEND); + } + + if (seq->startstill || seq->endstill) { glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - + color3ubv_from_seq(scene, seq, col); - - if (seq->flag & SELECT) { - UI_GetColorPtrBlendShade3ubv(col, blendcol, col, 0.3, -40); - glColor4ub(col[0], col[1], col[2], 170); + UI_GetColorPtrBlendShade3ubv(col, blendcol, col, 0.5f, 60); + + if (seq->flag & SEQ_MUTE) { + col[3] = 96; } else { - UI_GetColorPtrBlendShade3ubv(col, blendcol, col, 0.6, 0); - glColor4ub(col[0], col[1], col[2], 110); + if (seq->flag & SELECT) { + col[3] = 255; + } + else { + col[3] = 170; + } } - - glRectf(x2, y2, (float)(seq->start + seq->len), y2 + SEQ_STRIP_OFSBOTTOM); - - if (seq->flag & SELECT) glColor4ub(col[0], col[1], col[2], 255); - else glColor4ub(col[0], col[1], col[2], 160); - - fdrawbox(x2, y2, (float)(seq->start + seq->len), y2 + SEQ_STRIP_OFSBOTTOM); //outline - - glDisable(GL_BLEND); + + immUniformColor4ubv(col); } + if (seq->startstill) { - color3ubv_from_seq(scene, seq, col); - UI_GetColorPtrBlendShade3ubv(col, blendcol, col, 0.75, 40); - glColor3ubv((GLubyte *)col); - - draw_shadedstrip(seq, col, x1, y1, (float)(seq->start), y2); - - /* feint pinstripes, helps see exactly which is extended and which isn't, - * especially when the extension is very small */ - if (seq->flag & SELECT) UI_GetColorPtrBlendShade3ubv(col, col, col, 0.0, 24); - else UI_GetColorPtrShade3ubv(col, col, -16); - - glColor3ubv((GLubyte *)col); - - for (a = y1; a < y2; a += pixely * 2.0f) { - fdrawline(x1, a, (float)(seq->start), a); - } + immRectf(pos, x1, y1, (float)(seq->start), y2); } if (seq->endstill) { - color3ubv_from_seq(scene, seq, col); - UI_GetColorPtrBlendShade3ubv(col, blendcol, col, 0.75, 40); - glColor3ubv((GLubyte *)col); - - draw_shadedstrip(seq, col, (float)(seq->start + seq->len), y1, x2, y2); - - /* feint pinstripes, helps see exactly which is extended and which isn't, - * especially when the extension is very small */ - if (seq->flag & SELECT) UI_GetColorPtrShade3ubv(col, col, 24); - else UI_GetColorPtrShade3ubv(col, col, -16); - - glColor3ubv((GLubyte *)col); - - for (a = y1; a < y2; a += pixely * 2.0f) { - fdrawline((float)(seq->start + seq->len), a, x2, a); - } + immRectf(pos, (float)(seq->start + seq->len), y1, x2, y2); + } + + if (seq->startstill || seq->endstill) { + glDisable(GL_BLEND); } } @@ -756,7 +701,7 @@ static void draw_seq_strip(const bContext *C, SpaceSeq *sseq, Scene *scene, AReg { View2D *v2d = &ar->v2d; float x1, x2, y1, y2; - unsigned char col[3], background_col[3], is_single_image; + unsigned char col[4], background_col[4], is_single_image; const float handsize_clamped = draw_seq_handle_size_get_clamped(seq, pixelx); /* we need to know if this is a single image/color or not for drawing */ @@ -768,72 +713,105 @@ static void draw_seq_strip(const bContext *C, SpaceSeq *sseq, Scene *scene, AReg x2 = (seq->endstill) ? (seq->start + seq->len) : seq->enddisp; y2 = seq->machine + SEQ_STRIP_OFSTOP; + unsigned int pos = add_attrib(immVertexFormat(), "pos", GL_FLOAT, 2, KEEP_FLOAT); + + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); /* get the correct color per strip type*/ //color3ubv_from_seq(scene, seq, col); color3ubv_from_seq(scene, seq, background_col); - + + if (seq->flag & SEQ_MUTE) { + background_col[3] = 128; + + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + } + else { + background_col[3] = 255; + } + + if (seq->flag & SELECT) { + UI_GetColorPtrShade3ubv(background_col, background_col, -50); + } + + immUniformColor4ubv(background_col); + /* draw the main strip body */ if (is_single_image) { /* single image */ - draw_shadedstrip(seq, background_col, - BKE_sequence_tx_get_final_left(seq, false), y1, - BKE_sequence_tx_get_final_right(seq, false), y2); + immRectf(pos, BKE_sequence_tx_get_final_left(seq, false), y1, + BKE_sequence_tx_get_final_right(seq, false), y2); } else { /* normal operation */ - draw_shadedstrip(seq, background_col, x1, y1, x2, y2); + immRectf(pos, x1, y1, x2, y2); + } + + if (seq->flag & SEQ_MUTE) { + glDisable(GL_BLEND); } if (!is_single_image) { if ((sseq->draw_flag & SEQ_DRAW_OFFSET_EXT) || (seq == special_seq_update)) { - draw_sequence_extensions(scene, ar, seq); + draw_sequence_extensions(scene, ar, seq, pos); } } - draw_seq_handle(v2d, seq, handsize_clamped, SEQ_LEFTHANDLE); - draw_seq_handle(v2d, seq, handsize_clamped, SEQ_RIGHTHANDLE); - - /* draw the strip outline */ + draw_seq_handle(v2d, seq, handsize_clamped, SEQ_LEFTHANDLE, pos); + draw_seq_handle(v2d, seq, handsize_clamped, SEQ_RIGHTHANDLE, pos); + x1 = seq->startdisp; x2 = seq->enddisp; /* draw sound wave */ if (seq->type == SEQ_TYPE_SOUND_RAM) { if (!(sseq->flag & SEQ_NO_WAVEFORMS)) { - drawseqwave(C, sseq, scene, seq, x1, y1, x2, y2, BLI_rctf_size_x(&ar->v2d.cur) / ar->winx); + drawseqwave(v2d, C, sseq, scene, seq, x1, y1, x2, y2, BLI_rctf_size_x(&ar->v2d.cur) / ar->winx, pos); } } + immUnbindProgram(); + /* draw lock */ if (seq->flag & SEQ_LOCK) { - GPU_basic_shader_bind(GPU_SHADER_STIPPLE | GPU_SHADER_USE_COLOR); glEnable(GL_BLEND); - /* light stripes */ - glColor4ub(255, 255, 255, 32); - GPU_basic_shader_stipple(GPU_SHADER_STIPPLE_DIAG_STRIPES); - glRectf(x1, y1, x2, y2); + pos = add_attrib(immVertexFormat(), "pos", GL_FLOAT, 2, KEEP_FLOAT); + immBindBuiltinProgram(GPU_SHADER_2D_DIAG_STRIPES); - /* dark stripes */ - glColor4ub(0, 0, 0, 32); - GPU_basic_shader_stipple(GPU_SHADER_STIPPLE_DIAG_STRIPES_SWAP); - glRectf(x1, y1, x2, y2); + immUniform4f("color1", 1.0f, 1.0f, 1.0f, 0.125f); + immUniform4f("color2", 0.0f, 0.0f, 0.0f, 0.125f); + immUniform1i("size1", 8); + immUniform1i("size2", 8); + + immRectf(pos, x1, y1, x2, y2); + + immUnbindProgram(); - GPU_basic_shader_bind(GPU_SHADER_USE_COLOR); glDisable(GL_BLEND); } if (!BKE_sequence_is_valid_check(seq)) { - GPU_basic_shader_bind(GPU_SHADER_STIPPLE | GPU_SHADER_USE_COLOR); + glEnable(GL_BLEND); + + pos = add_attrib(immVertexFormat(), "pos", GL_FLOAT, 2, KEEP_FLOAT); + immBindBuiltinProgram(GPU_SHADER_2D_DIAG_STRIPES); - /* panic! */ - glColor4ub(255, 0, 0, 255); - GPU_basic_shader_stipple(GPU_SHADER_STIPPLE_DIAG_STRIPES); - glRectf(x1, y1, x2, y2); + immUniform4f("color1", 1.0f, 0.0f, 0.0f, 1.0f); + immUniform4f("color2", 0.0f, 0.0f, 0.0f, 0.0f); + immUniform1i("size1", 8); + immUniform1i("size2", 8); - GPU_basic_shader_bind(GPU_SHADER_USE_COLOR); + immRectf(pos, x1, y1, x2, y2); + + immUnbindProgram(); + + glDisable(GL_BLEND); } color3ubv_from_seq(scene, seq, col); + + /* draw the strip outline */ + color3ubv_from_seq(scene, seq, col); if ((G.moving & G_TRANSFORM_SEQ) && (seq->flag & SELECT)) { if (seq->flag & SEQ_OVERLAP) { col[0] = 255; col[1] = col[2] = 40; @@ -850,19 +828,30 @@ static void draw_seq_strip(const bContext *C, SpaceSeq *sseq, Scene *scene, AReg drawmeta_contents(scene, seq, x1, y1, x2, y2); } + pos = add_attrib(immVertexFormat(), "pos", GL_FLOAT, 2, KEEP_FLOAT); + + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + if (seq->flag & SEQ_MUTE) { - glEnable(GL_LINE_STIPPLE); - glLineStipple(1, 0x8888); + col[3] = 96; + + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + + immUniformColor4ubv(col); } - - glColor3ubv((GLubyte *)col); - - UI_draw_roundbox_shade_x(GL_LINE_LOOP, x1, y1, x2, y2, 0.0, 0.1, 0.0); - + else { + immUniformColor3ubv(col); + } + + imm_draw_line_box(pos, x1, y1, x2, y2); /* outline */ + if (seq->flag & SEQ_MUTE) { glDisable(GL_LINE_STIPPLE); } - + + immUnbindProgram(); + /* calculate if seq is long enough to print a name */ x1 = seq->startdisp + handsize_clamped; x2 = seq->enddisp - handsize_clamped; @@ -1048,30 +1037,30 @@ static void sequencer_draw_borders(const SpaceSeq *sseq, const View2D *v2d, cons /* border */ setlinestyle(3); - UI_ThemeColorBlendShade(TH_WIRE, TH_BACK, 1.0, 0); + unsigned int pos = add_attrib(immVertexFormat(), "pos", GL_FLOAT, 2, KEEP_FLOAT); - glBegin(GL_LINE_LOOP); - glVertex2f(x1 - 0.5f, y1 - 0.5f); - glVertex2f(x1 - 0.5f, y2 + 0.5f); - glVertex2f(x2 + 0.5f, y2 + 0.5f); - glVertex2f(x2 + 0.5f, y1 - 0.5f); - glEnd(); + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + immUniformThemeColor(TH_BACK); + + imm_draw_line_box(pos, x1 - 0.5f, y1 - 0.5f, x2 + 0.5f, y2 + 0.5f); /* safety border */ if (sseq->flag & SEQ_SHOW_SAFE_MARGINS) { UI_draw_safe_areas( - x1, x2, y1, y2, + pos, x1, x2, y1, y2, scene->safe_areas.title, scene->safe_areas.action); if (sseq->flag & SEQ_SHOW_SAFE_CENTER) { UI_draw_safe_areas( - x1, x2, y1, y2, + pos, x1, x2, y1, y2, scene->safe_areas.title_center, scene->safe_areas.action_center); } } + immUnbindProgram(); + setlinestyle(0); } @@ -1087,11 +1076,7 @@ static void sequencer_draw_background( /* only draw alpha for main buffer */ if (sseq->mainb == SEQ_DRAW_IMG_IMBUF) { if ((sseq->flag & SEQ_USE_ALPHA) && !draw_overlay) { - glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - - fdrawcheckerboard(v2d->tot.xmin, v2d->tot.ymin, v2d->tot.xmax, v2d->tot.ymax); - glColor4f(1.0, 1.0, 1.0, 1.0); + imm_draw_checker_box(v2d->tot.xmin, v2d->tot.ymin, v2d->tot.xmax, v2d->tot.ymax); } } } @@ -1135,9 +1120,6 @@ void draw_image_seq(const bContext *C, Scene *scene, ARegion *ar, SpaceSeq *sseq glClear(GL_COLOR_BUFFER_BIT); } - /* without this colors can flicker from previous opengl state */ - glColor4ub(255, 255, 255, 255); - /* only initialize the preview if a render is in progress */ if (G.is_rendering) return; @@ -1152,15 +1134,16 @@ void draw_image_seq(const bContext *C, Scene *scene, ARegion *ar, SpaceSeq *sseq if ((ibuf == NULL) || (ibuf->rect == NULL && ibuf->rect_float == NULL)) { - /* gpencil can also be drawn without a valid imbuf */ - if ((draw_gpencil && is_imbuf) && !draw_overlay) { - sequencer_display_size(scene, sseq, viewrect); + sequencer_display_size(scene, sseq, viewrect); - sequencer_draw_background(sseq, v2d, viewrect, false); - sequencer_draw_borders(sseq, v2d, scene); + sequencer_draw_background(sseq, v2d, viewrect, false); + sequencer_draw_borders(sseq, v2d, scene); + /* gpencil can also be drawn without a valid imbuf */ + if ((draw_gpencil && is_imbuf) && !draw_overlay) { sequencer_draw_gpencil(C); } + return; } @@ -1229,6 +1212,11 @@ void draw_image_seq(const bContext *C, Scene *scene, ARegion *ar, SpaceSeq *sseq sequencer_draw_background(sseq, v2d, viewrect, draw_overlay); } + if (sseq->mainb == SEQ_DRAW_IMG_IMBUF && sseq->flag & SEQ_USE_ALPHA) { + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + } + if (scope) { IMB_freeImBuf(ibuf); ibuf = scope; @@ -1301,9 +1289,15 @@ void draw_image_seq(const bContext *C, Scene *scene, ARegion *ar, SpaceSeq *sseq } } - glColor4f(1.0, 1.0, 1.0, 1.0); + if (draw_backdrop) { + glMatrixMode(GL_PROJECTION); + glPushMatrix(); + glLoadIdentity(); + glMatrixMode(GL_MODELVIEW); + glPushMatrix(); + glLoadIdentity(); + } - GPU_basic_shader_bind(GPU_SHADER_TEXTURE_2D | GPU_SHADER_USE_COLOR); glGenTextures(1, (GLuint *)&texid); glBindTexture(GL_TEXTURE_2D, texid); @@ -1316,15 +1310,15 @@ void draw_image_seq(const bContext *C, Scene *scene, ARegion *ar, SpaceSeq *sseq else glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, ibuf->x, ibuf->y, 0, format, type, display_buffer); - if (draw_backdrop) { - glMatrixMode(GL_PROJECTION); - glPushMatrix(); - glLoadIdentity(); - glMatrixMode(GL_MODELVIEW); - glPushMatrix(); - glLoadIdentity(); - } - glBegin(GL_QUADS); + VertexFormat *imm_format = immVertexFormat(); + unsigned int pos = add_attrib(imm_format, "pos", GL_FLOAT, 2, KEEP_FLOAT); + unsigned int texCoord = add_attrib(imm_format, "texCoord", GL_FLOAT, 2, KEEP_FLOAT); + + immBindBuiltinProgram(GPU_SHADER_2D_IMAGE_COLOR); + immUniform4f("color", 1.0f, 1.0f, 1.0f, 1.0f); + immUniform1i("image", GL_TEXTURE0); + + immBegin(GL_QUADS, 4); if (draw_overlay) { if (sseq->overlay_type == SEQ_DRAW_OVERLAY_RECT) { @@ -1334,16 +1328,30 @@ void draw_image_seq(const bContext *C, Scene *scene, ARegion *ar, SpaceSeq *sseq tot_clip.xmax = v2d->tot.xmin + (fabsf(BLI_rctf_size_x(&v2d->tot)) * scene->ed->over_border.xmax); tot_clip.ymax = v2d->tot.ymin + (fabsf(BLI_rctf_size_y(&v2d->tot)) * scene->ed->over_border.ymax); - glTexCoord2f(scene->ed->over_border.xmin, scene->ed->over_border.ymin); glVertex2f(tot_clip.xmin, tot_clip.ymin); - glTexCoord2f(scene->ed->over_border.xmin, scene->ed->over_border.ymax); glVertex2f(tot_clip.xmin, tot_clip.ymax); - glTexCoord2f(scene->ed->over_border.xmax, scene->ed->over_border.ymax); glVertex2f(tot_clip.xmax, tot_clip.ymax); - glTexCoord2f(scene->ed->over_border.xmax, scene->ed->over_border.ymin); glVertex2f(tot_clip.xmax, tot_clip.ymin); + immAttrib2f(texCoord, scene->ed->over_border.xmin, scene->ed->over_border.ymin); + immVertex2f(pos, tot_clip.xmin, tot_clip.ymin); + + immAttrib2f(texCoord, scene->ed->over_border.xmin, scene->ed->over_border.ymax); + immVertex2f(pos, tot_clip.xmin, tot_clip.ymax); + + immAttrib2f(texCoord, scene->ed->over_border.xmax, scene->ed->over_border.ymax); + immVertex2f(pos, tot_clip.xmax, tot_clip.ymax); + + immAttrib2f(texCoord, scene->ed->over_border.xmax, scene->ed->over_border.ymin); + immVertex2f(pos, tot_clip.xmax, tot_clip.ymin); } else if (sseq->overlay_type == SEQ_DRAW_OVERLAY_REFERENCE) { - glTexCoord2f(0.0f, 0.0f); glVertex2f(v2d->tot.xmin, v2d->tot.ymin); - glTexCoord2f(0.0f, 1.0f); glVertex2f(v2d->tot.xmin, v2d->tot.ymax); - glTexCoord2f(1.0f, 1.0f); glVertex2f(v2d->tot.xmax, v2d->tot.ymax); - glTexCoord2f(1.0f, 0.0f); glVertex2f(v2d->tot.xmax, v2d->tot.ymin); + immAttrib2f(texCoord, 0.0f, 0.0f); + immVertex2f(pos, v2d->tot.xmin, v2d->tot.ymin); + + immAttrib2f(texCoord, 0.0f, 1.0f); + immVertex2f(pos, v2d->tot.xmin, v2d->tot.ymax); + + immAttrib2f(texCoord, 1.0f, 1.0f); + immVertex2f(pos, v2d->tot.xmax, v2d->tot.ymax); + + immAttrib2f(texCoord, 1.0f, 0.0f); + immVertex2f(pos, v2d->tot.xmax, v2d->tot.ymin); } } else if (draw_backdrop) { @@ -1362,25 +1370,44 @@ void draw_image_seq(const bContext *C, Scene *scene, ARegion *ar, SpaceSeq *sseq imagey = aspect / image_aspect; } - glTexCoord2f(0.0f, 0.0f); glVertex2f(-imagex, -imagey); - glTexCoord2f(0.0f, 1.0f); glVertex2f(-imagex, imagey); - glTexCoord2f(1.0f, 1.0f); glVertex2f(imagex, imagey); - glTexCoord2f(1.0f, 0.0f); glVertex2f(imagex, -imagey); + immAttrib2f(texCoord, 0.0f, 0.0f); + immVertex2f(pos, -imagex, -imagey); + + immAttrib2f(texCoord, 0.0f, 1.0f); + immVertex2f(pos, -imagex, imagey); + + immAttrib2f(texCoord, 1.0f, 1.0f); + immVertex2f(pos, imagex, imagey); + + immAttrib2f(texCoord, 1.0f, 0.0f); + immVertex2f(pos, imagex, -imagey); } else { draw_metadata = ((sseq->flag & SEQ_SHOW_METADATA) != 0); - glTexCoord2f(0.0f, 0.0f); glVertex2f(v2d->tot.xmin, v2d->tot.ymin); - glTexCoord2f(0.0f, 1.0f); glVertex2f(v2d->tot.xmin, v2d->tot.ymax); - glTexCoord2f(1.0f, 1.0f); glVertex2f(v2d->tot.xmax, v2d->tot.ymax); - glTexCoord2f(1.0f, 0.0f); glVertex2f(v2d->tot.xmax, v2d->tot.ymin); + immAttrib2f(texCoord, 0.0f, 0.0f); + immVertex2f(pos, v2d->tot.xmin, v2d->tot.ymin); + + immAttrib2f(texCoord, 0.0f, 1.0f); + immVertex2f(pos, v2d->tot.xmin, v2d->tot.ymax); + + immAttrib2f(texCoord, 1.0f, 1.0f); + immVertex2f(pos, v2d->tot.xmax, v2d->tot.ymax); + + immAttrib2f(texCoord, 1.0f, 0.0f); + immVertex2f(pos, v2d->tot.xmax, v2d->tot.ymin); } - glEnd(); + + immEnd(); glBindTexture(GL_TEXTURE_2D, 0); - GPU_basic_shader_bind(GPU_SHADER_USE_COLOR); - if (sseq->mainb == SEQ_DRAW_IMG_IMBUF && sseq->flag & SEQ_USE_ALPHA) + + immUnbindProgram(); + + if (sseq->mainb == SEQ_DRAW_IMG_IMBUF && sseq->flag & SEQ_USE_ALPHA) { glDisable(GL_BLEND); + } + glDeleteTextures(1, &texid); if (glsl_used) @@ -1474,42 +1501,42 @@ void drawprefetchseqspace(Scene *scene, ARegion *UNUSED(ar), SpaceSeq *sseq) static void draw_seq_backdrop(View2D *v2d) { int i; - + + unsigned pos = add_attrib(immVertexFormat(), "pos", GL_FLOAT, 2, KEEP_FLOAT); + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + /* darker gray overlay over the view backdrop */ - UI_ThemeColorShade(TH_BACK, -20); - glRectf(v2d->cur.xmin, -1.0, v2d->cur.xmax, 1.0); + immUniformThemeColorShade(TH_BACK, -20); + immRectf(pos, v2d->cur.xmin, -1.0, v2d->cur.xmax, 1.0); /* Alternating horizontal stripes */ i = max_ii(1, ((int)v2d->cur.ymin) - 1); - glBegin(GL_QUADS); while (i < v2d->cur.ymax) { - if (((int)i) & 1) - UI_ThemeColorShade(TH_BACK, -15); - else - UI_ThemeColorShade(TH_BACK, -25); - - glVertex2f(v2d->cur.xmax, i); - glVertex2f(v2d->cur.xmin, i); - glVertex2f(v2d->cur.xmin, i + 1); - glVertex2f(v2d->cur.xmax, i + 1); + if (i & 1) { + immUniformThemeColorShade(TH_BACK, -15); + } + else { + immUniformThemeColorShade(TH_BACK, -25); + } - i += 1.0; + immRectf(pos, v2d->cur.xmin, i, v2d->cur.xmax, i + 1); + + i++; } - glEnd(); - + /* Darker lines separating the horizontal bands */ i = max_ii(1, ((int)v2d->cur.ymin) - 1); - UI_ThemeColor(TH_GRID); - - glBegin(GL_LINES); - while (i < v2d->cur.ymax) { - glVertex2f(v2d->cur.xmax, i); - glVertex2f(v2d->cur.xmin, i); - - i += 1.0; + int line_ct = (int)v2d->cur.ymax - i + 1; + immUniformThemeColor(TH_GRID); + immBegin(GL_LINES, line_ct * 2); + while (line_ct--) { + immVertex2f(pos, v2d->cur.xmax, i); + immVertex2f(pos, v2d->cur.xmin, i); } - glEnd(); + immEnd(); + + immUnbindProgram(); } /* draw the contents of the sequencer strips view */ @@ -1525,7 +1552,7 @@ static void draw_seq_strips(const bContext *C, Editing *ed, ARegion *ar) /* loop through twice, first unselected, then selected */ for (j = 0; j < 2; j++) { Sequence *seq; - int outline_tint = (j) ? -60 : -150; /* highlighting around strip edges indicating selection */ + int outline_tint = (j) ? 40 : -40; /* highlighting around strip edges indicating selection */ /* loop through strips, checking for those that are visible */ for (seq = ed->seqbasep->first; seq; seq = seq->next) { @@ -1553,8 +1580,15 @@ static void draw_seq_strips(const bContext *C, Editing *ed, ARegion *ar) if (special_seq_update) { const Sequence *seq = special_seq_update; glEnable(GL_BLEND); - glColor4ub(255, 255, 255, 48); - glRectf(seq->startdisp, seq->machine + SEQ_STRIP_OFSBOTTOM, seq->enddisp, seq->machine + SEQ_STRIP_OFSTOP); + + unsigned pos = add_attrib(immVertexFormat(), "pos", GL_FLOAT, 2, KEEP_FLOAT); + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + + immUniformColor4ub(255, 255, 255, 48); + immRectf(pos, seq->startdisp, seq->machine + SEQ_STRIP_OFSBOTTOM, seq->enddisp, seq->machine + SEQ_STRIP_OFSTOP); + + immUnbindProgram(); + glDisable(GL_BLEND); } } @@ -1566,36 +1600,56 @@ static void seq_draw_sfra_efra(Scene *scene, View2D *v2d) const int frame_end = PEFRA + 1; glEnable(GL_BLEND); - + + unsigned pos = add_attrib(immVertexFormat(), "pos", GL_FLOAT, 2, KEEP_FLOAT); + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + /* draw darkened area outside of active timeline * frame range used is preview range or scene range */ - UI_ThemeColorShadeAlpha(TH_BACK, -25, -100); + immUniformThemeColorShadeAlpha(TH_BACK, -25, -100); if (frame_sta < frame_end) { - glRectf(v2d->cur.xmin, v2d->cur.ymin, (float)frame_sta, v2d->cur.ymax); - glRectf((float)frame_end, v2d->cur.ymin, v2d->cur.xmax, v2d->cur.ymax); + immRectf(pos, v2d->cur.xmin, v2d->cur.ymin, (float)frame_sta, v2d->cur.ymax); + immRectf(pos, (float)frame_end, v2d->cur.ymin, v2d->cur.xmax, v2d->cur.ymax); } else { - glRectf(v2d->cur.xmin, v2d->cur.ymin, v2d->cur.xmax, v2d->cur.ymax); + immRectf(pos, v2d->cur.xmin, v2d->cur.ymin, v2d->cur.xmax, v2d->cur.ymax); } - UI_ThemeColorShade(TH_BACK, -60); + immUniformThemeColorShade(TH_BACK, -60); + /* thin lines where the actual frames are */ - fdrawline(frame_sta, v2d->cur.ymin, frame_sta, v2d->cur.ymax); - fdrawline(frame_end, v2d->cur.ymin, frame_end, v2d->cur.ymax); + immBegin(GL_LINES, 4); + + immVertex2f(pos, frame_sta, v2d->cur.ymin); + immVertex2f(pos, frame_sta, v2d->cur.ymax); + + immVertex2f(pos, frame_end, v2d->cur.ymin); + immVertex2f(pos, frame_end, v2d->cur.ymax); + + immEnd(); if (ed && !BLI_listbase_is_empty(&ed->metastack)) { MetaStack *ms = ed->metastack.last; - glColor4ub(255, 255, 255, 8); - glRectf(ms->disp_range[0], v2d->cur.ymin, ms->disp_range[1], v2d->cur.ymax); + immUniformColor4ub(255, 255, 255, 8); + immRectf(pos, ms->disp_range[0], v2d->cur.ymin, ms->disp_range[1], v2d->cur.ymax); - UI_ThemeColorShade(TH_BACK, -40); + immUniformThemeColorShade(TH_BACK, -40); - fdrawline(ms->disp_range[0], v2d->cur.ymin, ms->disp_range[0], v2d->cur.ymax); - fdrawline(ms->disp_range[1], v2d->cur.ymin, ms->disp_range[1], v2d->cur.ymax); + immBegin(GL_LINES, 4); + + immVertex2f(pos, ms->disp_range[0], v2d->cur.ymin); + immVertex2f(pos, ms->disp_range[0], v2d->cur.ymax); + + immVertex2f(pos, ms->disp_range[1], v2d->cur.ymin); + immVertex2f(pos, ms->disp_range[1], v2d->cur.ymax); + + immEnd(); } + immUnbindProgram(); + glDisable(GL_BLEND); } @@ -1670,16 +1724,20 @@ void draw_timeline_seq(const bContext *C, ARegion *ar) /* overlap playhead */ if (scene->ed && scene->ed->over_flag & SEQ_EDIT_OVERLAY_SHOW) { int cfra_over = (scene->ed->over_flag & SEQ_EDIT_OVERLAY_ABS) ? scene->ed->over_cfra : scene->r.cfra + scene->ed->over_ofs; - glColor3f(0.2, 0.2, 0.2); - // glRectf(cfra_over, v2d->cur.ymin, scene->ed->over_ofs + scene->r.cfra + 1, v2d->cur.ymax); - glBegin(GL_LINES); - glVertex2f(cfra_over, v2d->cur.ymin); - glVertex2f(cfra_over, v2d->cur.ymax); - glEnd(); + unsigned pos = add_attrib(immVertexFormat(), "pos", GL_FLOAT, 2, KEEP_FLOAT); + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + immUniformColor3f(0.2, 0.2, 0.2); + + immBegin(GL_LINES, 2); + immVertex2f(pos, cfra_over, v2d->cur.ymin); + immVertex2f(pos, cfra_over, v2d->cur.ymax); + immEnd(); + + immUnbindProgram(); } - + /* callback */ ED_region_draw_cb_draw(C, ar, REGION_DRAW_POST_VIEW); diff --git a/source/blender/editors/space_sequencer/sequencer_edit.c b/source/blender/editors/space_sequencer/sequencer_edit.c index 8ae89941bdb..8963eb760ce 100644 --- a/source/blender/editors/space_sequencer/sequencer_edit.c +++ b/source/blender/editors/space_sequencer/sequencer_edit.c @@ -1256,7 +1256,6 @@ typedef struct SlipData { int num_seq; bool slow; int slow_offset; /* offset at the point where offset was turned on */ - void *draw_handle; NumInput num_input; } SlipData; @@ -1291,21 +1290,6 @@ static void transseq_restore(TransSeq *ts, Sequence *seq) seq->len = ts->len; } -static void draw_slip_extensions(const bContext *C, ARegion *ar, void *data) -{ - Scene *scene = CTX_data_scene(C); - SlipData *td = data; - int i; - - for (i = 0; i < td->num_seq; i++) { - Sequence *seq = td->seq_array[i]; - - if ((seq->type != SEQ_TYPE_META) && td->trim[i]) { - draw_sequence_extensions(scene, ar, seq); - } - } -} - static int slip_add_sequences_rec(ListBase *seqbasep, Sequence **seq_array, bool *trim, int offset, bool do_trim) { Sequence *seq; @@ -1354,7 +1338,6 @@ static int sequencer_slip_invoke(bContext *C, wmOperator *op, const wmEvent *eve SlipData *data; Scene *scene = CTX_data_scene(C); Editing *ed = BKE_sequencer_editing_get(scene, false); - ARegion *ar = CTX_wm_region(C); float mouseloc[2]; int num_seq, i; View2D *v2d = UI_view2d_fromcontext(C); @@ -1384,8 +1367,6 @@ static int sequencer_slip_invoke(bContext *C, wmOperator *op, const wmEvent *eve transseq_backup(data->ts + i, data->seq_array[i]); } - data->draw_handle = ED_region_draw_cb_activate(ar->type, draw_slip_extensions, data, REGION_DRAW_POST_VIEW); - UI_view2d_region_to_view(v2d, event->mval[0], event->mval[1], &mouseloc[0], &mouseloc[1]); copy_v2_v2_int(data->init_mouse, event->mval); @@ -1527,7 +1508,6 @@ static int sequencer_slip_modal(bContext *C, wmOperator *op, const wmEvent *even Scene *scene = CTX_data_scene(C); SlipData *data = (SlipData *)op->customdata; ScrArea *sa = CTX_wm_area(C); - ARegion *ar = CTX_wm_region(C); const bool has_numInput = hasNumInput(&data->num_input); bool handled = true; @@ -1585,7 +1565,6 @@ static int sequencer_slip_modal(bContext *C, wmOperator *op, const wmEvent *even case RETKEY: case SPACEKEY: { - ED_region_draw_cb_exit(ar->type, data->draw_handle); MEM_freeN(data->seq_array); MEM_freeN(data->trim); MEM_freeN(data->ts); @@ -1614,8 +1593,6 @@ static int sequencer_slip_modal(bContext *C, wmOperator *op, const wmEvent *even BKE_sequence_calc(scene, seq); } - ED_region_draw_cb_exit(ar->type, data->draw_handle); - MEM_freeN(data->seq_array); MEM_freeN(data->ts); MEM_freeN(data->trim); diff --git a/source/blender/editors/space_sequencer/sequencer_intern.h b/source/blender/editors/space_sequencer/sequencer_intern.h index 730cc117287..7ce2f73cbef 100644 --- a/source/blender/editors/space_sequencer/sequencer_intern.h +++ b/source/blender/editors/space_sequencer/sequencer_intern.h @@ -56,8 +56,6 @@ struct ARegion *sequencer_has_buttons_region(struct ScrArea *sa); void draw_timeline_seq(const struct bContext *C, struct ARegion *ar); void draw_image_seq(const struct bContext *C, struct Scene *scene, struct ARegion *ar, struct SpaceSeq *sseq, int cfra, int offset, bool draw_overlay, bool draw_backdrop); void color3ubv_from_seq(struct Scene *curscene, struct Sequence *seq, unsigned char col[3]); -void draw_shadedstrip(struct Sequence *seq, unsigned char col[3], float x1, float y1, float x2, float y2); -void draw_sequence_extensions(struct Scene *scene, struct ARegion *ar, struct Sequence *seq); void sequencer_special_update_set(Sequence *seq); diff --git a/source/blender/editors/space_text/text_draw.c b/source/blender/editors/space_text/text_draw.c index 81605a80f69..30b607e063d 100644 --- a/source/blender/editors/space_text/text_draw.c +++ b/source/blender/editors/space_text/text_draw.c @@ -906,7 +906,7 @@ static void draw_textscroll(const SpaceText *st, rcti *scroll, rcti *back) { bTheme *btheme = UI_GetTheme(); uiWidgetColors wcol = btheme->tui.wcol_scroll; - unsigned char col[4]; + float col[4]; float rad; UI_ThemeColor(TH_BACK); @@ -916,11 +916,10 @@ static void draw_textscroll(const SpaceText *st, rcti *scroll, rcti *back) UI_draw_roundbox_corner_set(UI_CNR_ALL); rad = 0.4f * min_ii(BLI_rcti_size_x(&st->txtscroll), BLI_rcti_size_y(&st->txtscroll)); - UI_GetThemeColor3ubv(TH_HILITE, col); - col[3] = 48; - glColor4ubv(col); + UI_GetThemeColor3fv(TH_HILITE, col); + col[3] = 0.18f; glEnable(GL_BLEND); - UI_draw_roundbox(st->txtscroll.xmin + 1, st->txtscroll.ymin, st->txtscroll.xmax - 1, st->txtscroll.ymax, rad); + UI_draw_roundbox(st->txtscroll.xmin + 1, st->txtscroll.ymin, st->txtscroll.xmax - 1, st->txtscroll.ymax, rad, col); glDisable(GL_BLEND); } diff --git a/source/blender/editors/space_time/space_time.c b/source/blender/editors/space_time/space_time.c index 15eb154c757..986ac062b05 100644 --- a/source/blender/editors/space_time/space_time.c +++ b/source/blender/editors/space_time/space_time.c @@ -69,6 +69,9 @@ #include "ED_space_api.h" #include "ED_markers.h" +#include "GPU_immediate.h" +#include "GPU_matrix.h" + #include "time_intern.h" /* ************************ main time area region *********************** */ @@ -80,28 +83,42 @@ static void time_draw_sfra_efra(Scene *scene, View2D *v2d) */ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glEnable(GL_BLEND); - glColor4f(0.0f, 0.0f, 0.0f, 0.4f); - + + VertexFormat *format = immVertexFormat(); + unsigned pos = add_attrib(format, "pos", GL_FLOAT, 2, KEEP_FLOAT); + + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + immUniformColor4f(0.0f, 0.0f, 0.0f, 0.4f); + if (PSFRA < PEFRA) { - glRectf(v2d->cur.xmin, v2d->cur.ymin, (float)PSFRA, v2d->cur.ymax); - glRectf((float)PEFRA, v2d->cur.ymin, v2d->cur.xmax, v2d->cur.ymax); + immRectf(pos, v2d->cur.xmin, v2d->cur.ymin, (float)PSFRA, v2d->cur.ymax); + immRectf(pos, (float)PEFRA, v2d->cur.ymin, v2d->cur.xmax, v2d->cur.ymax); } else { - glRectf(v2d->cur.xmin, v2d->cur.ymin, v2d->cur.xmax, v2d->cur.ymax); + immRectf(pos, v2d->cur.xmin, v2d->cur.ymin, v2d->cur.xmax, v2d->cur.ymax); } + glDisable(GL_BLEND); - UI_ThemeColorShade(TH_BACK, -60); /* thin lines where the actual frames are */ - fdrawline((float)PSFRA, v2d->cur.ymin, (float)PSFRA, v2d->cur.ymax); - fdrawline((float)PEFRA, v2d->cur.ymin, (float)PEFRA, v2d->cur.ymax); + immUniformThemeColorShade(TH_BACK, -60); + + immBegin(GL_LINES, 4); + + immVertex2f(pos, (float)PSFRA, v2d->cur.ymin); + immVertex2f(pos, (float)PSFRA, v2d->cur.ymax); + + immVertex2f(pos, (float)PEFRA, v2d->cur.ymin); + immVertex2f(pos, (float)PEFRA, v2d->cur.ymax); + + immEnd(); + immUnbindProgram(); } static void time_draw_cache(SpaceTime *stime, Object *ob, Scene *scene) { PTCacheID *pid; ListBase pidlist; - SpaceTimeCache *stc = stime->caches.first; const float cache_draw_height = (4.0f * UI_DPI_FAC * U.pixelsize); float yoffs = 0.f; @@ -110,12 +127,14 @@ static void time_draw_cache(SpaceTime *stime, Object *ob, Scene *scene) BKE_ptcache_ids_from_object(&pidlist, ob, scene, 0); + gpuMatrixBegin3D_legacy(); + unsigned int pos = add_attrib(immVertexFormat(), "pos", GL_FLOAT, 2, KEEP_FLOAT); + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + /* iterate over pointcaches on the active object, * add spacetimecache and vertex array for each */ for (pid = pidlist.first; pid; pid = pid->next) { - float col[4], *fp; - int i, sta = pid->cache->startframe, end = pid->cache->endframe; - int len = (end - sta + 1) * 4; + float col[4]; switch (pid->type) { case PTCACHE_TYPE_SOFTBODY: @@ -142,43 +161,9 @@ static void time_draw_cache(SpaceTime *stime, Object *ob, Scene *scene) if (pid->cache->cached_frames == NULL) continue; - /* make sure we have stc with correct array length */ - if (stc == NULL || MEM_allocN_len(stc->array) != len * 2 * sizeof(float)) { - if (stc) { - MEM_freeN(stc->array); - } - else { - stc = MEM_callocN(sizeof(SpaceTimeCache), "spacetimecache"); - BLI_addtail(&stime->caches, stc); - } - - stc->array = MEM_callocN(len * 2 * sizeof(float), "SpaceTimeCache array"); - } - - /* fill the vertex array with a quad for each cached frame */ - for (i = sta, fp = stc->array; i <= end; i++) { - if (pid->cache->cached_frames[i - sta]) { - fp[0] = (float)i - 0.5f; - fp[1] = 0.0; - fp += 2; - - fp[0] = (float)i - 0.5f; - fp[1] = 1.0; - fp += 2; - - fp[0] = (float)i + 0.5f; - fp[1] = 1.0; - fp += 2; - - fp[0] = (float)i + 0.5f; - fp[1] = 0.0; - fp += 2; - } - } - - glPushMatrix(); - glTranslatef(0.0, (float)V2D_SCROLL_HEIGHT + yoffs, 0.0); - glScalef(1.0, cache_draw_height, 0.0); + gpuPushMatrix(); + gpuTranslate3f(0.0, (float)V2D_SCROLL_HEIGHT + yoffs, 0.0); + gpuScale3f(1.0, cache_draw_height, 0.0); switch (pid->type) { case PTCACHE_TYPE_SOFTBODY: @@ -212,12 +197,15 @@ static void time_draw_cache(SpaceTime *stime, Object *ob, Scene *scene) BLI_assert(0); break; } - glColor4fv(col); - + + int sta = pid->cache->startframe, end = pid->cache->endframe; + int len = (end - sta + 1) * 4; + glEnable(GL_BLEND); - - glRectf((float)sta, 0.0, (float)end, 1.0); - + + immUniformColor4fv(col); + immRectf(pos, (float)sta, 0.0, (float)end, 1.0); + col[3] = 0.4f; if (pid->cache->flag & PTCACHE_BAKED) { col[0] -= 0.4f; col[1] -= 0.4f; col[2] -= 0.4f; @@ -225,52 +213,36 @@ static void time_draw_cache(SpaceTime *stime, Object *ob, Scene *scene) else if (pid->cache->flag & PTCACHE_OUTDATED) { col[0] += 0.4f; col[1] += 0.4f; col[2] += 0.4f; } - glColor4fv(col); - - glEnableClientState(GL_VERTEX_ARRAY); - glVertexPointer(2, GL_FLOAT, 0, stc->array); - glDrawArrays(GL_QUADS, 0, (fp - stc->array) / 2); - glDisableClientState(GL_VERTEX_ARRAY); - - glDisable(GL_BLEND); - - glPopMatrix(); - - yoffs += cache_draw_height; - stc = stc->next; - } + immUniformColor4fv(col); - BLI_freelistN(&pidlist); + if (len > 0) { + immBeginAtMost(GL_QUADS, len); - /* free excessive caches */ - while (stc) { - SpaceTimeCache *tmp = stc->next; - BLI_remlink(&stime->caches, stc); - MEM_freeN(stc->array); - MEM_freeN(stc); - stc = tmp; - } -} + /* draw a quad for each cached frame */ + for (int i = sta; i <= end; i++) { + if (pid->cache->cached_frames[i - sta]) { + immVertex2f(pos, (float)i - 0.5f, 0.0f); + immVertex2f(pos, (float)i - 0.5f, 1.0f); + immVertex2f(pos, (float)i + 0.5f, 1.0f); + immVertex2f(pos, (float)i + 0.5f, 0.0f); + } + } -static void time_cache_free(SpaceTime *stime) -{ - SpaceTimeCache *stc; - - for (stc = stime->caches.first; stc; stc = stc->next) { - if (stc->array) { - MEM_freeN(stc->array); - stc->array = NULL; + immEnd(); } + + glDisable(GL_BLEND); + + gpuPopMatrix(); + + yoffs += cache_draw_height; } - - BLI_freelistN(&stime->caches); -} -static void time_cache_refresh(SpaceTime *stime) -{ - /* Free previous caches to indicate full refresh */ - time_cache_free(stime); + immUnbindProgram(); + gpuMatrixEnd(); + + BLI_freelistN(&pidlist); } /* helper function - find actkeycolumn that occurs on cframe, or the nearest one if not found */ @@ -296,7 +268,7 @@ static ActKeyColumn *time_cfra_find_ak(ActKeyColumn *ak, float cframe) } /* helper for time_draw_keyframes() */ -static void time_draw_idblock_keyframes(View2D *v2d, ID *id, short onlysel) +static void time_draw_idblock_keyframes(View2D *v2d, ID *id, short onlysel, const unsigned char color[3]) { bDopeSheet ads = {NULL}; DLRBT_Tree keys; @@ -339,21 +311,42 @@ static void time_draw_idblock_keyframes(View2D *v2d, ID *id, short onlysel) * the first visible keyframe (last one can then be easily checked) * - draw within a single GL block to be faster */ - glBegin(GL_LINES); - for (ak = time_cfra_find_ak(keys.root, v2d->cur.xmin); - (ak) && (ak->cfra <= v2d->cur.xmax); - ak = ak->next) - { - glVertex2f(ak->cfra, ymin); - glVertex2f(ak->cfra, ymax); + + ActKeyColumn *link; + int max_len = 0; + + ak = time_cfra_find_ak(keys.root, v2d->cur.xmin); + + for (link = ak; link; link = link->next) { + max_len++; } - glEnd(); // GL_LINES - + + if (max_len > 0) { + + VertexFormat *format = immVertexFormat(); + unsigned pos = add_attrib(format, "pos", GL_FLOAT, 2, KEEP_FLOAT); + + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + immUniformColor3ubv(color); + + immBeginAtMost(GL_LINES, max_len * 2); + + for (; (ak) && (ak->cfra <= v2d->cur.xmax); + ak = ak->next) + { + immVertex2f(pos, ak->cfra, ymin); + immVertex2f(pos, ak->cfra, ymax); + } + + immEnd(); + immUnbindProgram(); + } + /* free temp stuff */ BLI_dlrbTree_free(&keys); } -static void time_draw_caches_keyframes(Main *bmain, Scene *scene, View2D *v2d, bool onlysel) +static void time_draw_caches_keyframes(Main *bmain, SceneLayer *sl, View2D *v2d, bool onlysel, const unsigned char color[3]) { CacheFile *cache_file; @@ -364,7 +357,7 @@ static void time_draw_caches_keyframes(Main *bmain, Scene *scene, View2D *v2d, b cache_file->draw_flag &= ~CACHEFILE_KEYFRAME_DRAWN; } - for (Base *base = scene->base.first; base; base = base->next) { + for (Base *base = sl->object_bases.first; base; base = base->next) { Object *ob = base->object; ModifierData *md = modifiers_findByType(ob, eModifierType_MeshSequenceCache); @@ -380,7 +373,7 @@ static void time_draw_caches_keyframes(Main *bmain, Scene *scene, View2D *v2d, b cache_file->draw_flag |= CACHEFILE_KEYFRAME_DRAWN; - time_draw_idblock_keyframes(v2d, (ID *)cache_file, onlysel); + time_draw_idblock_keyframes(v2d, (ID *)cache_file, onlysel, color); } for (bConstraint *con = ob->constraints.first; con; con = con->next) { @@ -398,7 +391,7 @@ static void time_draw_caches_keyframes(Main *bmain, Scene *scene, View2D *v2d, b cache_file->draw_flag |= CACHEFILE_KEYFRAME_DRAWN; - time_draw_idblock_keyframes(v2d, (ID *)cache_file, onlysel); + time_draw_idblock_keyframes(v2d, (ID *)cache_file, onlysel, color); } } } @@ -407,24 +400,27 @@ static void time_draw_caches_keyframes(Main *bmain, Scene *scene, View2D *v2d, b static void time_draw_keyframes(const bContext *C, ARegion *ar) { Scene *scene = CTX_data_scene(C); + SceneLayer *sl = CTX_data_scene_layer(C); Object *ob = CTX_data_active_object(C); View2D *v2d = &ar->v2d; bool onlysel = ((scene->flag & SCE_KEYS_NO_SELONLY) == 0); + unsigned char color[3]; /* set this for all keyframe lines once and for all */ glLineWidth(1.0); /* draw cache files keyframes (if available) */ - UI_ThemeColor(TH_TIME_KEYFRAME); - time_draw_caches_keyframes(CTX_data_main(C), scene, v2d, onlysel); + UI_GetThemeColor3ubv(TH_TIME_KEYFRAME, color); + time_draw_caches_keyframes(CTX_data_main(C), sl, v2d, onlysel, color); /* draw grease pencil keyframes (if available) */ - UI_ThemeColor(TH_TIME_GP_KEYFRAME); + UI_GetThemeColor3ubv(TH_TIME_GP_KEYFRAME, color); + if (scene->gpd) { - time_draw_idblock_keyframes(v2d, (ID *)scene->gpd, onlysel); + time_draw_idblock_keyframes(v2d, (ID *)scene->gpd, onlysel, color); } if (ob && ob->gpd) { - time_draw_idblock_keyframes(v2d, (ID *)ob->gpd, onlysel); + time_draw_idblock_keyframes(v2d, (ID *)ob->gpd, onlysel, color); } /* draw scene keyframes first @@ -433,8 +429,8 @@ static void time_draw_keyframes(const bContext *C, ARegion *ar) */ if (onlysel == 0) { /* set draw color */ - UI_ThemeColorShade(TH_TIME_KEYFRAME, -50); - time_draw_idblock_keyframes(v2d, (ID *)scene, onlysel); + UI_GetThemeColorShade3ubv(TH_TIME_KEYFRAME, -50, color); + time_draw_idblock_keyframes(v2d, (ID *)scene, onlysel, color); } /* draw keyframes from selected objects @@ -442,11 +438,11 @@ static void time_draw_keyframes(const bContext *C, ARegion *ar) * OR the onlysel flag was set, which means that only active object's keyframes should * be considered */ - UI_ThemeColor(TH_TIME_KEYFRAME); - + UI_GetThemeColor3ubv(TH_TIME_KEYFRAME, color); + if (ob && ((ob->mode == OB_MODE_POSE) || onlysel)) { /* draw keyframes for active object only */ - time_draw_idblock_keyframes(v2d, (ID *)ob, onlysel); + time_draw_idblock_keyframes(v2d, (ID *)ob, onlysel, color); } else { bool active_done = false; @@ -455,7 +451,7 @@ static void time_draw_keyframes(const bContext *C, ARegion *ar) CTX_DATA_BEGIN (C, Object *, obsel, selected_objects) { /* last arg is 0, since onlysel doesn't apply here... */ - time_draw_idblock_keyframes(v2d, (ID *)obsel, 0); + time_draw_idblock_keyframes(v2d, (ID *)obsel, 0, color); /* if this object is the active one, set flag so that we don't draw again */ if (obsel == ob) @@ -465,22 +461,12 @@ static void time_draw_keyframes(const bContext *C, ARegion *ar) /* if active object hasn't been done yet, draw it... */ if (ob && (active_done == 0)) - time_draw_idblock_keyframes(v2d, (ID *)ob, 0); + time_draw_idblock_keyframes(v2d, (ID *)ob, 0, color); } } /* ---------------- */ -static void time_refresh(const bContext *UNUSED(C), ScrArea *sa) -{ - /* find the main timeline region and refresh cache display*/ - ARegion *ar = BKE_area_find_region_type(sa, RGN_TYPE_WINDOW); - if (ar) { - SpaceTime *stime = (SpaceTime *)sa->spacedata.first; - time_cache_refresh(stime); - } -} - /* editor level listener */ static void time_listener(bScreen *UNUSED(sc), ScrArea *sa, wmNotifier *wmn) { @@ -752,13 +738,6 @@ static SpaceLink *time_new(const bContext *C) return (SpaceLink *)stime; } -/* not spacelink itself */ -static void time_free(SpaceLink *sl) -{ - SpaceTime *stime = (SpaceTime *)sl; - - time_cache_free(stime); -} /* spacetype; init callback in ED_area_initialize() */ /* init is called to (re)initialize an existing editor (file read, screen changes) */ /* validate spacedata, add own area level handlers */ @@ -766,8 +745,6 @@ static void time_init(wmWindowManager *UNUSED(wm), ScrArea *sa) { SpaceTime *stime = (SpaceTime *)sa->spacedata.first; - time_cache_free(stime); - /* enable all cache display */ stime->cache_display |= TIME_CACHE_DISPLAY; stime->cache_display |= (TIME_CACHE_SOFTBODY | TIME_CACHE_PARTICLES); @@ -796,13 +773,11 @@ void ED_spacetype_time(void) strncpy(st->name, "Timeline", BKE_ST_MAXNAME); st->new = time_new; - st->free = time_free; st->init = time_init; st->duplicate = time_duplicate; st->operatortypes = time_operatortypes; st->keymap = NULL; st->listener = time_listener; - st->refresh = time_refresh; /* regions: main window */ art = MEM_callocN(sizeof(ARegionType), "spacetype time region"); diff --git a/source/blender/editors/space_view3d/CMakeLists.txt b/source/blender/editors/space_view3d/CMakeLists.txt index a5c60248bf1..f6d5cf6e5d2 100644 --- a/source/blender/editors/space_view3d/CMakeLists.txt +++ b/source/blender/editors/space_view3d/CMakeLists.txt @@ -52,6 +52,7 @@ set(SRC view3d_buttons.c view3d_camera_control.c view3d_draw.c + view3d_draw_legacy.c view3d_edit.c view3d_fly.c view3d_walk.c @@ -94,8 +95,4 @@ if(WITH_MOD_SMOKE) add_definitions(-DWITH_SMOKE) endif() -if(WITH_LEGACY_DEPSGRAPH) - add_definitions(-DWITH_LEGACY_DEPSGRAPH) -endif() - blender_add_lib(bf_editor_space_view3d "${SRC}" "${INC}" "${INC_SYS}") diff --git a/source/blender/editors/space_view3d/drawanimviz.c b/source/blender/editors/space_view3d/drawanimviz.c index f0e65f84205..505ed1fdd3a 100644 --- a/source/blender/editors/space_view3d/drawanimviz.c +++ b/source/blender/editors/space_view3d/drawanimviz.c @@ -51,6 +51,8 @@ #include "BIF_gl.h" +#include "GPU_immediate.h" + #include "ED_keyframes_draw.h" @@ -86,10 +88,11 @@ void draw_motion_paths_init(View3D *v3d, ARegion *ar) * - User selected color for next frames */ static void set_motion_path_color(Scene *scene, bMotionPath *mpath, int i, short sel, int sfra, int efra, - float prev_color[3], float frame_color[3], float next_color[3]) + float prev_color[3], float frame_color[3], float next_color[3], unsigned color) { int frame = sfra + i; int blend_base = (abs(frame - CFRA) == 1) ? TH_CFRAME : TH_BACK; /* "bleed" cframe color to ease color blending */ + unsigned char ubcolor[3]; #define SET_INTENSITY(A, B, C, min, max) (((1.0f - ((C - B) / (C - A))) * (max - min)) + min) float intensity; /* how faint */ @@ -97,7 +100,7 @@ static void set_motion_path_color(Scene *scene, bMotionPath *mpath, int i, short if (frame < CFRA) { if (mpath->flag & MOTIONPATH_FLAG_CUSTOM) { /* Custom color: previous frames color is darker than current frame */ - glColor3fv(prev_color); + rgb_float_to_uchar(ubcolor, prev_color); } else { /* black - before cfra */ @@ -109,13 +112,14 @@ static void set_motion_path_color(Scene *scene, bMotionPath *mpath, int i, short /* intensity = 0.8f; */ intensity = SET_INTENSITY(sfra, i, CFRA, 0.68f, 0.92f); } - UI_ThemeColorBlend(TH_WIRE, blend_base, intensity); + + UI_GetThemeColorBlend3ubv(TH_WIRE, blend_base, intensity, ubcolor); } } else if (frame > CFRA) { if (mpath->flag & MOTIONPATH_FLAG_CUSTOM) { /* Custom color: next frames color is equal to user selected color */ - glColor3fv(next_color); + rgb_float_to_uchar(ubcolor, next_color); } else { /* blue - after cfra */ @@ -127,13 +131,14 @@ static void set_motion_path_color(Scene *scene, bMotionPath *mpath, int i, short /* intensity = 0.8f; */ intensity = SET_INTENSITY(CFRA, i, efra, 0.68f, 0.92f); } - UI_ThemeColorBlend(TH_BONE_POSE, blend_base, intensity); + + UI_GetThemeColorBlend3ubv(TH_BONE_POSE, blend_base, intensity, ubcolor); } } else { if (mpath->flag & MOTIONPATH_FLAG_CUSTOM) { /* Custom color: current frame color is slightly darker than user selected color */ - glColor3fv(frame_color); + rgb_float_to_uchar(ubcolor, frame_color); } else { /* green - on cfra */ @@ -143,9 +148,12 @@ static void set_motion_path_color(Scene *scene, bMotionPath *mpath, int i, short else { intensity = 0.99f; } - UI_ThemeColorBlendShade(TH_CFRAME, TH_BACK, intensity, 10); + UI_GetThemeColorBlendShade3ubv(TH_CFRAME, TH_BACK, intensity, 10, ubcolor); } } + + immAttrib3ubv(color, ubcolor); + #undef SET_INTENSITY } @@ -231,42 +239,65 @@ void draw_motion_path_instance(Scene *scene, /* set line thickness */ glLineWidth(mpath->line_thickness); - glBegin(GL_LINE_STRIP); + VertexFormat *format = immVertexFormat(); + unsigned pos = add_attrib(format, "pos", GL_FLOAT, 3, KEEP_FLOAT); + unsigned color = add_attrib(format, "color", GL_UNSIGNED_BYTE, 3, NORMALIZE_INT_TO_FLOAT); + + immBindBuiltinProgram(GPU_SHADER_3D_SMOOTH_COLOR); + + immBegin(GL_LINE_STRIP, len); + for (i = 0, mpv = mpv_start; i < len; i++, mpv++) { short sel = (pchan) ? (pchan->bone->flag & BONE_SELECTED) : (ob->flag & SELECT); + /* Set color */ - set_motion_path_color(scene, mpath, i, sel, sfra, efra, prev_color, frame_color, next_color); + set_motion_path_color(scene, mpath, i, sel, sfra, efra, prev_color, frame_color, next_color, color); + /* draw a vertex with this color */ - glVertex3fv(mpv->co); + immVertex3fv(pos, mpv->co); } - glEnd(); + immEnd(); + + immUnbindProgram(); + /* back to old line thickness */ glLineWidth(old_width); } + unsigned pos = add_attrib(immVertexFormat(), "pos", GL_FLOAT, 3, KEEP_FLOAT); + + immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR); + /* Point must be bigger than line thickness */ glPointSize(mpath->line_thickness + 1.0); - /* draw little black point at each frame - * NOTE: this is not really visible/noticeable - */ - glBegin(GL_POINTS); - for (i = 0, mpv = mpv_start; i < len; i++, mpv++) - glVertex3fv(mpv->co); - glEnd(); - + /* draw little black point at each frame */ + immUniformColor3ub(0, 0, 0); + + immBegin(GL_POINTS, len); + + for (i = 0, mpv = mpv_start; i < len; i++, mpv++) { + immVertex3fv(pos, mpv->co); + } + + immEnd(); + /* Draw little white dots at each framestep value or replace with custom color */ if (mpath->flag & MOTIONPATH_FLAG_CUSTOM) { - glColor4fv(mpath->color); + immUniformColor3fv(mpath->color); } else { - UI_ThemeColor(TH_TEXT_HI); + immUniformThemeColor(TH_TEXT_HI); } - glBegin(GL_POINTS); - for (i = 0, mpv = mpv_start; i < len; i += stepsize, mpv += stepsize) - glVertex3fv(mpv->co); - glEnd(); + + immBegin(GL_POINTS, (len + stepsize - 1) / stepsize); + + for (i = 0, mpv = mpv_start; i < len; i += stepsize, mpv += stepsize) { + immVertex3fv(pos, mpv->co); + } + + immEnd(); /* Draw big green dot where the current frame is * NOTE: this is only done when keyframes are shown, since this adds similar types of clutter @@ -274,16 +305,18 @@ void draw_motion_path_instance(Scene *scene, if ((avs->path_viewflag & MOTIONPATH_VIEW_KFRAS) && (sfra < CFRA) && (CFRA <= efra)) { - UI_ThemeColor(TH_CFRAME); - glPointSize(mpath->line_thickness + 5.0); - glBegin(GL_POINTS); + immUniformThemeColor(TH_CFRAME); + + immBegin(GL_POINTS, 1); + mpv = mpv_start + (CFRA - sfra); - glVertex3fv(mpv->co); - glEnd(); - - UI_ThemeColor(TH_TEXT_HI); + immVertex3fv(pos, mpv->co); + + immEnd(); } + + immUnbindProgram(); /* XXX, this isn't up to date but probably should be kept so. */ invert_m4_m4(ob->imat, ob->obmat); @@ -353,24 +386,28 @@ void draw_motion_path_instance(Scene *scene, UI_GetThemeColor3ubv(TH_VERTEX_SELECT, col); col[3] = 255; - /* if custom, point must be bigger than line */ - if (mpath->flag & MOTIONPATH_FLAG_CUSTOM) { - glPointSize(mpath->line_thickness + 3.0); - } - else { - glPointSize(4.0f); - } - glColor3ubv(col); + /* point must be bigger than line */ + glPointSize(mpath->line_thickness + 3.0); + + pos = add_attrib(immVertexFormat(), "pos", GL_FLOAT, 3, KEEP_FLOAT); + + immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR); + immUniformColor3ubv(col); - glBegin(GL_POINTS); + immBeginAtMost(GL_POINTS, len); + for (i = 0, mpv = mpv_start; i < len; i++, mpv++) { int frame = sfra + i; float mframe = (float)(frame); - if (BLI_dlrbTree_search_exact(&keys, compare_ak_cfraPtr, &mframe)) - glVertex3fv(mpv->co); + if (BLI_dlrbTree_search_exact(&keys, compare_ak_cfraPtr, &mframe)) { + immVertex3fv(pos, mpv->co); + } } - glEnd(); + + immEnd(); + + immUnbindProgram(); /* Draw frame numbers of keyframes */ if (avs->path_viewflag & MOTIONPATH_VIEW_KFNOS) { diff --git a/source/blender/editors/space_view3d/drawarmature.c b/source/blender/editors/space_view3d/drawarmature.c index 149144d969a..172df71bfc5 100644 --- a/source/blender/editors/space_view3d/drawarmature.c +++ b/source/blender/editors/space_view3d/drawarmature.c @@ -63,6 +63,9 @@ #include "ED_keyframes_draw.h" #include "GPU_basic_shader.h" +#include "GPU_batch.h" +#include "GPU_immediate.h" +#include "GPU_matrix.h" #include "UI_resources.h" @@ -74,8 +77,10 @@ /* global here is reset before drawing each bone */ static ThemeWireColor *bcolor = NULL; +static float fcolor[4] = {0.0f}; +static bool flat_color; -/* values of colCode for set_pchan_glcolor */ +/* values of colCode for set_pchan_color */ enum { PCHAN_COLOR_NORMAL = 0, /* normal drawing */ PCHAN_COLOR_SOLID, /* specific case where "solid" color is needed */ @@ -128,7 +133,7 @@ static void set_pchan_colorset(Object *ob, bPoseChannel *pchan) } } -/* This function is for brightening/darkening a given color (like UI_ThemeColorShade()) */ +/* This function is for brightening/darkening a given color (like UI_GetThemeColorShade3ubv()) */ static void cp_shade_color3ub(unsigned char cp[3], const int offset) { int r, g, b; @@ -146,13 +151,13 @@ static void cp_shade_color3ub(unsigned char cp[3], const int offset) } /* This function sets the gl-color for coloring a certain bone (based on bcolor) */ -static bool set_pchan_glColor(short colCode, int boneflag, short constflag) +static bool set_pchan_color(short colCode, int boneflag, short constflag) { switch (colCode) { case PCHAN_COLOR_NORMAL: { if (bcolor) { - unsigned char cp[3]; + unsigned char cp[4] = {255}; if (boneflag & BONE_DRAW_ACTIVE) { copy_v3_v3_char((char *)cp, bcolor->active); @@ -169,20 +174,20 @@ static bool set_pchan_glColor(short colCode, int boneflag, short constflag) cp_shade_color3ub(cp, -50); } - glColor3ubv(cp); + rgb_uchar_to_float(fcolor, cp); } else { if ((boneflag & BONE_DRAW_ACTIVE) && (boneflag & BONE_SELECTED)) { - UI_ThemeColor(TH_BONE_POSE_ACTIVE); + UI_GetThemeColor4fv(TH_BONE_POSE_ACTIVE, fcolor); } else if (boneflag & BONE_DRAW_ACTIVE) { - UI_ThemeColorBlend(TH_WIRE, TH_BONE_POSE, 0.15f); /* unselected active */ + UI_GetThemeColorBlendShade4fv(TH_WIRE, TH_BONE_POSE, 0.15f, 0, fcolor); } else if (boneflag & BONE_SELECTED) { - UI_ThemeColor(TH_BONE_POSE); + UI_GetThemeColor4fv(TH_BONE_POSE, fcolor); } else { - UI_ThemeColor(TH_WIRE); + UI_GetThemeColor4fv(TH_WIRE, fcolor); } } @@ -191,21 +196,25 @@ static bool set_pchan_glColor(short colCode, int boneflag, short constflag) case PCHAN_COLOR_SOLID: { if (bcolor) { - glColor3ubv((unsigned char *)bcolor->solid); + rgb_uchar_to_float(fcolor, (unsigned char *)bcolor->solid); + } + else { + UI_GetThemeColor4fv(TH_BONE_SOLID, fcolor); } - else - UI_ThemeColor(TH_BONE_SOLID); return true; } case PCHAN_COLOR_CONSTS: { if ((bcolor == NULL) || (bcolor->flag & TH_WIRECOLOR_CONSTCOLS)) { - if (constflag & PCHAN_HAS_TARGET) glColor4ub(255, 150, 0, 80); - else if (constflag & PCHAN_HAS_IK) glColor4ub(255, 255, 0, 80); - else if (constflag & PCHAN_HAS_SPLINEIK) glColor4ub(200, 255, 0, 80); - else if (constflag & PCHAN_HAS_CONST) glColor4ub(0, 255, 120, 80); - + unsigned char cp[4]; + if (constflag & PCHAN_HAS_TARGET) rgba_char_args_set((char *)cp, 255, 150, 0, 80); + else if (constflag & PCHAN_HAS_IK) rgba_char_args_set((char *)cp, 255, 255, 0, 80); + else if (constflag & PCHAN_HAS_SPLINEIK) rgba_char_args_set((char *)cp, 200, 255, 0, 80); + else if (constflag & PCHAN_HAS_CONST) rgba_char_args_set((char *)cp, 0, 255, 120, 80); + + rgba_uchar_to_float(fcolor, cp); + return true; } return false; @@ -213,7 +222,7 @@ static bool set_pchan_glColor(short colCode, int boneflag, short constflag) case PCHAN_COLOR_SPHEREBONE_BASE: { if (bcolor) { - unsigned char cp[3]; + unsigned char cp[4] = {255}; if (boneflag & BONE_DRAW_ACTIVE) { copy_v3_v3_char((char *)cp, bcolor->active); @@ -225,12 +234,18 @@ static bool set_pchan_glColor(short colCode, int boneflag, short constflag) copy_v3_v3_char((char *)cp, bcolor->solid); } - glColor3ubv(cp); + rgb_uchar_to_float(fcolor, cp); } else { - if (boneflag & BONE_DRAW_ACTIVE) UI_ThemeColorShade(TH_BONE_POSE, 40); - else if (boneflag & BONE_SELECTED) UI_ThemeColor(TH_BONE_POSE); - else UI_ThemeColor(TH_BONE_SOLID); + if (boneflag & BONE_DRAW_ACTIVE) { + UI_GetThemeColorShade4fv(TH_BONE_POSE, 40, fcolor); + } + else if (boneflag & BONE_SELECTED) { + UI_GetThemeColor4fv(TH_BONE_POSE, fcolor); + } + else { + UI_GetThemeColor4fv(TH_BONE_SOLID, fcolor); + } } return true; @@ -238,7 +253,7 @@ static bool set_pchan_glColor(short colCode, int boneflag, short constflag) case PCHAN_COLOR_SPHEREBONE_END: { if (bcolor) { - unsigned char cp[3]; + unsigned char cp[4] = {255}; if (boneflag & BONE_DRAW_ACTIVE) { copy_v3_v3_char((char *)cp, bcolor->active); @@ -253,12 +268,18 @@ static bool set_pchan_glColor(short colCode, int boneflag, short constflag) cp_shade_color3ub(cp, -30); } - glColor3ubv(cp); + rgb_uchar_to_float(fcolor, cp); } else { - if (boneflag & BONE_DRAW_ACTIVE) UI_ThemeColorShade(TH_BONE_POSE, 10); - else if (boneflag & BONE_SELECTED) UI_ThemeColorShade(TH_BONE_POSE, -30); - else UI_ThemeColorShade(TH_BONE_SOLID, -30); + if (boneflag & BONE_DRAW_ACTIVE) { + UI_GetThemeColorShade4fv(TH_BONE_POSE, 10, fcolor); + } + else if (boneflag & BONE_SELECTED) { + UI_GetThemeColorShade4fv(TH_BONE_POSE, -30, fcolor); + } + else { + UI_GetThemeColorShade4fv(TH_BONE_SOLID, -30, fcolor); + } } break; } @@ -266,19 +287,24 @@ static bool set_pchan_glColor(short colCode, int boneflag, short constflag) { /* inner part in background color or constraint */ if ((constflag) && ((bcolor == NULL) || (bcolor->flag & TH_WIRECOLOR_CONSTCOLS))) { - if (constflag & PCHAN_HAS_TARGET) glColor3ub(255, 150, 0); - else if (constflag & PCHAN_HAS_IK) glColor3ub(255, 255, 0); - else if (constflag & PCHAN_HAS_SPLINEIK) glColor3ub(200, 255, 0); - else if (constflag & PCHAN_HAS_CONST) glColor3ub(0, 255, 120); - else if (constflag) UI_ThemeColor(TH_BONE_POSE); /* PCHAN_HAS_ACTION */ + unsigned char cp[4]; + if (constflag & PCHAN_HAS_TARGET) rgba_char_args_set((char *)cp, 255, 150, 0, 255); + else if (constflag & PCHAN_HAS_IK) rgba_char_args_set((char *)cp, 255, 255, 0, 255); + else if (constflag & PCHAN_HAS_SPLINEIK) rgba_char_args_set((char *)cp, 200, 255, 0, 255); + else if (constflag & PCHAN_HAS_CONST) rgba_char_args_set((char *)cp, 0, 255, 120, 255); + else if (constflag) UI_GetThemeColor4ubv(TH_BONE_POSE, cp); /* PCHAN_HAS_ACTION */ + + rgb_uchar_to_float(fcolor, cp); } else { if (bcolor) { const char *cp = bcolor->solid; - glColor4ub(cp[0], cp[1], cp[2], 204); + rgb_uchar_to_float(fcolor, (unsigned char *)cp); + fcolor[3] = 204.f / 255.f; + } + else { + UI_GetThemeColorShade4fv(TH_BACK, -30, fcolor); } - else - UI_ThemeColorShade(TH_BACK, -30); } return true; @@ -288,26 +314,37 @@ static bool set_pchan_glColor(short colCode, int boneflag, short constflag) return false; } -static void set_ebone_glColor(const unsigned int boneflag) +static void set_ebone_color(const unsigned int boneflag) { if ((boneflag & BONE_DRAW_ACTIVE) && (boneflag & BONE_SELECTED)) { - UI_ThemeColor(TH_EDGE_SELECT); + UI_GetThemeColor4fv(TH_EDGE_SELECT, fcolor); } else if (boneflag & BONE_DRAW_ACTIVE) { - UI_ThemeColorBlend(TH_WIRE_EDIT, TH_EDGE_SELECT, 0.15f); /* unselected active */ + UI_GetThemeColorBlendShade4fv(TH_WIRE_EDIT, TH_EDGE_SELECT, 0.15f, 0, fcolor); } else if (boneflag & BONE_SELECTED) { - UI_ThemeColorShade(TH_EDGE_SELECT, -20); + UI_GetThemeColorShade4fv(TH_EDGE_SELECT, -20, fcolor); } else { - UI_ThemeColor(TH_WIRE_EDIT); + UI_GetThemeColor4fv(TH_WIRE_EDIT, fcolor); } } /* *************** Armature drawing, helper calls for parts ******************* */ +static void add_solid_flat_triangle(VertexBuffer *vbo, unsigned int *vertex, unsigned int pos, unsigned int nor, + const float p1[3], const float p2[3], const float p3[3], const float n[3]) +{ + setAttrib(vbo, nor, *vertex, n); + setAttrib(vbo, pos, (*vertex)++, p1); + setAttrib(vbo, nor, *vertex, n); + setAttrib(vbo, pos, (*vertex)++, p2); + setAttrib(vbo, nor, *vertex, n); + setAttrib(vbo, pos, (*vertex)++, p3); +} + /* half the cube, in Y */ -static const float cube[8][3] = { +static const float cube_vert[8][3] = { {-1.0, 0.0, -1.0}, {-1.0, 0.0, 1.0}, {-1.0, 1.0, 1.0}, @@ -318,128 +355,189 @@ static const float cube[8][3] = { { 1.0, 1.0, -1.0}, }; +static const float cube_wire[24] = { + 0, 1, 1, 2, 2, 3, 3, 0, + 4, 5, 5, 6, 6, 7, 7, 4, + 0, 4, 1, 5, 2, 6, 3, 7, +}; + static void drawsolidcube_size(float xsize, float ysize, float zsize) { - static GLuint displist = 0; - float n[3] = {0.0f}; - - glScalef(xsize, ysize, zsize); - - if (displist == 0) { - displist = glGenLists(1); - glNewList(displist, GL_COMPILE); + static VertexFormat format = {0}; + static VertexBuffer vbo = {0}; + static Batch batch = {0}; + const float light_vec[3] = {0.0f, 0.0f, 1.0f}; + + if (format.attrib_ct == 0) { + unsigned int i = 0; + float n[3] = {0.0f}; + /* Vertex format */ + unsigned int pos = add_attrib(&format, "pos", GL_FLOAT, 3, KEEP_FLOAT); + unsigned int nor = add_attrib(&format, "nor", GL_FLOAT, 3, KEEP_FLOAT); + + /* Vertices */ + VertexBuffer_init_with_format(&vbo, &format); + VertexBuffer_allocate_data(&vbo, 36); - glBegin(GL_QUADS); n[0] = -1.0; - glNormal3fv(n); - glVertex3fv(cube[0]); glVertex3fv(cube[1]); glVertex3fv(cube[2]); glVertex3fv(cube[3]); + add_solid_flat_triangle(&vbo, &i, pos, nor, cube_vert[0], cube_vert[1], cube_vert[2], n); + add_solid_flat_triangle(&vbo, &i, pos, nor, cube_vert[2], cube_vert[3], cube_vert[0], n); n[0] = 0; n[1] = -1.0; - glNormal3fv(n); - glVertex3fv(cube[0]); glVertex3fv(cube[4]); glVertex3fv(cube[5]); glVertex3fv(cube[1]); + add_solid_flat_triangle(&vbo, &i, pos, nor, cube_vert[0], cube_vert[4], cube_vert[5], n); + add_solid_flat_triangle(&vbo, &i, pos, nor, cube_vert[5], cube_vert[1], cube_vert[0], n); n[1] = 0; n[0] = 1.0; - glNormal3fv(n); - glVertex3fv(cube[4]); glVertex3fv(cube[7]); glVertex3fv(cube[6]); glVertex3fv(cube[5]); + add_solid_flat_triangle(&vbo, &i, pos, nor, cube_vert[4], cube_vert[7], cube_vert[6], n); + add_solid_flat_triangle(&vbo, &i, pos, nor, cube_vert[6], cube_vert[5], cube_vert[4], n); n[0] = 0; n[1] = 1.0; - glNormal3fv(n); - glVertex3fv(cube[7]); glVertex3fv(cube[3]); glVertex3fv(cube[2]); glVertex3fv(cube[6]); + add_solid_flat_triangle(&vbo, &i, pos, nor, cube_vert[7], cube_vert[3], cube_vert[2], n); + add_solid_flat_triangle(&vbo, &i, pos, nor, cube_vert[2], cube_vert[6], cube_vert[7], n); n[1] = 0; n[2] = 1.0; - glNormal3fv(n); - glVertex3fv(cube[1]); glVertex3fv(cube[5]); glVertex3fv(cube[6]); glVertex3fv(cube[2]); + add_solid_flat_triangle(&vbo, &i, pos, nor, cube_vert[1], cube_vert[5], cube_vert[6], n); + add_solid_flat_triangle(&vbo, &i, pos, nor, cube_vert[6], cube_vert[2], cube_vert[1], n); n[2] = -1.0; - glNormal3fv(n); - glVertex3fv(cube[7]); glVertex3fv(cube[4]); glVertex3fv(cube[0]); glVertex3fv(cube[3]); - glEnd(); + add_solid_flat_triangle(&vbo, &i, pos, nor, cube_vert[7], cube_vert[4], cube_vert[0], n); + add_solid_flat_triangle(&vbo, &i, pos, nor, cube_vert[0], cube_vert[3], cube_vert[7], n); - glEndList(); + Batch_init(&batch, GL_TRIANGLES, &vbo, NULL); } - glCallList(displist); + gpuMatrixBegin3D_legacy(); + gpuScale3f(xsize, ysize, zsize); + + if (flat_color) { + Batch_set_builtin_program(&batch, GPU_SHADER_3D_UNIFORM_COLOR); + } + else { + /* TODO replace with good default lighting shader ? */ + Batch_set_builtin_program(&batch, GPU_SHADER_SIMPLE_LIGHTING); + Batch_Uniform3fv(&batch, "light", light_vec); + } + Batch_Uniform4fv(&batch, "color", fcolor); + Batch_draw(&batch); + + gpuMatrixEnd(); } static void drawcube_size(float xsize, float ysize, float zsize) { - static GLuint displist = 0; - - if (displist == 0) { - displist = glGenLists(1); - glNewList(displist, GL_COMPILE); - - glBegin(GL_LINE_STRIP); - glVertex3fv(cube[0]); glVertex3fv(cube[1]); glVertex3fv(cube[2]); glVertex3fv(cube[3]); - glVertex3fv(cube[0]); glVertex3fv(cube[4]); glVertex3fv(cube[5]); glVertex3fv(cube[6]); - glVertex3fv(cube[7]); glVertex3fv(cube[4]); - glEnd(); - - glBegin(GL_LINES); - glVertex3fv(cube[1]); glVertex3fv(cube[5]); - glVertex3fv(cube[2]); glVertex3fv(cube[6]); - glVertex3fv(cube[3]); glVertex3fv(cube[7]); - glEnd(); - - glEndList(); + static VertexFormat format = {0}; + static VertexBuffer vbo = {0}; + static ElementListBuilder elb = {0}; + static ElementList el = {0}; + static Batch batch = {0}; + + if (format.attrib_ct == 0) { + /* Vertex format */ + unsigned int pos = add_attrib(&format, "pos", GL_FLOAT, 3, KEEP_FLOAT); + + /* Elements */ + ElementListBuilder_init(&elb, GL_LINES, 12, 8); + for (int i = 0; i < 12; ++i) { + add_line_vertices(&elb, cube_wire[i*2], cube_wire[i*2+1]); + } + ElementList_build_in_place(&elb, &el); + + /* Vertices */ + VertexBuffer_init_with_format(&vbo, &format); + VertexBuffer_allocate_data(&vbo, 8); + for (int i = 0; i < 8; ++i) { + setAttrib(&vbo, pos, i, cube_vert[i]); + } + + Batch_init(&batch, GL_LINES, &vbo, &el); + Batch_set_builtin_program(&batch, GPU_SHADER_3D_UNIFORM_COLOR); } - glScalef(xsize, ysize, zsize); - glCallList(displist); - + gpuMatrixBegin3D_legacy(); + gpuScale3f(xsize, ysize, zsize); + + Batch_use_program(&batch); + Batch_Uniform4fv(&batch, "color", fcolor); + Batch_draw(&batch); + + gpuMatrixEnd(); } static void draw_bonevert(void) { - static GLuint displist = 0; - - if (displist == 0) { - GLUquadricObj *qobj; - - displist = glGenLists(1); - glNewList(displist, GL_COMPILE); - - glPushMatrix(); - - qobj = gluNewQuadric(); - gluQuadricDrawStyle(qobj, GLU_SILHOUETTE); - gluDisk(qobj, 0.0, 0.05, 16, 1); - - glRotatef(90, 0, 1, 0); - gluDisk(qobj, 0.0, 0.05, 16, 1); - - glRotatef(90, 1, 0, 0); - gluDisk(qobj, 0.0, 0.05, 16, 1); - - gluDeleteQuadric(qobj); - - glPopMatrix(); - glEndList(); + static VertexFormat format = {0}; + static VertexBuffer vbo = {0}; + static Batch batch = {0}; + + if (format.attrib_ct == 0) { + /* Vertex format */ + unsigned int pos = add_attrib(&format, "pos", GL_FLOAT, 3, KEEP_FLOAT); + + /* Vertices */ + VertexBuffer_init_with_format(&vbo, &format); + VertexBuffer_allocate_data(&vbo, 96); + for (int i = 0; i < 16; ++i) { + float vert[3] = {0.f, 0.f, 0.f}; + const float r = 0.05f; + + vert[0] = r * cosf(2 * M_PI * i / 16.f); + vert[1] = r * sinf(2 * M_PI * i / 16.f); + setAttrib(&vbo, pos, i * 6 + 0, vert); + vert[0] = r * cosf(2 * M_PI * (i + 1) / 16.f); + vert[1] = r * sinf(2 * M_PI * (i + 1) / 16.f); + setAttrib(&vbo, pos, i * 6 + 1, vert); + + vert[0] = 0.f; + vert[1] = r * cosf(2 * M_PI * i / 16.f); + vert[2] = r * sinf(2 * M_PI * i / 16.f); + setAttrib(&vbo, pos, i * 6 + 2, vert); + vert[1] = r * cosf(2 * M_PI * (i + 1) / 16.f); + vert[2] = r * sinf(2 * M_PI * (i + 1) / 16.f); + setAttrib(&vbo, pos, i * 6 + 3, vert); + + vert[1] = 0.f; + vert[0] = r * cosf(2 * M_PI * i / 16.f); + vert[2] = r * sinf(2 * M_PI * i / 16.f); + setAttrib(&vbo, pos, i * 6 + 4, vert); + vert[0] = r * cosf(2 * M_PI * (i + 1) / 16.f); + vert[2] = r * sinf(2 * M_PI * (i + 1) / 16.f); + setAttrib(&vbo, pos, i * 6 + 5, vert); + } + + Batch_init(&batch, GL_LINES, &vbo, NULL); + Batch_set_builtin_program(&batch, GPU_SHADER_3D_UNIFORM_COLOR); } - glCallList(displist); + gpuMatrixBegin3D_legacy(); + + Batch_use_program(&batch); + Batch_Uniform4fv(&batch, "color", fcolor); + Batch_draw(&batch); + + gpuMatrixEnd(); } static void draw_bonevert_solid(void) { - static GLuint displist = 0; - - if (displist == 0) { - GLUquadricObj *qobj; - - displist = glGenLists(1); - glNewList(displist, GL_COMPILE); - - qobj = gluNewQuadric(); - gluQuadricDrawStyle(qobj, GLU_FILL); - /* Draw tips of a bone */ - gluSphere(qobj, 0.05, 8, 5); - gluDeleteQuadric(qobj); - - glEndList(); + Batch *batch = Batch_get_sphere(0); + const float light_vec[3] = {0.0f, 0.0f, 1.0f}; + + gpuMatrixBegin3D_legacy(); + + gpuScale3f(0.05, 0.05, 0.05); + + if (flat_color) { + Batch_set_builtin_program(batch, GPU_SHADER_3D_UNIFORM_COLOR); + } + else { + /* TODO replace with good default lighting shader ? */ + Batch_set_builtin_program(batch, GPU_SHADER_SIMPLE_LIGHTING); + Batch_Uniform3fv(batch, "light", light_vec); } + Batch_Uniform4fv(batch, "color", fcolor); + Batch_draw(batch); - glCallList(displist); + gpuMatrixEnd(); } static const float bone_octahedral_verts[6][3] = { @@ -451,8 +549,11 @@ static const float bone_octahedral_verts[6][3] = { { 0.0f, 1.0f, 0.0f} }; -static const unsigned int bone_octahedral_wire_sides[8] = {0, 1, 5, 3, 0, 4, 5, 2}; -static const unsigned int bone_octahedral_wire_square[8] = {1, 2, 3, 4, 1}; +static const unsigned int bone_octahedral_wire[24] = { + 0, 1, 1, 5, 5, 3, 3, 0, + 0, 4, 4, 5, 5, 2, 2, 0, + 1, 2, 2, 3, 3, 4, 4, 1, +}; static const unsigned int bone_octahedral_solid_tris[8][3] = { {2, 1, 0}, /* bottom */ @@ -480,69 +581,85 @@ static const float bone_octahedral_solid_normals[8][3] = { static void draw_bone_octahedral(void) { - static GLuint displist = 0; - - if (displist == 0) { - displist = glGenLists(1); - glNewList(displist, GL_COMPILE); - - /* Section 1, sides */ - glEnableClientState(GL_VERTEX_ARRAY); - glVertexPointer(3, GL_FLOAT, 0, bone_octahedral_verts); - glDrawElements(GL_LINE_LOOP, - sizeof(bone_octahedral_wire_sides) / sizeof(*bone_octahedral_wire_sides), - GL_UNSIGNED_INT, - bone_octahedral_wire_sides); - - /* Section 1, square */ - glDrawElements(GL_LINE_LOOP, - sizeof(bone_octahedral_wire_square) / sizeof(*bone_octahedral_wire_square), - GL_UNSIGNED_INT, - bone_octahedral_wire_square); - glDisableClientState(GL_VERTEX_ARRAY); - - glEndList(); + static VertexFormat format = {0}; + static VertexBuffer vbo = {0}; + static ElementListBuilder elb = {0}; + static ElementList el = {0}; + static Batch batch = {0}; + + if (format.attrib_ct == 0) { + /* Vertex format */ + unsigned int pos = add_attrib(&format, "pos", GL_FLOAT, 3, KEEP_FLOAT); + + /* Elements */ + ElementListBuilder_init(&elb, GL_LINES, 12, 6); + for (int i = 0; i < 12; ++i) { + add_line_vertices(&elb, bone_octahedral_wire[i*2], bone_octahedral_wire[i*2+1]); + } + ElementList_build_in_place(&elb, &el); + + /* Vertices */ + VertexBuffer_init_with_format(&vbo, &format); + VertexBuffer_allocate_data(&vbo, 6); + for (int i = 0; i < 6; ++i) { + setAttrib(&vbo, pos, i, bone_octahedral_verts[i]); + } + + Batch_init(&batch, GL_LINES, &vbo, &el); + Batch_set_builtin_program(&batch, GPU_SHADER_3D_UNIFORM_COLOR); } - glCallList(displist); + gpuMatrixBegin3D_legacy(); + + Batch_use_program(&batch); + Batch_Uniform4fv(&batch, "color", fcolor); + Batch_draw(&batch); + + gpuMatrixEnd(); } static void draw_bone_solid_octahedral(void) { - static GLuint displist = 0; - - if (displist == 0) { - int i; - - displist = glGenLists(1); - glNewList(displist, GL_COMPILE); - -#if 1 - glBegin(GL_TRIANGLES); - for (i = 0; i < 8; i++) { - glNormal3fv(bone_octahedral_solid_normals[i]); - glVertex3fv(bone_octahedral_verts[bone_octahedral_solid_tris[i][0]]); - glVertex3fv(bone_octahedral_verts[bone_octahedral_solid_tris[i][1]]); - glVertex3fv(bone_octahedral_verts[bone_octahedral_solid_tris[i][2]]); - } - - glEnd(); - -#else /* not working because each vert needs a different normal */ - glEnableClientState(GL_NORMAL_ARRAY); - glEnableClientState(GL_VERTEX_ARRAY); - glNormalPointer(GL_FLOAT, 0, bone_octahedral_solid_normals); - glVertexPointer(3, GL_FLOAT, 0, bone_octahedral_verts); - glDrawElements(GL_TRIANGLES, sizeof(bone_octahedral_solid_tris) / sizeof(unsigned int), - GL_UNSIGNED_INT, bone_octahedral_solid_tris); - glDisableClientState(GL_NORMAL_ARRAY); - glDisableClientState(GL_VERTEX_ARRAY); -#endif + static VertexFormat format = {0}; + static VertexBuffer vbo = {0}; + static Batch batch = {0}; + const float light_vec[3] = {0.0f, 0.0f, 1.0f}; + + if (format.attrib_ct == 0) { + unsigned int v_idx = 0; + /* Vertex format */ + unsigned int pos = add_attrib(&format, "pos", GL_FLOAT, 3, KEEP_FLOAT); + unsigned int nor = add_attrib(&format, "nor", GL_FLOAT, 3, KEEP_FLOAT); + + /* Vertices */ + VertexBuffer_init_with_format(&vbo, &format); + VertexBuffer_allocate_data(&vbo, 24); + + for (int i = 0; i < 8; i++) { + add_solid_flat_triangle(&vbo, &v_idx, pos, nor, + bone_octahedral_verts[bone_octahedral_solid_tris[i][0]], + bone_octahedral_verts[bone_octahedral_solid_tris[i][1]], + bone_octahedral_verts[bone_octahedral_solid_tris[i][2]], + bone_octahedral_solid_normals[i]); + } - glEndList(); + Batch_init(&batch, GL_TRIANGLES, &vbo, NULL); + } + + gpuMatrixBegin3D_legacy(); + + if (flat_color) { + Batch_set_builtin_program(&batch, GPU_SHADER_3D_UNIFORM_COLOR); + } + else { + /* TODO replace with good default lighting shader ? */ + Batch_set_builtin_program(&batch, GPU_SHADER_SIMPLE_LIGHTING); + Batch_Uniform3fv(&batch, "light", light_vec); } + Batch_Uniform4fv(&batch, "color", fcolor); + Batch_draw(&batch); - glCallList(displist); + gpuMatrixEnd(); } /* *************** Armature drawing, bones ******************* */ @@ -557,15 +674,20 @@ static void draw_bone_points(const short dt, int armflag, unsigned int boneflag, if (dt <= OB_WIRE) { if (armflag & ARM_EDITMODE) { - if (boneflag & BONE_ROOTSEL) UI_ThemeColor(TH_VERTEX_SELECT); - else UI_ThemeColor(TH_VERTEX); + if (boneflag & BONE_ROOTSEL) { + UI_GetThemeColor4fv(TH_VERTEX_SELECT, fcolor); + } + else { + UI_GetThemeColor4fv(TH_VERTEX, fcolor); + } } } else { if (armflag & ARM_POSEMODE) - set_pchan_glColor(PCHAN_COLOR_SOLID, boneflag, 0); - else - UI_ThemeColor(TH_BONE_SOLID); + set_pchan_color(PCHAN_COLOR_SOLID, boneflag, 0); + else { + UI_GetThemeColor4fv(TH_BONE_SOLID, fcolor); + } } if (dt > OB_WIRE) @@ -580,15 +702,20 @@ static void draw_bone_points(const short dt, int armflag, unsigned int boneflag, if (dt <= OB_WIRE) { if (armflag & ARM_EDITMODE) { - if (boneflag & BONE_TIPSEL) UI_ThemeColor(TH_VERTEX_SELECT); - else UI_ThemeColor(TH_VERTEX); + if (boneflag & BONE_TIPSEL) { + UI_GetThemeColor4fv(TH_VERTEX_SELECT, fcolor); + } + else { + UI_GetThemeColor4fv(TH_VERTEX, fcolor); + } } } else { if (armflag & ARM_POSEMODE) - set_pchan_glColor(PCHAN_COLOR_SOLID, boneflag, 0); - else - UI_ThemeColor(TH_BONE_SOLID); + set_pchan_color(PCHAN_COLOR_SOLID, boneflag, 0); + else { + UI_GetThemeColor4fv(TH_BONE_SOLID, fcolor); + } } glTranslatef(0.0f, 1.0f, 0.0f); @@ -696,8 +823,13 @@ static void draw_sphere_bone_dist(float smat[4][4], float imat[4][4], bPoseChann //mul_v3_fl(dirvec, head); cross_v3_v3v3(norvec, dirvec, imat[2]); - - glBegin(GL_QUAD_STRIP); + + VertexFormat *format = immVertexFormat(); + unsigned pos = add_attrib(format, "pos", GL_FLOAT, 3, KEEP_FLOAT); + + immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR); + immBegin(GL_TRIANGLE_STRIP, 66); + immUniformColor4ub(255, 255, 255, 50); for (a = 0; a < 16; a++) { vec[0] = -si[a] * dirvec[0] + co[a] * norvec[0]; @@ -707,10 +839,8 @@ static void draw_sphere_bone_dist(float smat[4][4], float imat[4][4], bPoseChann madd_v3_v3v3fl(vec1, headvec, vec, head); madd_v3_v3v3fl(vec2, headvec, vec, head + dist); - glColor4ub(255, 255, 255, 50); - glVertex3fv(vec1); - //glColor4ub(255, 255, 255, 0); - glVertex3fv(vec2); + immVertex3fv(pos, vec1); + immVertex3fv(pos, vec2); } for (a = 15; a >= 0; a--) { @@ -721,10 +851,8 @@ static void draw_sphere_bone_dist(float smat[4][4], float imat[4][4], bPoseChann madd_v3_v3v3fl(vec1, tailvec, vec, tail); madd_v3_v3v3fl(vec2, tailvec, vec, tail + dist); - //glColor4ub(255, 255, 255, 50); - glVertex3fv(vec1); - //glColor4ub(255, 255, 255, 0); - glVertex3fv(vec2); + immVertex3fv(pos, vec1); + immVertex3fv(pos, vec2); } /* make it cyclic... */ @@ -735,12 +863,11 @@ static void draw_sphere_bone_dist(float smat[4][4], float imat[4][4], bPoseChann madd_v3_v3v3fl(vec1, headvec, vec, head); madd_v3_v3v3fl(vec2, headvec, vec, head + dist); - //glColor4ub(255, 255, 255, 50); - glVertex3fv(vec1); - //glColor4ub(255, 255, 255, 0); - glVertex3fv(vec2); + immVertex3fv(pos, vec1); + immVertex3fv(pos, vec2); - glEnd(); + immEnd(); + immUnbindProgram(); } } @@ -752,6 +879,11 @@ static void draw_sphere_bone_wire(float smat[4][4], float imat[4][4], { float head, tail /*, length*/; float *headvec, *tailvec, dirvec[3]; + + VertexFormat *format = immVertexFormat(); + unsigned int pos = add_attrib(format, "pos", GL_FLOAT, 3, KEEP_FLOAT); + + immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR); /* figure out the sizes of spheres */ if (ebone) { @@ -780,35 +912,49 @@ static void draw_sphere_bone_wire(float smat[4][4], float imat[4][4], /* sphere root color */ if (armflag & ARM_EDITMODE) { - if (boneflag & BONE_ROOTSEL) UI_ThemeColor(TH_VERTEX_SELECT); - else UI_ThemeColor(TH_VERTEX); + if (boneflag & BONE_ROOTSEL) { + UI_GetThemeColor4fv(TH_VERTEX_SELECT, fcolor); + } + else { + UI_GetThemeColor4fv(TH_VERTEX, fcolor); + } } else if (armflag & ARM_POSEMODE) - set_pchan_glColor(PCHAN_COLOR_NORMAL, boneflag, constflag); - + set_pchan_color(PCHAN_COLOR_NORMAL, boneflag, constflag); + + immUniformColor4fv(fcolor); + /* Draw root point if we are not connected */ if ((boneflag & BONE_CONNECTED) == 0) { if (id != -1) GPU_select_load_id(id | BONESEL_ROOT); - drawcircball(GL_LINE_LOOP, headvec, head, imat); + imm_drawcircball(headvec, head, imat, pos); } /* Draw tip point */ if (armflag & ARM_EDITMODE) { - if (boneflag & BONE_TIPSEL) UI_ThemeColor(TH_VERTEX_SELECT); - else UI_ThemeColor(TH_VERTEX); + if (boneflag & BONE_TIPSEL) { + UI_GetThemeColor4fv(TH_VERTEX_SELECT, fcolor); + } + else { + UI_GetThemeColor4fv(TH_VERTEX, fcolor); + } } if (id != -1) GPU_select_load_id(id | BONESEL_TIP); - drawcircball(GL_LINE_LOOP, tailvec, tail, imat); + imm_drawcircball(tailvec, tail, imat, pos); /* base */ if (armflag & ARM_EDITMODE) { - if (boneflag & BONE_SELECTED) UI_ThemeColor(TH_SELECT); - else UI_ThemeColor(TH_WIRE_EDIT); + if (boneflag & BONE_SELECTED){ + UI_GetThemeColor4fv(TH_SELECT, fcolor); + } + else { + UI_GetThemeColor4fv(TH_WIRE_EDIT, fcolor); + } } sub_v3_v3v3(dirvec, tailvec, headvec); @@ -834,34 +980,41 @@ static void draw_sphere_bone_wire(float smat[4][4], float imat[4][4], if (id != -1) GPU_select_load_id(id | BONESEL_BONE); - glBegin(GL_LINES); + immBegin(GL_LINES, 4); add_v3_v3v3(vec, headvec, norvech); - glVertex3fv(vec); + immVertex3fv(pos, vec); add_v3_v3v3(vec, tailvec, norvect); - glVertex3fv(vec); + immVertex3fv(pos, vec); sub_v3_v3v3(vec, headvec, norvech); - glVertex3fv(vec); + immVertex3fv(pos, vec); sub_v3_v3v3(vec, tailvec, norvect); - glVertex3fv(vec); + immVertex3fv(pos, vec); - glEnd(); + immEnd(); } + + immUnbindProgram(); } /* does wire only for outline selecting */ static void draw_sphere_bone(const short dt, int armflag, int boneflag, short constflag, unsigned int id, bPoseChannel *pchan, EditBone *ebone) { - GLUquadricObj *qobj; + Batch *sphere = Batch_get_sphere(1); float head, tail, length; - float fac1, fac2; - - glPushMatrix(); - qobj = gluNewQuadric(); + float fac1, fac2, size1, size2; + const float light_vec[3] = {0.0f, 0.0f, 1.0f}; + + /* dt is always OB_SOlID */ + Batch_set_builtin_program(sphere, GPU_SHADER_SIMPLE_LIGHTING); + Batch_Uniform3fv(sphere, "light", light_vec); + + gpuMatrixBegin3D_legacy(); + gpuPushMatrix(); /* figure out the sizes of spheres */ if (ebone) { @@ -882,110 +1035,125 @@ static void draw_sphere_bone(const short dt, int armflag, int boneflag, short co } /* move to z-axis space */ - glRotatef(-90.0f, 1.0f, 0.0f, 0.0f); + gpuRotate3f(-90.0f, 1.0f, 0.0f, 0.0f); - if (dt == OB_SOLID) { - /* set up solid drawing */ - GPU_basic_shader_bind(GPU_SHADER_LIGHTING | GPU_SHADER_USE_COLOR); - - gluQuadricDrawStyle(qobj, GLU_FILL); - } - else { - gluQuadricDrawStyle(qobj, GLU_SILHOUETTE); - } - /* sphere root color */ if (armflag & ARM_EDITMODE) { - if (boneflag & BONE_ROOTSEL) UI_ThemeColor(TH_VERTEX_SELECT); - else UI_ThemeColorShade(TH_BONE_SOLID, -30); + if (boneflag & BONE_ROOTSEL) + UI_GetThemeColor4fv(TH_VERTEX_SELECT, fcolor); + else + UI_GetThemeColorShade4fv(TH_BONE_SOLID, -30, fcolor); } else if (armflag & ARM_POSEMODE) - set_pchan_glColor(PCHAN_COLOR_SPHEREBONE_END, boneflag, constflag); + set_pchan_color(PCHAN_COLOR_SPHEREBONE_END, boneflag, constflag); else if (dt == OB_SOLID) - UI_ThemeColorShade(TH_BONE_SOLID, -30); + UI_GetThemeColorShade4fv(TH_BONE_SOLID, -30, fcolor); /* Draw root point if we are not connected */ if ((boneflag & BONE_CONNECTED) == 0) { if (id != -1) GPU_select_load_id(id | BONESEL_ROOT); - gluSphere(qobj, head, 16, 10); + gpuPushMatrix(); + gpuScale3f(head, head, head); + Batch_Uniform4fv(sphere, "color", fcolor); + Batch_draw(sphere); + gpuPopMatrix(); } /* Draw tip point */ if (armflag & ARM_EDITMODE) { - if (boneflag & BONE_TIPSEL) UI_ThemeColor(TH_VERTEX_SELECT); - else UI_ThemeColorShade(TH_BONE_SOLID, -30); + if (boneflag & BONE_TIPSEL) UI_GetThemeColor4fv(TH_VERTEX_SELECT, fcolor); + else UI_GetThemeColorShade4fv(TH_BONE_SOLID, -30, fcolor); } if (id != -1) GPU_select_load_id(id | BONESEL_TIP); - glTranslatef(0.0f, 0.0f, length); - gluSphere(qobj, tail, 16, 10); - glTranslatef(0.0f, 0.0f, -length); + gpuTranslate3f(0.0f, 0.0f, length); + + gpuPushMatrix(); + gpuScale3f(tail, tail, tail); + Batch_use_program(sphere); /* hack to make the following uniforms stick */ + Batch_Uniform4fv(sphere, "color", fcolor); + Batch_draw(sphere); + gpuPopMatrix(); + + gpuTranslate3f(0.0f, 0.0f, -length); /* base */ if (armflag & ARM_EDITMODE) { - if (boneflag & BONE_SELECTED) UI_ThemeColor(TH_SELECT); - else UI_ThemeColor(TH_BONE_SOLID); + if (boneflag & BONE_SELECTED) UI_GetThemeColor4fv(TH_SELECT, fcolor); + else UI_GetThemeColor4fv(TH_BONE_SOLID, fcolor); } else if (armflag & ARM_POSEMODE) - set_pchan_glColor(PCHAN_COLOR_SPHEREBONE_BASE, boneflag, constflag); + set_pchan_color(PCHAN_COLOR_SPHEREBONE_BASE, boneflag, constflag); else if (dt == OB_SOLID) - UI_ThemeColor(TH_BONE_SOLID); + UI_GetThemeColor4fv(TH_BONE_SOLID, fcolor); + + Batch_use_program(sphere); /* hack to make the following uniforms stick */ + Batch_Uniform4fv(sphere, "color", fcolor); fac1 = (length - head) / length; fac2 = (length - tail) / length; if (length > (head + tail)) { + size1 = fac2 * tail + (1.0f - fac2) * head; + size2 = fac1 * head + (1.0f - fac1) * tail; + if (id != -1) GPU_select_load_id(id | BONESEL_BONE); + /* draw sphere on extrema */ + gpuPushMatrix(); + gpuTranslate3f(0.0f, 0.0f, length - tail); + gpuScale3f(size1, size1, size1); + + Batch_draw(sphere); + gpuPopMatrix(); + + gpuPushMatrix(); + gpuTranslate3f(0.0f, 0.0f, head); + gpuScale3f(size2, size2, size2); + + Batch_draw(sphere); + gpuPopMatrix(); + + /* draw cynlinder between spheres */ glEnable(GL_POLYGON_OFFSET_FILL); glPolygonOffset(-1.0f, -1.0f); - - glTranslatef(0.0f, 0.0f, head); - gluCylinder(qobj, fac1 * head + (1.0f - fac1) * tail, fac2 * tail + (1.0f - fac2) * head, length - head - tail, 16, 1); - glTranslatef(0.0f, 0.0f, -head); + + VertexFormat *format = immVertexFormat(); + unsigned int pos = add_attrib(format, "pos", GL_FLOAT, 3, KEEP_FLOAT); + unsigned int nor = add_attrib(format, "nor", GL_FLOAT, 3, KEEP_FLOAT); + + immBindBuiltinProgram(GPU_SHADER_SIMPLE_LIGHTING); + immUniformColor4fv(fcolor); + immUniform3fv("light", light_vec); + + gpuTranslate3f(0.0f, 0.0f, head); + imm_cylinder(pos, nor, size2, size1, length - head - tail, 16, 1); + + immUnbindProgram(); glDisable(GL_POLYGON_OFFSET_FILL); - - /* draw sphere on extrema */ - glTranslatef(0.0f, 0.0f, length - tail); - gluSphere(qobj, fac2 * tail + (1.0f - fac2) * head, 16, 10); - glTranslatef(0.0f, 0.0f, -length + tail); - - glTranslatef(0.0f, 0.0f, head); - gluSphere(qobj, fac1 * head + (1.0f - fac1) * tail, 16, 10); } else { + size1 = fac1 * head + (1.0f - fac1) * tail; + /* 1 sphere in center */ - glTranslatef(0.0f, 0.0f, (head + length - tail) / 2.0f); - gluSphere(qobj, fac1 * head + (1.0f - fac1) * tail, 16, 10); - } - - /* restore */ - if (dt == OB_SOLID) { - GPU_basic_shader_bind(GPU_SHADER_USE_COLOR); + gpuTranslate3f(0.0f, 0.0f, (head + length - tail) / 2.0f); + + gpuScale3f(size1, size1, size1); + Batch_draw(sphere); } - glPopMatrix(); - gluDeleteQuadric(qobj); + gpuPopMatrix(); + gpuMatrixEnd(); } -static GLubyte bm_dot6[] = {0x0, 0x18, 0x3C, 0x7E, 0x7E, 0x3C, 0x18, 0x0}; -static GLubyte bm_dot8[] = {0x3C, 0x7E, 0xFF, 0xFF, 0xFF, 0xFF, 0x7E, 0x3C}; - -static GLubyte bm_dot5[] = {0x0, 0x0, 0x10, 0x38, 0x7c, 0x38, 0x10, 0x0}; -static GLubyte bm_dot7[] = {0x0, 0x38, 0x7C, 0xFE, 0xFE, 0xFE, 0x7C, 0x38}; - - static void draw_line_bone(int armflag, int boneflag, short constflag, unsigned int id, bPoseChannel *pchan, EditBone *ebone) { - /* call this once, avoid constant changing */ - BLI_assert(glaGetOneInt(GL_UNPACK_ALIGNMENT) == 1); - float length; if (pchan) @@ -993,103 +1161,121 @@ static void draw_line_bone(int armflag, int boneflag, short constflag, unsigned else length = ebone->length; - glPushMatrix(); - glScalef(length, length, length); + VertexFormat *format = immVertexFormat(); + unsigned int pos = add_attrib(format, "pos", GL_FLOAT, 3, KEEP_FLOAT); + + gpuMatrixBegin3D_legacy(); + gpuPushMatrix(); + gpuScale3f(length, length, length); /* this chunk not in object mode */ if (armflag & (ARM_EDITMODE | ARM_POSEMODE)) { glLineWidth(4.0f); - if (G.f & G_PICKSEL) { - /* no bitmap in selection mode, crashes 3d cards... - * instead draw a solid point the same size */ - glPointSize(8.0f); - } + glPointSize(8.0f); if (armflag & ARM_POSEMODE) - set_pchan_glColor(PCHAN_COLOR_NORMAL, boneflag, constflag); + set_pchan_color(PCHAN_COLOR_NORMAL, boneflag, constflag); else if (armflag & ARM_EDITMODE) { - UI_ThemeColor(TH_WIRE_EDIT); + UI_GetThemeColor4fv(TH_WIRE_EDIT, fcolor); } - + + /* line */ + immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR); + immUniformColor4fv(fcolor); + + if (id != -1) + GPU_select_load_id(id | BONESEL_BONE); + + immBegin(GL_LINES, 2); + immVertex3f(pos, 0.0f, 1.0f, 0.0f); + immVertex3f(pos, 0.0f, 0.0f, 0.0f); + immEnd(); + + immUnbindProgram(); + + immBindBuiltinProgram(GPU_SHADER_3D_POINT_FIXED_SIZE_UNIFORM_COLOR); + immUniformColor4fv(fcolor); + /* Draw root point if we are not connected */ if ((boneflag & BONE_CONNECTED) == 0) { - if (G.f & G_PICKSEL) { + if (G.f & G_PICKSEL) GPU_select_load_id(id | BONESEL_ROOT); - glBegin(GL_POINTS); - glVertex3f(0.0f, 0.0f, 0.0f); - glEnd(); - } - else { - glRasterPos3f(0.0f, 0.0f, 0.0f); - glBitmap(8, 8, 4, 4, 0, 0, bm_dot8); - } + + immBegin(GL_POINTS, 1); + immVertex3f(pos, 0.0f, 0.0f, 0.0f); + immEnd(); } - - if (id != -1) - GPU_select_load_id((GLuint) id | BONESEL_BONE); - - glBegin(GL_LINES); - glVertex3f(0.0f, 0.0f, 0.0f); - glVertex3f(0.0f, 1.0f, 0.0f); - glEnd(); - + /* tip */ - if (G.f & G_PICKSEL) { - /* no bitmap in selection mode, crashes 3d cards... */ + if (G.f & G_PICKSEL) GPU_select_load_id(id | BONESEL_TIP); - glBegin(GL_POINTS); - glVertex3f(0.0f, 1.0f, 0.0f); - glEnd(); - } - else { - glRasterPos3f(0.0f, 1.0f, 0.0f); - glBitmap(8, 8, 4, 4, 0, 0, bm_dot7); - } - + + immBegin(GL_POINTS, 1); + immVertex3f(pos, 0.0f, 1.0f, 0.0f); + immEnd(); + + immUnbindProgram(); + + /* further we send no names */ if (id != -1) GPU_select_load_id(id & 0xFFFF); /* object tag, for bordersel optim */ if (armflag & ARM_POSEMODE) - set_pchan_glColor(PCHAN_COLOR_LINEBONE, boneflag, constflag); + set_pchan_color(PCHAN_COLOR_LINEBONE, boneflag, constflag); } - - glLineWidth(2.0); - + + /* Now draw the inner color */ + glLineWidth(2.0f); + glPointSize(5.0f); + + /* line */ + if (armflag & ARM_EDITMODE) { + if (boneflag & BONE_SELECTED) UI_GetThemeColor4fv(TH_EDGE_SELECT, fcolor); + else UI_GetThemeColorShade4fv(TH_BACK, -30, fcolor); + } + + immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR); + immUniformColor4fv(fcolor); + + immBegin(GL_LINES, 2); + immVertex3f(pos, 0.0f, 1.0f, 0.0f); + immVertex3f(pos, 0.0f, 0.0f, 0.0f); + immEnd(); + + immUnbindProgram(); + + immBindBuiltinProgram(GPU_SHADER_3D_POINT_FIXED_SIZE_UNIFORM_COLOR); + /*Draw root point if we are not connected */ if ((boneflag & BONE_CONNECTED) == 0) { - if ((G.f & G_PICKSEL) == 0) { - /* no bitmap in selection mode, crashes 3d cards... */ - if (armflag & ARM_EDITMODE) { - if (boneflag & BONE_ROOTSEL) UI_ThemeColor(TH_VERTEX_SELECT); - else UI_ThemeColor(TH_VERTEX); - } - glRasterPos3f(0.0f, 0.0f, 0.0f); - glBitmap(8, 8, 4, 4, 0, 0, bm_dot6); + if (armflag & ARM_EDITMODE) { + if (boneflag & BONE_ROOTSEL) UI_GetThemeColor4fv(TH_VERTEX_SELECT, fcolor); + else UI_GetThemeColor4fv(TH_VERTEX, fcolor); } + immUniformColor4fv(fcolor); + immBegin(GL_POINTS, 1); + immVertex3f(pos, 0.0f, 0.0f, 0.0f); + immEnd(); } - - if (armflag & ARM_EDITMODE) { - if (boneflag & BONE_SELECTED) UI_ThemeColor(TH_EDGE_SELECT); - else UI_ThemeColorShade(TH_BACK, -30); - } - glBegin(GL_LINES); - glVertex3f(0.0f, 0.0f, 0.0f); - glVertex3f(0.0f, 1.0f, 0.0f); - glEnd(); - + /* tip */ if ((G.f & G_PICKSEL) == 0) { /* no bitmap in selection mode, crashes 3d cards... */ if (armflag & ARM_EDITMODE) { - if (boneflag & BONE_TIPSEL) UI_ThemeColor(TH_VERTEX_SELECT); - else UI_ThemeColor(TH_VERTEX); + if (boneflag & BONE_TIPSEL) UI_GetThemeColor4fv(TH_VERTEX_SELECT, fcolor); + else UI_GetThemeColor4fv(TH_VERTEX, fcolor); } - glRasterPos3f(0.0f, 1.0f, 0.0f); - glBitmap(8, 8, 4, 4, 0, 0, bm_dot5); + immUniformColor4fv(fcolor); + immBegin(GL_POINTS, 1); + immVertex3f(pos, 0.0f, 1.0f, 0.0f); + immEnd(); } - - glPopMatrix(); + + immUnbindProgram(); + + gpuPopMatrix(); + gpuMatrixEnd(); } /* A partial copy of b_bone_spline_setup(), with just the parts for previewing editmode curve settings @@ -1232,16 +1418,17 @@ static void draw_b_bone(const short dt, int armflag, int boneflag, short constfl /* colors for modes */ if (armflag & ARM_POSEMODE) { if (dt <= OB_WIRE) - set_pchan_glColor(PCHAN_COLOR_NORMAL, boneflag, constflag); + set_pchan_color(PCHAN_COLOR_NORMAL, boneflag, constflag); else - set_pchan_glColor(PCHAN_COLOR_SOLID, boneflag, constflag); + set_pchan_color(PCHAN_COLOR_SOLID, boneflag, constflag); } else if (armflag & ARM_EDITMODE) { if (dt == OB_WIRE) { - set_ebone_glColor(boneflag); + set_ebone_color(boneflag); + } + else { + UI_GetThemeColor4fv(TH_BONE_SOLID, fcolor); } - else - UI_ThemeColor(TH_BONE_SOLID); } if (id != -1) { @@ -1250,33 +1437,31 @@ static void draw_b_bone(const short dt, int armflag, int boneflag, short constfl /* set up solid drawing */ if (dt > OB_WIRE) { - GPU_basic_shader_bind(GPU_SHADER_LIGHTING | GPU_SHADER_USE_COLOR); - if (armflag & ARM_POSEMODE) - set_pchan_glColor(PCHAN_COLOR_SOLID, boneflag, constflag); - else - UI_ThemeColor(TH_BONE_SOLID); + set_pchan_color(PCHAN_COLOR_SOLID, boneflag, constflag); + else { + UI_GetThemeColor4fv(TH_BONE_SOLID, fcolor); + } + flat_color = false; draw_b_bone_boxes(OB_SOLID, pchan, ebone, xwidth, length, zwidth); - - /* disable solid drawing */ - GPU_basic_shader_bind(GPU_SHADER_USE_COLOR); } else { /* wire */ if (armflag & ARM_POSEMODE) { if (constflag) { /* set constraint colors */ - if (set_pchan_glColor(PCHAN_COLOR_CONSTS, boneflag, constflag)) { + if (set_pchan_color(PCHAN_COLOR_CONSTS, boneflag, constflag)) { glEnable(GL_BLEND); + flat_color = true; draw_b_bone_boxes(OB_SOLID, pchan, ebone, xwidth, length, zwidth); glDisable(GL_BLEND); } /* restore colors */ - set_pchan_glColor(PCHAN_COLOR_NORMAL, boneflag, constflag); + set_pchan_color(PCHAN_COLOR_NORMAL, boneflag, constflag); } } @@ -1286,33 +1471,45 @@ static void draw_b_bone(const short dt, int armflag, int boneflag, short constfl static void draw_wire_bone_segments(bPoseChannel *pchan, Mat4 *bbones, float length, int segments) { + VertexFormat *format = immVertexFormat(); + unsigned int pos = add_attrib(format, "pos", GL_FLOAT, 3, KEEP_FLOAT); + + immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR); + immUniformColor4fv(fcolor); + + gpuMatrixBegin3D_legacy(); + if ((segments > 1) && (pchan)) { float dlen = length / (float)segments; Mat4 *bbone = bbones; int a; - + for (a = 0; a < segments; a++, bbone++) { - glPushMatrix(); - glMultMatrixf(bbone->mat); - - glBegin(GL_LINES); - glVertex3f(0.0f, 0.0f, 0.0f); - glVertex3f(0.0f, dlen, 0.0f); - glEnd(); /* GL_LINES */ - - glPopMatrix(); + gpuPushMatrix(); + gpuMultMatrix3D(bbone->mat); + + immBegin(GL_LINES, 2); + immVertex3f(pos, 0.0f, 0.0f, 0.0f); + immVertex3f(pos, 0.0f, dlen, 0.0f); + immEnd(); + + gpuPopMatrix(); } } else { - glPushMatrix(); - - glBegin(GL_LINES); - glVertex3f(0.0f, 0.0f, 0.0f); - glVertex3f(0.0f, length, 0.0f); - glEnd(); - - glPopMatrix(); + gpuPushMatrix(); + + immBegin(GL_LINES, 2); + immVertex3f(pos, 0.0f, 0.0f, 0.0f); + immVertex3f(pos, 0.0f, length, 0.0f); + immEnd(); + + gpuPopMatrix(); } + + gpuMatrixEnd(); + + immUnbindProgram(); } static void draw_wire_bone(const short dt, int armflag, int boneflag, short constflag, unsigned int id, @@ -1340,6 +1537,7 @@ static void draw_wire_bone(const short dt, int armflag, int boneflag, short cons /* move to unitspace */ glPushMatrix(); glScalef(length, length, length); + flat_color = true; draw_bone_points(dt, armflag, boneflag, id); glPopMatrix(); length *= 0.95f; /* make vertices visible */ @@ -1359,10 +1557,10 @@ static void draw_wire_bone(const short dt, int armflag, int boneflag, short cons /* colors for modes */ if (armflag & ARM_POSEMODE) { - set_pchan_glColor(PCHAN_COLOR_NORMAL, boneflag, constflag); + set_pchan_color(PCHAN_COLOR_NORMAL, boneflag, constflag); } else if (armflag & ARM_EDITMODE) { - set_ebone_glColor(boneflag); + set_ebone_color(boneflag); } /* draw normal */ @@ -1372,23 +1570,23 @@ static void draw_wire_bone(const short dt, int armflag, int boneflag, short cons static void draw_bone(const short dt, int armflag, int boneflag, short constflag, unsigned int id, float length) { - /* Draw a 3d octahedral bone, we use normalized space based on length, - * for display-lists */ - + /* Draw a 3d octahedral bone, we use normalized space based on length */ glScalef(length, length, length); /* set up solid drawing */ if (dt > OB_WIRE) { - GPU_basic_shader_bind(GPU_SHADER_LIGHTING | GPU_SHADER_USE_COLOR); - UI_ThemeColor(TH_BONE_SOLID); + UI_GetThemeColor4fv(TH_BONE_SOLID, fcolor); + flat_color = false; } + else + flat_color = true; /* colors for posemode */ if (armflag & ARM_POSEMODE) { if (dt <= OB_WIRE) - set_pchan_glColor(PCHAN_COLOR_NORMAL, boneflag, constflag); + set_pchan_color(PCHAN_COLOR_NORMAL, boneflag, constflag); else - set_pchan_glColor(PCHAN_COLOR_SOLID, boneflag, constflag); + set_pchan_color(PCHAN_COLOR_SOLID, boneflag, constflag); } @@ -1403,12 +1601,12 @@ static void draw_bone(const short dt, int armflag, int boneflag, short constflag if (dt <= OB_WIRE) { /* colors */ if (armflag & ARM_EDITMODE) { - set_ebone_glColor(boneflag); + set_ebone_color(boneflag); } else if (armflag & ARM_POSEMODE) { if (constflag) { /* draw constraint colors */ - if (set_pchan_glColor(PCHAN_COLOR_CONSTS, boneflag, constflag)) { + if (set_pchan_color(PCHAN_COLOR_CONSTS, boneflag, constflag)) { glEnable(GL_BLEND); draw_bone_solid_octahedral(); @@ -1417,7 +1615,7 @@ static void draw_bone(const short dt, int armflag, int boneflag, short constflag } /* restore colors */ - set_pchan_glColor(PCHAN_COLOR_NORMAL, boneflag, constflag); + set_pchan_color(PCHAN_COLOR_NORMAL, boneflag, constflag); } } draw_bone_octahedral(); @@ -1425,15 +1623,11 @@ static void draw_bone(const short dt, int armflag, int boneflag, short constflag else { /* solid */ if (armflag & ARM_POSEMODE) - set_pchan_glColor(PCHAN_COLOR_SOLID, boneflag, constflag); + set_pchan_color(PCHAN_COLOR_SOLID, boneflag, constflag); else - UI_ThemeColor(TH_BONE_SOLID); - draw_bone_solid_octahedral(); - } + UI_GetThemeColor4fv(TH_BONE_SOLID, fcolor); - /* disable solid drawing */ - if (dt > OB_WIRE) { - GPU_basic_shader_bind(GPU_SHADER_USE_COLOR); + draw_bone_solid_octahedral(); } } @@ -1446,14 +1640,14 @@ static void draw_custom_bone(Scene *scene, View3D *v3d, RegionView3D *rv3d, Obje /* colors for posemode */ if (armflag & ARM_POSEMODE) { - set_pchan_glColor(PCHAN_COLOR_NORMAL, boneflag, 0); + set_pchan_color(PCHAN_COLOR_NORMAL, boneflag, 0); } if (id != -1) { GPU_select_load_id((GLuint) id | BONESEL_BONE); } - - draw_object_instance(scene, v3d, rv3d, ob, dt, armflag & ARM_POSEMODE); + + draw_object_instance(scene, v3d, rv3d, ob, dt, armflag & ARM_POSEMODE, fcolor); } @@ -1461,7 +1655,14 @@ static void pchan_draw_IK_root_lines(bPoseChannel *pchan, short only_temp) { bConstraint *con; bPoseChannel *parchan; - + + VertexFormat *format = immVertexFormat(); + unsigned int pos = add_attrib(format, "pos", GL_FLOAT, 3, KEEP_FLOAT); + + immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR); + immUniformColor4fv(fcolor); + + setlinestyle(3); for (con = pchan->constraints.first; con; con = con->next) { if (con->enforce == 0.0f) continue; @@ -1471,47 +1672,45 @@ static void pchan_draw_IK_root_lines(bPoseChannel *pchan, short only_temp) { bKinematicConstraint *data = (bKinematicConstraint *)con->data; int segcount = 0; + float ik_tip[3]; /* if only_temp, only draw if it is a temporary ik-chain */ if ((only_temp) && !(data->flag & CONSTRAINT_IK_TEMP)) continue; - - setlinestyle(3); - glBegin(GL_LINES); - + /* exclude tip from chain? */ if ((data->flag & CONSTRAINT_IK_TIP) == 0) parchan = pchan->parent; else parchan = pchan; - glVertex3fv(parchan->pose_tail); + copy_v3_v3(ik_tip, parchan->pose_tail); /* Find the chain's root */ while (parchan->parent) { segcount++; - if (segcount == data->rootbone || segcount > 255) { - break; /* 255 is weak */ - } + /* FIXME: revise the breaking conditions */ + if (segcount == data->rootbone || segcount > 255) break; /* 255 is weak */ parchan = parchan->parent; } - if (parchan) - glVertex3fv(parchan->pose_head); + + if (parchan) { + immBegin(GL_LINES, 2); + immVertex3fv(pos, ik_tip); + immVertex3fv(pos, parchan->pose_head); + immEnd(); + } - glEnd(); - setlinestyle(0); break; } case CONSTRAINT_TYPE_SPLINEIK: { bSplineIKConstraint *data = (bSplineIKConstraint *)con->data; int segcount = 0; - - setlinestyle(3); - glBegin(GL_LINES); + float ik_tip[3]; parchan = pchan; - glVertex3fv(parchan->pose_tail); + copy_v3_v3(ik_tip, parchan->pose_tail); /* Find the chain's root */ while (parchan->parent) { @@ -1521,18 +1720,21 @@ static void pchan_draw_IK_root_lines(bPoseChannel *pchan, short only_temp) parchan = parchan->parent; } /* Only draw line in case our chain is more than one bone long! */ - if (parchan != pchan) /* XXX revise the breaking conditions to only stop at the tail? */ - glVertex3fv(parchan->pose_head); - - glEnd(); - setlinestyle(0); + if (parchan != pchan) { /* XXX revise the breaking conditions to only stop at the tail? */ + immBegin(GL_LINES, 2); + immVertex3fv(pos, ik_tip); + immVertex3fv(pos, parchan->pose_head); + immEnd(); + } break; } } } + setlinestyle(0); + immUnbindProgram(); } -static void bgl_sphere_project(float ax, float az) +static void imm_sphere_project(unsigned int pos, float ax, float az) { float dir[3], sine, q3; @@ -1543,11 +1745,13 @@ static void bgl_sphere_project(float ax, float az) dir[1] = 1.0f - 2.0f * sine; dir[2] = ax * q3; - glVertex3fv(dir); + immVertex3fv(pos, dir); } -static void draw_dof_ellipse(float ax, float az) +static void draw_dof_ellipse(unsigned int pos, float ax, float az) { + const int n = 16; + const int tri = n*n - 2*n + 1; /* Yay fancy math ! */ const float staticSine[16] = { 0.0f, 0.104528463268f, 0.207911690818f, 0.309016994375f, 0.406736643076f, 0.5f, 0.587785252292f, 0.669130606359f, @@ -1556,15 +1760,15 @@ static void draw_dof_ellipse(float ax, float az) 0.994521895368f, 1.0f }; - int i, j, n = 16; + int i, j; float x, z, px, pz; glEnable(GL_BLEND); glDepthMask(0); - glColor4ub(70, 70, 70, 50); + immUniformColor4ub(70, 70, 70, 50); - glBegin(GL_QUADS); + immBegin(GL_TRIANGLES, tri*3); pz = 0.0f; for (i = 1; i < n; i++) { z = staticSine[i]; @@ -1574,36 +1778,35 @@ static void draw_dof_ellipse(float ax, float az) x = staticSine[j]; if (j == n - i) { - glEnd(); - glBegin(GL_TRIANGLES); - bgl_sphere_project(ax * px, az * z); - bgl_sphere_project(ax * px, az * pz); - bgl_sphere_project(ax * x, az * pz); - glEnd(); - glBegin(GL_QUADS); + imm_sphere_project(pos, ax * px, az * z); + imm_sphere_project(pos, ax * px, az * pz); + imm_sphere_project(pos, ax * x, az * pz); } else { - bgl_sphere_project(ax * x, az * z); - bgl_sphere_project(ax * x, az * pz); - bgl_sphere_project(ax * px, az * pz); - bgl_sphere_project(ax * px, az * z); + imm_sphere_project(pos, ax * x, az * z); + imm_sphere_project(pos, ax * x, az * pz); + imm_sphere_project(pos, ax * px, az * pz); + + imm_sphere_project(pos, ax * px, az * pz); + imm_sphere_project(pos, ax * px, az * z); + imm_sphere_project(pos, ax * x, az * z); } px = x; } pz = z; } - glEnd(); + immEnd(); glDisable(GL_BLEND); glDepthMask(1); - glColor3ub(0, 0, 0); + immUniformColor3ub(0, 0, 0); - glBegin(GL_LINE_STRIP); + immBegin(GL_LINE_STRIP, n); for (i = 0; i < n; i++) - bgl_sphere_project(staticSine[n - i - 1] * ax, staticSine[i] * az); - glEnd(); + imm_sphere_project(pos, staticSine[n - i - 1] * ax, staticSine[i] * az); + immEnd(); } static void draw_pose_dofs(Object *ob) @@ -1611,7 +1814,13 @@ static void draw_pose_dofs(Object *ob) bArmature *arm = ob->data; bPoseChannel *pchan; Bone *bone; - + + VertexFormat *format = immVertexFormat(); + unsigned int pos = add_attrib(format, "pos", GL_FLOAT, 3, KEEP_FLOAT); + + immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR); + gpuMatrixBegin3D_legacy(); + for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) { bone = pchan->bone; @@ -1625,54 +1834,54 @@ static void draw_pose_dofs(Object *ob) int a, i; /* in parent-bone pose, but own restspace */ - glPushMatrix(); + gpuPushMatrix(); copy_v3_v3(posetrans, pchan->pose_mat[3]); - glTranslate3fv(posetrans); + gpuTranslate3fv(posetrans); if (pchan->parent) { copy_m4_m4(mat, pchan->parent->pose_mat); mat[3][0] = mat[3][1] = mat[3][2] = 0.0f; - glMultMatrixf(mat); + gpuMultMatrix3D(mat); } copy_m4_m3(mat, pchan->bone->bone_mat); - glMultMatrixf(mat); + gpuMultMatrix3D(mat); scale = bone->length * pchan->size[1]; - glScalef(scale, scale, scale); + gpuScale3f(scale, scale, scale); - if (pchan->ikflag & BONE_IK_XLIMIT) { - if (pchan->ikflag & BONE_IK_ZLIMIT) { - float amin[3], amax[3]; - - for (i = 0; i < 3; i++) { - /* *0.5f here comes from M_PI/360.0f when rotations were still in degrees */ - amin[i] = sinf(pchan->limitmin[i] * 0.5f); - amax[i] = sinf(pchan->limitmax[i] * 0.5f); - } - - glScalef(1.0f, -1.0f, 1.0f); - if ((amin[0] != 0.0f) && (amin[2] != 0.0f)) - draw_dof_ellipse(amin[0], amin[2]); - if ((amin[0] != 0.0f) && (amax[2] != 0.0f)) - draw_dof_ellipse(amin[0], amax[2]); - if ((amax[0] != 0.0f) && (amin[2] != 0.0f)) - draw_dof_ellipse(amax[0], amin[2]); - if ((amax[0] != 0.0f) && (amax[2] != 0.0f)) - draw_dof_ellipse(amax[0], amax[2]); - glScalef(1.0f, -1.0f, 1.0f); + if (((pchan->ikflag & BONE_IK_XLIMIT) != 0) && + ((pchan->ikflag & BONE_IK_ZLIMIT) != 0)) + { + float amin[3], amax[3]; + + for (i = 0; i < 3; i++) { + /* *0.5f here comes from M_PI/360.0f when rotations were still in degrees */ + amin[i] = sinf(pchan->limitmin[i] * 0.5f); + amax[i] = sinf(pchan->limitmax[i] * 0.5f); } + + gpuScale3f(1.0f, -1.0f, 1.0f); + if ((amin[0] != 0.0f) && (amin[2] != 0.0f)) + draw_dof_ellipse(pos, amin[0], amin[2]); + if ((amin[0] != 0.0f) && (amax[2] != 0.0f)) + draw_dof_ellipse(pos, amin[0], amax[2]); + if ((amax[0] != 0.0f) && (amin[2] != 0.0f)) + draw_dof_ellipse(pos, amax[0], amin[2]); + if ((amax[0] != 0.0f) && (amax[2] != 0.0f)) + draw_dof_ellipse(pos, amax[0], amax[2]); + gpuScale3f(1.0f, -1.0f, 1.0f); } /* arcs */ if (pchan->ikflag & BONE_IK_ZLIMIT) { /* OpenGL requires rotations in degrees; so we're taking the average angle here */ theta = RAD2DEGF(0.5f * (pchan->limitmin[2] + pchan->limitmax[2])); - glRotatef(theta, 0.0f, 0.0f, 1.0f); + gpuRotate3f(theta, 0.0f, 0.0f, 1.0f); - glColor3ub(50, 50, 255); /* blue, Z axis limit */ - glBegin(GL_LINE_STRIP); + immUniformColor3ub(50, 50, 255); /* blue, Z axis limit */ + immBegin(GL_LINE_STRIP, 33); for (a = -16; a <= 16; a++) { /* *0.5f here comes from M_PI/360.0f when rotations were still in degrees */ float fac = ((float)a) / 16.0f * 0.5f; @@ -1683,20 +1892,20 @@ static void draw_pose_dofs(Object *ob) corner[i][0] = sinf(phi); corner[i][1] = cosf(phi); corner[i][2] = 0.0f; - glVertex3fv(corner[i]); + immVertex3fv(pos, corner[i]); } - glEnd(); + immEnd(); - glRotatef(-theta, 0.0f, 0.0f, 1.0f); + gpuRotate3f(-theta, 0.0f, 0.0f, 1.0f); } if (pchan->ikflag & BONE_IK_XLIMIT) { /* OpenGL requires rotations in degrees; so we're taking the average angle here */ theta = RAD2DEGF(0.5f * (pchan->limitmin[0] + pchan->limitmax[0])); - glRotatef(theta, 1.0f, 0.0f, 0.0f); + gpuRotate3f(theta, 1.0f, 0.0f, 0.0f); - glColor3ub(255, 50, 50); /* Red, X axis limit */ - glBegin(GL_LINE_STRIP); + immUniformColor3ub(255, 50, 50); /* Red, X axis limit */ + immBegin(GL_LINE_STRIP, 33); for (a = -16; a <= 16; a++) { /* *0.5f here comes from M_PI/360.0f when rotations were still in degrees */ float fac = ((float)a) / 16.0f * 0.5f; @@ -1706,21 +1915,23 @@ static void draw_pose_dofs(Object *ob) corner[i][0] = 0.0f; corner[i][1] = sinf(phi); corner[i][2] = cosf(phi); - glVertex3fv(corner[i]); + immVertex3fv(pos, corner[i]); } - glEnd(); + immEnd(); - glRotatef(-theta, 1.0f, 0.0f, 0.0f); + gpuRotate3f(-theta, 1.0f, 0.0f, 0.0f); } /* out of cone, out of bone */ - glPopMatrix(); + gpuPopMatrix(); } } } } } } + gpuMatrixEnd(); + immUnbindProgram(); } static void bone_matrix_translate_y(float mat[4][4], float y) @@ -1733,7 +1944,7 @@ static void bone_matrix_translate_y(float mat[4][4], float y) } /* assumes object is Armature with pose */ -static void draw_pose_bones(Scene *scene, View3D *v3d, ARegion *ar, Base *base, +static void draw_pose_bones(Scene *scene, View3D *v3d, ARegion *ar, BaseLegacy *base, const short dt, const unsigned char ob_wire_col[4], const bool do_const_color, const bool is_outline) { @@ -1756,7 +1967,9 @@ static void draw_pose_bones(Scene *scene, View3D *v3d, ARegion *ar, Base *base, /* being set below */ arm->layer_used = 0; - + + rgba_uchar_to_float(fcolor, ob_wire_col); + /* precalc inverse matrix for drawing screen aligned */ if (arm->drawtype == ARM_ENVELOPE) { /* precalc inverse matrix for drawing screen aligned */ @@ -1937,7 +2150,7 @@ static void draw_pose_bones(Scene *scene, View3D *v3d, ARegion *ar, Base *base, else if (arm->flag & ARM_POSEMODE) set_pchan_colorset(ob, pchan); else { - glColor3ubv(ob_wire_col); + rgba_uchar_to_float(fcolor, ob_wire_col); } /* catch exception for bone with hidden parent */ @@ -2011,16 +2224,25 @@ static void draw_pose_bones(Scene *scene, View3D *v3d, ARegion *ar, Base *base, * - only if V3D_HIDE_HELPLINES is enabled... */ if ((do_dashed & DASH_HELP_LINES) && ((bone->flag & BONE_CONNECTED) == 0)) { + VertexFormat *format = immVertexFormat(); + unsigned int pos = add_attrib(format, "pos", GL_FLOAT, 3, KEEP_FLOAT); + + immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR); + if (arm->flag & ARM_POSEMODE) { GPU_select_load_id(index & 0xFFFF); /* object tag, for bordersel optim */ - UI_ThemeColor(TH_WIRE); + UI_GetThemeColor4fv(TH_WIRE, fcolor); + immUniformColor4fv(fcolor); } + setlinestyle(3); - glBegin(GL_LINES); - glVertex3fv(pchan->pose_head); - glVertex3fv(pchan->parent->pose_tail); - glEnd(); + immBegin(GL_LINES, 2); + immVertex3fv(pos, pchan->pose_head); + immVertex3fv(pos, pchan->parent->pose_tail); + immEnd(); setlinestyle(0); + + immUnbindProgram(); } /* Draw a line to IK root bone @@ -2029,8 +2251,8 @@ static void draw_pose_bones(Scene *scene, View3D *v3d, ARegion *ar, Base *base, if (arm->flag & ARM_POSEMODE) { if (constflag & PCHAN_HAS_IK) { if (bone->flag & BONE_SELECTED) { - if (constflag & PCHAN_HAS_TARGET) glColor3ub(200, 120, 0); - else glColor3ub(200, 200, 50); /* add theme! */ + if (constflag & PCHAN_HAS_TARGET) rgba_float_args_set(fcolor, 200.f/255.f, 120.f/255.f, 0.f/255.f, 1.0f); + else rgba_float_args_set(fcolor, 200.f/255.f, 200.f/255.f, 50.f/255.f, 1.0f); /* add theme! */ GPU_select_load_id(index & 0xFFFF); pchan_draw_IK_root_lines(pchan, !(do_dashed & DASH_HELP_LINES)); @@ -2038,7 +2260,7 @@ static void draw_pose_bones(Scene *scene, View3D *v3d, ARegion *ar, Base *base, } else if (constflag & PCHAN_HAS_SPLINEIK) { if (bone->flag & BONE_SELECTED) { - glColor3ub(150, 200, 50); /* add theme! */ + rgba_float_args_set(fcolor, 150.f/255.f, 200.f/255.f, 50.f/255.f, 1.0f); /* add theme! */ GPU_select_load_id(index & 0xFFFF); pchan_draw_IK_root_lines(pchan, !(do_dashed & DASH_HELP_LINES)); @@ -2106,7 +2328,7 @@ static void draw_pose_bones(Scene *scene, View3D *v3d, ARegion *ar, Base *base, /* draw DoFs */ if (arm->flag & ARM_POSEMODE) { - if (((base->flag & OB_FROMDUPLI) == 0) && ((v3d->flag & V3D_HIDE_HELPLINES) == 0)) { + if (((base->flag_legacy & OB_FROMDUPLI) == 0) && ((v3d->flag & V3D_HIDE_HELPLINES) == 0)) { draw_pose_dofs(ob); } } @@ -2114,26 +2336,17 @@ static void draw_pose_bones(Scene *scene, View3D *v3d, ARegion *ar, Base *base, /* finally names and axes */ if ((arm->flag & (ARM_DRAWNAMES | ARM_DRAWAXES)) && (is_outline == 0) && - ((base->flag & OB_FROMDUPLI) == 0)) + ((base->flag_legacy & OB_FROMDUPLI) == 0)) { /* patch for several 3d cards (IBM mostly) that crash on GL_SELECT with text drawing */ if ((G.f & G_PICKSEL) == 0) { float vec[3]; unsigned char col[4]; - if (do_const_color) { - /* so we can draw bone names in current const color */ - float tcol[4]; - glGetFloatv(GL_CURRENT_COLOR, tcol); - rgb_float_to_uchar(col, tcol); - col[3] = 255; - } - else { - col[0] = ob_wire_col[0]; - col[1] = ob_wire_col[1]; - col[2] = ob_wire_col[2]; - col[3] = 255; - } + col[0] = ob_wire_col[0]; + col[1] = ob_wire_col[1]; + col[2] = ob_wire_col[2]; + col[3] = 255; if (v3d->zbuf) glDisable(GL_DEPTH_TEST); @@ -2161,11 +2374,9 @@ static void draw_pose_bones(Scene *scene, View3D *v3d, ARegion *ar, Base *base, bone_matrix_translate_y(bmat, pchan->bone->length); glMultMatrixf(bmat); - glColor3ubv(col); - float viewmat_pchan[4][4]; mul_m4_m4m4(viewmat_pchan, rv3d->viewmatob, bmat); - drawaxes(viewmat_pchan, pchan->bone->length * 0.25f, OB_ARROWS); + drawaxes(viewmat_pchan, pchan->bone->length * 0.25f, OB_ARROWS, col); glPopMatrix(); } @@ -2313,16 +2524,23 @@ static void draw_ebones(View3D *v3d, ARegion *ar, Object *ob, const short dt) /* offset to parent */ if (eBone->parent) { - UI_ThemeColor(TH_WIRE_EDIT); + VertexFormat *format = immVertexFormat(); + unsigned int pos = add_attrib(format, "pos", GL_FLOAT, 3, KEEP_FLOAT); + GPU_select_load_id(-1); /* -1 here is OK! */ - setlinestyle(3); - - glBegin(GL_LINES); - glVertex3fv(eBone->parent->tail); - glVertex3fv(eBone->head); - glEnd(); + + immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR); + UI_GetThemeColor4fv(TH_WIRE_EDIT, fcolor); + immUniformColor4fv(fcolor); + setlinestyle(3); + immBegin(GL_LINES, 2); + immVertex3fv(pos, eBone->head); + immVertex3fv(pos, eBone->parent->tail); + immEnd(); setlinestyle(0); + + immUnbindProgram(); } } } @@ -2370,11 +2588,9 @@ static void draw_ebones(View3D *v3d, ARegion *ar, Object *ob, const short dt) bone_matrix_translate_y(bmat, eBone->length); glMultMatrixf(bmat); - glColor3ubv(col); - float viewmat_ebone[4][4]; mul_m4_m4m4(viewmat_ebone, rv3d->viewmatob, bmat); - drawaxes(viewmat_ebone, eBone->length * 0.25f, OB_ARROWS); + drawaxes(viewmat_ebone, eBone->length * 0.25f, OB_ARROWS, col); glPopMatrix(); } @@ -2449,7 +2665,7 @@ static void ghost_poses_tag_unselected(Object *ob, short unset) /* draw ghosts that occur within a frame range * note: object should be in posemode */ -static void draw_ghost_poses_range(Scene *scene, View3D *v3d, ARegion *ar, Base *base) +static void draw_ghost_poses_range(Scene *scene, View3D *v3d, ARegion *ar, BaseLegacy *base) { Object *ob = base->object; AnimData *adt = BKE_animdata_from_id(&ob->id); @@ -2457,6 +2673,7 @@ static void draw_ghost_poses_range(Scene *scene, View3D *v3d, ARegion *ar, Base bPose *posen, *poseo; float start, end, stepsize, range, colfac; int cfrao, flago; + unsigned char col[4]; start = (float)arm->ghostsf; end = (float)arm->ghostef; @@ -2489,11 +2706,11 @@ static void draw_ghost_poses_range(Scene *scene, View3D *v3d, ARegion *ar, Base /* draw from first frame of range to last */ for (CFRA = (int)start; CFRA <= end; CFRA += (int)stepsize) { colfac = (end - (float)CFRA) / range; - UI_ThemeColorShadeAlpha(TH_WIRE, 0, -128 - (int)(120.0f * sqrtf(colfac))); + UI_GetThemeColorShadeAlpha4ubv(TH_WIRE, 0, -128 - (int)(120.0f * sqrtf(colfac)), col); BKE_animsys_evaluate_animdata(scene, &ob->id, adt, (float)CFRA, ADT_RECALC_ALL); BKE_pose_where_is(scene, ob); - draw_pose_bones(scene, v3d, ar, base, OB_WIRE, NULL, true, false); + draw_pose_bones(scene, v3d, ar, base, OB_WIRE, col, true, false); } glDisable(GL_BLEND); if (v3d->zbuf) glEnable(GL_DEPTH_TEST); @@ -2515,7 +2732,7 @@ static void draw_ghost_poses_range(Scene *scene, View3D *v3d, ARegion *ar, Base /* draw ghosts on keyframes in action within range * - object should be in posemode */ -static void draw_ghost_poses_keys(Scene *scene, View3D *v3d, ARegion *ar, Base *base) +static void draw_ghost_poses_keys(Scene *scene, View3D *v3d, ARegion *ar, BaseLegacy *base) { Object *ob = base->object; AnimData *adt = BKE_animdata_from_id(&ob->id); @@ -2526,6 +2743,7 @@ static void draw_ghost_poses_keys(Scene *scene, View3D *v3d, ARegion *ar, Base * ActKeyColumn *ak, *akn; float start, end, range, colfac, i; int cfrao, flago; + unsigned char col[4]; start = (float)arm->ghostsf; end = (float)arm->ghostef; @@ -2567,13 +2785,13 @@ static void draw_ghost_poses_keys(Scene *scene, View3D *v3d, ARegion *ar, Base * /* draw from first frame of range to last */ for (ak = keys.first, i = 0; ak; ak = ak->next, i++) { colfac = i / range; - UI_ThemeColorShadeAlpha(TH_WIRE, 0, -128 - (int)(120.0f * sqrtf(colfac))); + UI_GetThemeColorShadeAlpha4ubv(TH_WIRE, 0, -128 - (int)(120.0f * sqrtf(colfac)), col); CFRA = (int)ak->cfra; BKE_animsys_evaluate_animdata(scene, &ob->id, adt, (float)CFRA, ADT_RECALC_ALL); BKE_pose_where_is(scene, ob); - draw_pose_bones(scene, v3d, ar, base, OB_WIRE, NULL, true, false); + draw_pose_bones(scene, v3d, ar, base, OB_WIRE, col, true, false); } glDisable(GL_BLEND); if (v3d->zbuf) glEnable(GL_DEPTH_TEST); @@ -2596,7 +2814,7 @@ static void draw_ghost_poses_keys(Scene *scene, View3D *v3d, ARegion *ar, Base * /* draw ghosts around current frame * - object is supposed to be armature in posemode */ -static void draw_ghost_poses(Scene *scene, View3D *v3d, ARegion *ar, Base *base) +static void draw_ghost_poses(Scene *scene, View3D *v3d, ARegion *ar, BaseLegacy *base) { Object *ob = base->object; AnimData *adt = BKE_animdata_from_id(&ob->id); @@ -2604,6 +2822,7 @@ static void draw_ghost_poses(Scene *scene, View3D *v3d, ARegion *ar, Base *base) bPose *posen, *poseo; float cur, start, end, stepsize, range, colfac, actframe, ctime; int cfrao, flago; + unsigned char col[4]; /* pre conditions, get an action with sufficient frames */ if (ELEM(NULL, adt, adt->action)) @@ -2641,7 +2860,7 @@ static void draw_ghost_poses(Scene *scene, View3D *v3d, ARegion *ar, Base *base) for (cur = stepsize; cur < range; cur += stepsize) { ctime = cur - (float)fmod(cfrao, stepsize); /* ensures consistent stepping */ colfac = ctime / range; - UI_ThemeColorShadeAlpha(TH_WIRE, 0, -128 - (int)(120.0f * sqrtf(colfac))); + UI_GetThemeColorShadeAlpha4ubv(TH_WIRE, 0, -128 - (int)(120.0f * sqrtf(colfac)), col); /* only within action range */ if (actframe + ctime >= start && actframe + ctime <= end) { @@ -2650,13 +2869,13 @@ static void draw_ghost_poses(Scene *scene, View3D *v3d, ARegion *ar, Base *base) if (CFRA != cfrao) { BKE_animsys_evaluate_animdata(scene, &ob->id, adt, (float)CFRA, ADT_RECALC_ALL); BKE_pose_where_is(scene, ob); - draw_pose_bones(scene, v3d, ar, base, OB_WIRE, NULL, true, false); + draw_pose_bones(scene, v3d, ar, base, OB_WIRE, col, true, false); } } ctime = cur + (float)fmod((float)cfrao, stepsize) - stepsize + 1.0f; /* ensures consistent stepping */ colfac = ctime / range; - UI_ThemeColorShadeAlpha(TH_WIRE, 0, -128 - (int)(120.0f * sqrtf(colfac))); + UI_GetThemeColorShadeAlpha4ubv(TH_WIRE, 0, -128 - (int)(120.0f * sqrtf(colfac)), col); /* only within action range */ if ((actframe - ctime >= start) && (actframe - ctime <= end)) { @@ -2665,7 +2884,7 @@ static void draw_ghost_poses(Scene *scene, View3D *v3d, ARegion *ar, Base *base) if (CFRA != cfrao) { BKE_animsys_evaluate_animdata(scene, &ob->id, adt, (float)CFRA, ADT_RECALC_ALL); BKE_pose_where_is(scene, ob); - draw_pose_bones(scene, v3d, ar, base, OB_WIRE, NULL, true, false); + draw_pose_bones(scene, v3d, ar, base, OB_WIRE, col, true, false); } } } @@ -2690,7 +2909,7 @@ static void draw_ghost_poses(Scene *scene, View3D *v3d, ARegion *ar, Base *base) /* called from drawobject.c, return true if nothing was drawn * (ob_wire_col == NULL) when drawing ghost */ -bool draw_armature(Scene *scene, View3D *v3d, ARegion *ar, Base *base, +bool draw_armature(Scene *scene, SceneLayer *sl, View3D *v3d, ARegion *ar, Base *base, const short dt, const short dflag, const unsigned char ob_wire_col[4], const bool is_outline) { @@ -2701,11 +2920,7 @@ bool draw_armature(Scene *scene, View3D *v3d, ARegion *ar, Base *base, if (v3d->flag2 & V3D_RENDER_OVERRIDE) return true; - /* needed for 'draw_line_bone' which draws pixel. */ - if (arm->drawtype == ARM_LINE) { - glPixelStorei(GL_UNPACK_ALIGNMENT, 1); - } - +#if 0 /* Not used until lighting is properly reimplemented */ if (dt > OB_WIRE) { /* we use color for solid lighting */ if (ELEM(arm->drawtype, ARM_LINE, ARM_WIRE)) { @@ -2720,7 +2935,8 @@ bool draw_armature(Scene *scene, View3D *v3d, ARegion *ar, Base *base, glFrontFace((ob->transflag & OB_NEG_SCALE) ? GL_CW : GL_CCW); /* only for lighting... */ } } - +#endif + /* arm->flag is being used to detect mode... */ /* editmode? */ if (arm->edbo) { @@ -2737,7 +2953,7 @@ bool draw_armature(Scene *scene, View3D *v3d, ARegion *ar, Base *base, } /* drawing posemode selection indices or colors only in these cases */ - if (!(base->flag & OB_FROMDUPLI)) { + if (!(base->flag_legacy & OB_FROMDUPLI)) { if (G.f & G_PICKSEL) { #if 0 /* nifty but actually confusing to allow bone selection out of posemode */ @@ -2763,10 +2979,10 @@ bool draw_armature(Scene *scene, View3D *v3d, ARegion *ar, Base *base, draw_ghost_poses(scene, v3d, ar, base); } if ((dflag & DRAW_SCENESET) == 0) { - if (ob == OBACT) + if (ob == OBACT_NEW) arm->flag |= ARM_POSEMODE; - else if (OBACT && (OBACT->mode & OB_MODE_WEIGHT_PAINT)) { - if (ob == modifiers_isDeformedByArmature(OBACT)) + else if (OBACT_NEW && (OBACT_NEW->mode & OB_MODE_WEIGHT_PAINT)) { + if (ob == modifiers_isDeformedByArmature(OBACT_NEW)) arm->flag |= ARM_POSEMODE; } draw_pose_paths(scene, v3d, ar, ob); @@ -2775,9 +2991,6 @@ bool draw_armature(Scene *scene, View3D *v3d, ARegion *ar, Base *base, } draw_pose_bones(scene, v3d, ar, base, dt, ob_wire_col, (dflag & DRAW_CONSTCOLOR), is_outline); arm->flag &= ~ARM_POSEMODE; - - if (ob->mode & OB_MODE_POSE) - UI_ThemeColor(TH_WIRE); /* restore, for extra draw stuff */ } else { retval = true; @@ -2786,9 +2999,5 @@ bool draw_armature(Scene *scene, View3D *v3d, ARegion *ar, Base *base, /* restore */ glFrontFace(GL_CCW); - if (arm->drawtype == ARM_LINE) { - glPixelStorei(GL_UNPACK_ALIGNMENT, 4); - } - return retval; } diff --git a/source/blender/editors/space_view3d/drawobject.c b/source/blender/editors/space_view3d/drawobject.c index 90d33dc5995..8657991d1ba 100644 --- a/source/blender/editors/space_view3d/drawobject.c +++ b/source/blender/editors/space_view3d/drawobject.c @@ -65,6 +65,7 @@ #include "BKE_lattice.h" #include "BKE_main.h" #include "BKE_mesh.h" +#include "BKE_mesh_render.h" #include "BKE_material.h" #include "BKE_mball.h" #include "BKE_modifier.h" @@ -90,6 +91,9 @@ #include "GPU_select.h" #include "GPU_basic_shader.h" #include "GPU_shader.h" +#include "GPU_immediate.h" +#include "GPU_batch.h" +#include "GPU_matrix.h" #include "ED_mesh.h" #include "ED_particle.h" @@ -105,6 +109,9 @@ #include "view3d_intern.h" /* bad level include */ +/* prototypes */ +static void imm_draw_box(const float vec[8][3], bool solid, unsigned pos); + /* Workaround for sequencer scene render mode. * * Strips doesn't use DAG to update objects or so, which @@ -208,12 +215,12 @@ typedef struct drawBMSelect_userData { bool select; } drawBMSelect_userData; -static void draw_bounding_volume(Object *ob, char type); -static void drawcube_size(float size); -static void drawcircle_size(float size); -static void draw_empty_sphere(float size); -static void draw_empty_cone(float size); +static void drawcube_size(float size, unsigned pos); +static void drawcircle_size(float size, unsigned pos); +static void draw_empty_sphere(float size, unsigned pos); +static void draw_empty_cone(float size, unsigned pos); + static void draw_box(const float vec[8][3], bool solid); static void ob_wire_color_blend_theme_id(const unsigned char ob_wire_col[4], const int theme_id, float fac) @@ -316,9 +323,9 @@ bool draw_glsl_material(Scene *scene, Object *ob, View3D *v3d, const char dt) return false; } -static bool check_alpha_pass(Base *base) +static bool check_alpha_pass(BaseLegacy *base) { - if (base->flag & OB_FROMDUPLI) + if (base->flag_legacy & OB_FROMDUPLI) return false; if (G.f & G_PICKSEL) @@ -414,7 +421,7 @@ static const float cosval[CIRCLE_RESOL] = { * \param viewmat_local_unit is typically the 'rv3d->viewmatob' * copied into a 3x3 matrix and normalized. */ -static void draw_xyz_wire(const float viewmat_local_unit[3][3], const float c[3], float size, int axis) +static void draw_xyz_wire(const float viewmat_local_unit[3][3], const float c[3], float size, int axis, unsigned pos) { int line_type; float buffer[4][3]; @@ -501,54 +508,67 @@ static void draw_xyz_wire(const float viewmat_local_unit[3][3], const float c[3] return; } + immBegin(line_type, n); for (int i = 0; i < n; i++) { mul_transposed_m3_v3((float (*)[3])viewmat_local_unit, buffer[i]); add_v3_v3(buffer[i], c); + immVertex3fv(pos, buffer[i]); } + immEnd(); + /* TODO: recode this function for clarity once we're not in a hurry to modernize GL usage */ + +#if 0 glEnableClientState(GL_VERTEX_ARRAY); glVertexPointer(3, GL_FLOAT, 0, buffer); glDrawArrays(line_type, 0, n); glDisableClientState(GL_VERTEX_ARRAY); +#endif } -void drawaxes(const float viewmat_local[4][4], float size, char drawtype) +void drawaxes(const float viewmat_local[4][4], float size, char drawtype, const unsigned char color[4]) { int axis; float v1[3] = {0.0, 0.0, 0.0}; float v2[3] = {0.0, 0.0, 0.0}; float v3[3] = {0.0, 0.0, 0.0}; - glLineWidth(1); + glLineWidth(1.0f); - switch (drawtype) { + unsigned pos = add_attrib(immVertexFormat(), "pos", GL_FLOAT, 3, KEEP_FLOAT); + if (color) { + immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR); + immUniformColor4ubv(color); + } + else { + immBindBuiltinProgram(GPU_SHADER_3D_DEPTH_ONLY); + } + switch (drawtype) { case OB_PLAINAXES: + immBegin(GL_LINES, 6); for (axis = 0; axis < 3; axis++) { - glBegin(GL_LINES); - v1[axis] = size; v2[axis] = -size; - glVertex3fv(v1); - glVertex3fv(v2); + immVertex3fv(pos, v1); + immVertex3fv(pos, v2); /* reset v1 & v2 to zero */ v1[axis] = v2[axis] = 0.0f; - - glEnd(); } + immEnd(); break; - case OB_SINGLE_ARROW: - glBegin(GL_LINES); + case OB_SINGLE_ARROW: + immBegin(GL_LINES, 2); /* in positive z direction only */ v1[2] = size; - glVertex3fv(v1); - glVertex3fv(v2); - glEnd(); + immVertex3fv(pos, v1); + immVertex3fv(pos, v2); + immEnd(); /* square pyramid */ - glBegin(GL_TRIANGLES); + immBegin(GL_TRIANGLES, 12); v2[0] = size * 0.035f; v2[1] = size * 0.035f; v3[0] = size * -0.035f; v3[1] = size * 0.035f; @@ -564,28 +584,27 @@ void drawaxes(const float viewmat_local[4][4], float size, char drawtype) v3[0] = -v3[0]; } - glVertex3fv(v1); - glVertex3fv(v2); - glVertex3fv(v3); - + immVertex3fv(pos, v1); + immVertex3fv(pos, v2); + immVertex3fv(pos, v3); } - glEnd(); - + immEnd(); break; + case OB_CUBE: - drawcube_size(size); + drawcube_size(size, pos); break; case OB_CIRCLE: - drawcircle_size(size); + drawcircle_size(size, pos); break; case OB_EMPTY_SPHERE: - draw_empty_sphere(size); + draw_empty_sphere(size, pos); break; case OB_EMPTY_CONE: - draw_empty_cone(size); + draw_empty_cone(size, pos); break; case OB_ARROWS: @@ -599,34 +618,34 @@ void drawaxes(const float viewmat_local[4][4], float size, char drawtype) for (axis = 0; axis < 3; axis++) { const int arrow_axis = (axis == 0) ? 1 : 0; - glBegin(GL_LINES); + immBegin(GL_LINES, 6); v2[axis] = size; - glVertex3fv(v1); - glVertex3fv(v2); - + immVertex3fv(pos, v1); + immVertex3fv(pos, v2); + v1[axis] = size * 0.85f; v1[arrow_axis] = -size * 0.08f; - glVertex3fv(v1); - glVertex3fv(v2); - + immVertex3fv(pos, v1); + immVertex3fv(pos, v2); + v1[arrow_axis] = size * 0.08f; - glVertex3fv(v1); - glVertex3fv(v2); + immVertex3fv(pos, v1); + immVertex3fv(pos, v2); - glEnd(); - - v2[axis] += size * 0.125f; + immEnd(); - draw_xyz_wire(viewmat_local_unit, v2, size, axis); + v2[axis] += size * 0.125f; + draw_xyz_wire(viewmat_local_unit, v2, size, axis, pos); /* reset v1 & v2 to zero */ v1[arrow_axis] = v1[axis] = v2[axis] = 0.0f; } - break; } } + + immUnbindProgram(); } @@ -634,102 +653,111 @@ void drawaxes(const float viewmat_local[4][4], float size, char drawtype) static void draw_empty_image(Object *ob, const short dflag, const unsigned char ob_wire_col[4], StereoViews sview) { Image *ima = ob->data; - ImBuf *ibuf; - ImageUser iuser = *ob->iuser; - /* Support multi-view */ - if (ima && (sview == STEREO_RIGHT_ID)) { - iuser.multiview_eye = sview; - iuser.flag |= IMA_SHOW_STEREO; - BKE_image_multiview_index(ima, &iuser); - } + const float ob_alpha = ob->col[3]; + float width, height; - ibuf = BKE_image_acquire_ibuf(ima, &iuser, NULL); + int bindcode = 0; - if (ibuf && (ibuf->rect == NULL) && (ibuf->rect_float != NULL)) { - IMB_rect_from_float(ibuf); - } + if (ima) { + ImageUser iuser = *ob->iuser; - int ima_x, ima_y; + /* Support multi-view */ + if (ima && (sview == STEREO_RIGHT_ID)) { + iuser.multiview_eye = sview; + iuser.flag |= IMA_SHOW_STEREO; + BKE_image_multiview_index(ima, &iuser); + } - /* Get the buffer dimensions so we can fallback to fake ones */ - if (ibuf && ibuf->rect) { - ima_x = ibuf->x; - ima_y = ibuf->y; + if (ob_alpha > 0.0f) { + bindcode = GPU_verify_image(ima, &iuser, GL_TEXTURE_2D, 0, false, false, false); + /* don't bother drawing the image if alpha = 0 */ + } + + int w, h; + BKE_image_get_size(ima, &iuser, &w, &h); + width = w; + height = h; } else { - ima_x = 1; - ima_y = 1; + /* if no image, make it a 1x1 empty square, honor scale & offset */ + width = height = 1.0f; } - float sca_x = 1.0f; - float sca_y = 1.0f; + const float aspect = height / width; - /* Get the image aspect even if the buffer is invalid */ - if (ima) { - if (ima->aspx > ima->aspy) { - sca_y = ima->aspy / ima->aspx; - } - else if (ima->aspx < ima->aspy) { - sca_x = ima->aspx / ima->aspy; - } - } + float left = ob->ima_ofs[0]; + float right = ob->ima_ofs[0] + ob->empty_drawsize; + float top = ob->ima_ofs[1] + ob->empty_drawsize * aspect; + float bottom = ob->ima_ofs[1]; - /* Calculate the scale center based on object's origin */ - float ofs_x = ob->ima_ofs[0] * ima_x; - float ofs_y = ob->ima_ofs[1] * ima_y; + bool use_blend = false; - glMatrixMode(GL_MODELVIEW); - glPushMatrix(); + if (bindcode) { + use_blend = ob_alpha < 1.0f || BKE_image_has_alpha(ima); - /* Calculate Image scale */ - float scale = ob->empty_drawsize / max_ff((float)ima_x * sca_x, (float)ima_y * sca_y); + if (use_blend) { + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + } - /* Set the object scale */ - glScalef(scale * sca_x, scale * sca_y, 1.0f); + VertexFormat *format = immVertexFormat(); + unsigned pos = add_attrib(format, "pos", GL_FLOAT, 2, KEEP_FLOAT); + unsigned texCoord = add_attrib(format, "texCoord", GL_FLOAT, 2, KEEP_FLOAT); + immBindBuiltinProgram(GPU_SHADER_3D_IMAGE_MODULATE_ALPHA); + immUniform1f("alpha", ob_alpha); + immUniform1i("image", 0); /* default GL_TEXTURE0 unit */ - if (ibuf && ibuf->rect) { - const bool use_clip = (U.glalphaclip != 1.0f); - int zoomfilter = (U.gameflags & USER_DISABLE_MIPMAP) ? GL_NEAREST : GL_LINEAR; - /* Setup GL params */ - glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + immBegin(GL_TRIANGLE_FAN, 4); + immAttrib2f(texCoord, 0.0f, 0.0f); + immVertex2f(pos, left, bottom); - if (use_clip) { - glEnable(GL_ALPHA_TEST); - glAlphaFunc(GL_GREATER, U.glalphaclip); - } + immAttrib2f(texCoord, 1.0f, 0.0f); + immVertex2f(pos, right, bottom); - /* Use the object color and alpha */ - glColor4fv(ob->col); + immAttrib2f(texCoord, 1.0f, 1.0f); + immVertex2f(pos, right, top); - /* Draw the Image on the screen */ - glaDrawPixelsTex(ofs_x, ofs_y, ima_x, ima_y, GL_RGBA, GL_UNSIGNED_BYTE, zoomfilter, ibuf->rect); + immAttrib2f(texCoord, 0.0f, 1.0f); + immVertex2f(pos, left, top); + immEnd(); - glDisable(GL_BLEND); + immUnbindProgram(); - if (use_clip) { - glDisable(GL_ALPHA_TEST); - glAlphaFunc(GL_ALWAYS, 0.0f); - } + glBindTexture(GL_TEXTURE_2D, 0); /* necessary? */ } - if ((dflag & DRAW_CONSTCOLOR) == 0) { - glColor3ubv(ob_wire_col); + /* Draw the image outline */ + glLineWidth(1.5f); + unsigned pos = add_attrib(immVertexFormat(), "pos", GL_FLOAT, 2, KEEP_FLOAT); + + const bool picking = dflag & DRAW_CONSTCOLOR; + if (picking) { + /* TODO: deal with picking separately, use this function just to draw */ + immBindBuiltinProgram(GPU_SHADER_3D_DEPTH_ONLY); + if (use_blend) { + glDisable(GL_BLEND); + } + + imm_draw_line_box(pos, left, bottom, right, top); } + else { + immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR); + immUniformColor3ubv(ob_wire_col); + glEnable(GL_LINE_SMOOTH); - /* Calculate the outline vertex positions */ - glBegin(GL_LINE_LOOP); - glVertex2f(ofs_x, ofs_y); - glVertex2f(ofs_x + ima_x, ofs_y); - glVertex2f(ofs_x + ima_x, ofs_y + ima_y); - glVertex2f(ofs_x, ofs_y + ima_y); - glEnd(); + if (!use_blend) { + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + } - /* Reset GL settings */ - glPopMatrix(); + imm_draw_line_box(pos, left, bottom, right, top); - BKE_image_release_ibuf(ima, ibuf, NULL); + glDisable(GL_LINE_SMOOTH); + glDisable(GL_BLEND); + } + + immUnbindProgram(); } static void circball_array_fill(float verts[CIRCLE_RESOL][3], const float cent[3], float rad, const float tmat[4][4]) @@ -759,50 +787,65 @@ void drawcircball(int mode, const float cent[3], float rad, const float tmat[4][ glDisableClientState(GL_VERTEX_ARRAY); } -/* circle for object centers, special_color is for library or ob users */ -static void drawcentercircle(View3D *v3d, RegionView3D *rv3d, const float co[3], int selstate, bool special_color) +void imm_drawcircball(const float cent[3], float rad, const float tmat[4][4], unsigned pos) { - const float size = ED_view3d_pixel_size(rv3d, co) * (float)U.obcenter_dia * 0.5f; float verts[CIRCLE_RESOL][3]; - /* using glDepthFunc guarantees that it does write z values, - * but not checks for it, so centers remain visible independent of draw order */ - if (v3d->zbuf) glDepthFunc(GL_ALWAYS); - /* write to near buffer always */ - glDepthRange(0.0, 0.0); + circball_array_fill(verts, cent, rad, tmat); + + immBegin(GL_LINE_LOOP, CIRCLE_RESOL); + for (int i = 0; i < CIRCLE_RESOL; ++i) { + immVertex3fv(pos, verts[i]); + } + immEnd(); +} + +/* circle for object centers, special_color is for library or ob users */ +static void drawcentercircle(View3D *v3d, RegionView3D *UNUSED(rv3d), const float co[3], int selstate, bool special_color) +{ + const float outlineWidth = 1.0f * U.pixelsize; + const float size = U.obcenter_dia * U.pixelsize + outlineWidth; + + if (v3d->zbuf) { + glDisable(GL_DEPTH_TEST); + /* TODO(merwin): fit things like this into plates/buffers design */ + } + glEnable(GL_BLEND); - + GPU_enable_program_point_size(); + + unsigned pos = add_attrib(immVertexFormat(), "pos", GL_FLOAT, 3, KEEP_FLOAT); + immBindBuiltinProgram(GPU_SHADER_3D_POINT_UNIFORM_SIZE_UNIFORM_COLOR_OUTLINE_SMOOTH); + immUniform1f("size", size); + if (special_color) { - if (selstate == ACTIVE || selstate == SELECT) glColor4ub(0x88, 0xFF, 0xFF, 155); - else glColor4ub(0x55, 0xCC, 0xCC, 155); + if (selstate == ACTIVE || selstate == SELECT) immUniformColor4ub(0x88, 0xFF, 0xFF, 155); + else immUniformColor4ub(0x55, 0xCC, 0xCC, 155); } else { - if (selstate == ACTIVE) UI_ThemeColorShadeAlpha(TH_ACTIVE, 0, -80); - else if (selstate == SELECT) UI_ThemeColorShadeAlpha(TH_SELECT, 0, -80); - else if (selstate == DESELECT) UI_ThemeColorShadeAlpha(TH_TRANSFORM, 0, -80); + if (selstate == ACTIVE) immUniformThemeColorShadeAlpha(TH_ACTIVE, 0, -80); + else if (selstate == SELECT) immUniformThemeColorShadeAlpha(TH_SELECT, 0, -80); + else if (selstate == DESELECT) immUniformThemeColorShadeAlpha(TH_TRANSFORM, 0, -80); } - circball_array_fill(verts, co, size, rv3d->viewinv); + /* set up outline */ + float outlineColor[4]; + UI_GetThemeColorShadeAlpha4fv(TH_WIRE, 0, -30, outlineColor); + immUniform4fv("outlineColor", outlineColor); + immUniform1f("outlineWidth", outlineWidth); - /* enable vertex array */ - glEnableClientState(GL_VERTEX_ARRAY); - glVertexPointer(3, GL_FLOAT, 0, verts); - - /* 1. draw filled, blended polygon */ - glDrawArrays(GL_POLYGON, 0, CIRCLE_RESOL); - - /* 2. draw outline */ - glLineWidth(1); - UI_ThemeColorShadeAlpha(TH_WIRE, 0, -30); - glDrawArrays(GL_LINE_LOOP, 0, CIRCLE_RESOL); + immBegin(GL_POINTS, 1); + immVertex3fv(pos, co); + immEnd(); - /* finish up */ - glDisableClientState(GL_VERTEX_ARRAY); + immUnbindProgram(); - glDepthRange(0.0, 1.0); + GPU_disable_program_point_size(); glDisable(GL_BLEND); - if (v3d->zbuf) glDepthFunc(GL_LEQUAL); + if (v3d->zbuf) { + glEnable(GL_DEPTH_TEST); + } } /* *********** text drawing for object/particles/armature ************* */ @@ -919,7 +962,7 @@ void view3d_cached_text_draw_end(View3D *v3d, ARegion *ar, bool depth_write, flo if (v3d->zbuf) glDisable(GL_DEPTH_TEST); } else { - glDepthMask(0); + glDepthMask(GL_FALSE); } for (vos = g_v3d_strings[g_v3d_string_level]; vos; vos = vos->next) { @@ -944,7 +987,7 @@ void view3d_cached_text_draw_end(View3D *v3d, ARegion *ar, bool depth_write, flo if (v3d->zbuf) glEnable(GL_DEPTH_TEST); } else { - glDepthMask(1); + glDepthMask(GL_TRUE); } glMatrixMode(GL_PROJECTION); @@ -974,9 +1017,9 @@ void view3d_cached_text_draw_end(View3D *v3d, ARegion *ar, bool depth_write, flo /* draws a cube given the scaling of the cube, assuming that * all required matrices have been set (used for drawing empties) */ -static void drawcube_size(float size) +static void drawcube_size(float size, unsigned pos) { - const GLfloat pos[8][3] = { + const GLfloat verts[8][3] = { {-size, -size, -size}, {-size, -size, size}, {-size, size, -size}, @@ -989,13 +1032,21 @@ static void drawcube_size(float size) 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}; +#if 0 glEnableClientState(GL_VERTEX_ARRAY); - glVertexPointer(3, GL_FLOAT, 0, pos); + glVertexPointer(3, GL_FLOAT, 0, verts); glDrawRangeElements(GL_LINES, 0, 7, 24, GL_UNSIGNED_BYTE, indices); glDisableClientState(GL_VERTEX_ARRAY); +#else + immBegin(GL_LINES, 24); + for (int i = 0; i < 24; ++i) { + immVertex3fv(pos, verts[indices[i]]); + } + immEnd(); +#endif } -static void drawshadbuflimits(Lamp *la, float mat[4][4]) +static void drawshadbuflimits(const Lamp *la, const float mat[4][4], unsigned pos) { float sta[3], end[3], lavec[3]; @@ -1005,16 +1056,16 @@ static void drawshadbuflimits(Lamp *la, float mat[4][4]) madd_v3_v3v3fl(sta, mat[3], lavec, la->clipsta); madd_v3_v3v3fl(end, mat[3], lavec, la->clipend); - glBegin(GL_LINES); - glVertex3fv(sta); - glVertex3fv(end); - glEnd(); + immBegin(GL_LINES, 2); + immVertex3fv(pos, sta); + immVertex3fv(pos, end); + immEnd(); - glPointSize(3.0); - glBegin(GL_POINTS); - glVertex3fv(sta); - glVertex3fv(end); - glEnd(); + glPointSize(3.0f); + immBegin(GL_POINTS, 2); + immVertex3fv(pos, sta); + immVertex3fv(pos, end); + immEnd(); } static void spotvolume(float lvec[3], float vvec[3], const float inp) @@ -1080,62 +1131,63 @@ static void spotvolume(float lvec[3], float vvec[3], const float inp) mul_m3_v3(mat2, vvec); } -static void draw_spot_cone(Lamp *la, float x, float z) +static void draw_spot_cone(Lamp *la, float x, float z, unsigned pos) { z = fabsf(z); - glBegin(GL_TRIANGLE_FAN); - glVertex3f(0.0f, 0.0f, -x); + const bool square = (la->mode & LA_SQUARE); - if (la->mode & LA_SQUARE) { - glVertex3f(z, z, 0); - glVertex3f(-z, z, 0); - glVertex3f(-z, -z, 0); - glVertex3f(z, -z, 0); - glVertex3f(z, z, 0); + immBegin(GL_TRIANGLE_FAN, square ? 6 : 34); + immVertex3f(pos, 0.0f, 0.0f, -x); + + if (square) { + immVertex3f(pos, z, z, 0); + immVertex3f(pos, -z, z, 0); + immVertex3f(pos, -z, -z, 0); + immVertex3f(pos, z, -z, 0); + immVertex3f(pos, z, z, 0); } else { for (int a = 0; a < 33; a++) { float angle = a * M_PI * 2 / (33 - 1); - glVertex3f(z * cosf(angle), z * sinf(angle), 0); + immVertex3f(pos, z * cosf(angle), z * sinf(angle), 0.0f); } } - glEnd(); + immEnd(); } -static void draw_transp_spot_volume(Lamp *la, float x, float z) +static void draw_transp_spot_volume(Lamp *la, float x, float z, unsigned pos) { glEnable(GL_CULL_FACE); glEnable(GL_BLEND); - glDepthMask(0); + glDepthMask(GL_FALSE); /* draw backside darkening */ glCullFace(GL_FRONT); glBlendFunc(GL_ZERO, GL_SRC_ALPHA); - glColor4f(0.0f, 0.0f, 0.0f, 0.4f); + immUniformColor4f(0.0f, 0.0f, 0.0f, 0.4f); - draw_spot_cone(la, x, z); + draw_spot_cone(la, x, z, pos); /* draw front side lighting */ glCullFace(GL_BACK); glBlendFunc(GL_ONE, GL_ONE); - glColor4f(0.2f, 0.2f, 0.2f, 1.0f); + immUniformColor4f(0.2f, 0.2f, 0.2f, 1.0f); - draw_spot_cone(la, x, z); + draw_spot_cone(la, x, z, pos); /* restore state */ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glDisable(GL_BLEND); - glDepthMask(1); + glDepthMask(GL_TRUE); glDisable(GL_CULL_FACE); - glCullFace(GL_BACK); } #ifdef WITH_GAMEENGINE -static void draw_transp_sun_volume(Lamp *la) +static void draw_transp_sun_volume(Lamp *la, unsigned pos) { float box[8][3]; @@ -1148,50 +1200,46 @@ static void draw_transp_sun_volume(Lamp *la) box[1][2] = box[2][2] = box[5][2] = box[6][2] = -la->clipsta; /* draw edges */ - draw_box(box, false); + imm_draw_box(box, false, pos); /* draw faces */ glEnable(GL_CULL_FACE); glEnable(GL_BLEND); - glDepthMask(0); + glDepthMask(GL_FALSE); /* draw backside darkening */ glCullFace(GL_FRONT); glBlendFunc(GL_ZERO, GL_SRC_ALPHA); - glColor4f(0.0f, 0.0f, 0.0f, 0.4f); + immUniformColor4f(0.0f, 0.0f, 0.0f, 0.4f); - draw_box(box, true); + imm_draw_box(box, true, pos); /* draw front side lighting */ glCullFace(GL_BACK); glBlendFunc(GL_ONE, GL_ONE); - glColor4f(0.2f, 0.2f, 0.2f, 1.0f); + immUniformColor4f(0.2f, 0.2f, 0.2f, 1.0f); - draw_box(box, true); + imm_draw_box(box, true, pos); /* restore state */ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glDisable(GL_BLEND); - glDepthMask(1); + glDepthMask(GL_TRUE); glDisable(GL_CULL_FACE); - glCullFace(GL_BACK); } #endif -static void drawlamp(View3D *v3d, RegionView3D *rv3d, Base *base, - const char dt, const short dflag, const unsigned char ob_wire_col[4], const bool is_obact) +void drawlamp(View3D *v3d, RegionView3D *rv3d, Base *base, + const char dt, const short dflag, const unsigned char ob_wire_col[4], const bool is_obact) { Object *ob = base->object; const float pixsize = ED_view3d_pixel_size(rv3d, ob->obmat[3]); Lamp *la = ob->data; float vec[3], lvec[3], vvec[3], circrad; - float lampsize; float imat[4][4]; - unsigned char curcol[4]; - unsigned char col[4]; /* cone can't be drawn for duplicated lamps, because duplilist would be freed */ /* the moment of view3d_draw_transp() call */ const bool is_view = (rv3d->persp == RV3D_CAMOB && v3d->camera == base->object); @@ -1199,7 +1247,7 @@ static void drawlamp(View3D *v3d, RegionView3D *rv3d, Base *base, !(G.f & G_PICKSEL) && (la->type == LA_SPOT) && (la->mode & LA_SHOW_CONE) && - !(base->flag & OB_FROMDUPLI) && + !(base->flag_legacy & OB_FROMDUPLI) && !is_view); #ifdef WITH_GAMEENGINE @@ -1211,7 +1259,7 @@ static void drawlamp(View3D *v3d, RegionView3D *rv3d, Base *base, ((la->mode & LA_SHAD_BUF) || (la->mode & LA_SHAD_RAY)) && (la->mode & LA_SHOW_SHADOW_BOX) && - !(base->flag & OB_FROMDUPLI) && + !(base->flag_legacy & OB_FROMDUPLI) && !is_view); #else const bool drawshadowbox = false; @@ -1219,118 +1267,158 @@ static void drawlamp(View3D *v3d, RegionView3D *rv3d, Base *base, if ((drawcone || drawshadowbox) && !v3d->transp) { /* in this case we need to draw delayed */ - ED_view3d_after_add(v3d->xray ? &v3d->afterdraw_xraytransp : &v3d->afterdraw_transp, base, dflag); + ED_view3d_after_add(&v3d->afterdraw_transp, base, dflag); return; } - + /* we first draw only the screen aligned & fixed scale stuff */ - glPushMatrix(); - glLoadMatrixf(rv3d->viewmat); + gpuMatrixBegin3D_legacy(); + gpuPushMatrix(); + gpuLoadMatrix3D(rv3d->viewmat); /* lets calculate the scale: */ - lampsize = pixsize * ((float)U.obcenter_dia * 0.5f); + const float lampsize_px = U.obcenter_dia; + const float lampsize = pixsize * lampsize_px * 0.5f; /* and view aligned matrix: */ copy_m4_m4(imat, rv3d->viewinv); normalize_v3(imat[0]); normalize_v3(imat[1]); + const unsigned pos = add_attrib(immVertexFormat(), "pos", GL_FLOAT, 3, KEEP_FLOAT); + /* lamp center */ copy_v3_v3(vec, ob->obmat[3]); + float curcol[4]; if ((dflag & DRAW_CONSTCOLOR) == 0) { /* for AA effects */ - curcol[0] = ob_wire_col[0]; - curcol[1] = ob_wire_col[1]; - curcol[2] = ob_wire_col[2]; - curcol[3] = 154; - glColor4ubv(curcol); + rgb_uchar_to_float(curcol, ob_wire_col); + curcol[3] = 0.6f; + /* TODO: pay attention to GL_BLEND */ } - glLineWidth(1); + glLineWidth(1.0f); + setlinestyle(3); if (lampsize > 0.0f) { + const float outlineWidth = 1.5f * U.pixelsize; + const float lampdot_size = lampsize_px * U.pixelsize + outlineWidth; + /* Inner Circle */ if ((dflag & DRAW_CONSTCOLOR) == 0) { + const float *color = curcol; if (ob->id.us > 1) { - if (is_obact || (ob->flag & SELECT)) { - glColor4ub(0x88, 0xFF, 0xFF, 155); + if (is_obact || ((base->flag & BASE_SELECTED) != 0)) { + static const float active_color[4] = {0.533f, 1.0f, 1.0f, 1.0f}; + color = active_color; } else { - glColor4ub(0x77, 0xCC, 0xCC, 155); + static const float inactive_color[4] = {0.467f, 0.8f, 0.8f, 1.0f}; + color = inactive_color; } } + + GPU_enable_program_point_size(); + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + + immBindBuiltinProgram(GPU_SHADER_3D_POINT_UNIFORM_SIZE_UNIFORM_COLOR_OUTLINE_SMOOTH); + immUniform1f("size", lampdot_size); + immUniform1f("outlineWidth", outlineWidth); + immUniformColor3fvAlpha(color, 0.3f); + immUniform4fv("outlineColor", color); + + immBegin(GL_POINTS, 1); + immVertex3fv(pos, vec); + immEnd(); + + immUnbindProgram(); + + glDisable(GL_BLEND); + GPU_disable_program_point_size(); } - - /* Inner Circle */ - glEnable(GL_BLEND); - drawcircball(GL_LINE_LOOP, vec, lampsize, imat); - glDisable(GL_BLEND); - drawcircball(GL_POLYGON, vec, lampsize, imat); - + else { + /* CONSTCOLOR in effect */ + /* TODO: separate picking from drawing */ + immBindBuiltinProgram(GPU_SHADER_3D_POINT_FIXED_SIZE_UNIFORM_COLOR); + /* color doesn't matter, so don't set */ + glPointSize(lampdot_size); + + immBegin(GL_POINTS, 1); + immVertex3fv(pos, vec); + immEnd(); + + immUnbindProgram(); + } + + immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR); + /* TODO(merwin): short term, use DEPTH_ONLY for picking + * long term, separate picking from drawing + */ + /* restore */ if ((dflag & DRAW_CONSTCOLOR) == 0) { - if (ob->id.us > 1) - glColor4ubv(curcol); + immUniformColor4fv(curcol); } /* Outer circle */ circrad = 3.0f * lampsize; - setlinestyle(3); - drawcircball(GL_LINE_LOOP, vec, circrad, imat); + imm_drawcircball(vec, circrad, imat, pos); /* 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))) { - drawcircball(GL_LINE_LOOP, vec, circrad + 3.0f * pixsize, imat); + imm_drawcircball(vec, circrad + 3.0f * pixsize, imat, pos); } } } else { - setlinestyle(3); + immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR); + immUniformColor4fv(curcol); circrad = 0.0f; } - + /* draw the pretty sun rays */ if (la->type == LA_SUN) { float v1[3], v2[3], mat[3][3]; short axis; - + /* setup a 45 degree rotation matrix */ axis_angle_normalized_to_mat3_ex(mat, imat[2], M_SQRT1_2, M_SQRT1_2); /* vectors */ mul_v3_v3fl(v1, imat[0], circrad * 1.2f); mul_v3_v3fl(v2, imat[0], circrad * 2.5f); - + /* center */ - glTranslate3fv(vec); - + gpuPushMatrix(); + gpuTranslate3fv(vec); + setlinestyle(3); - - glBegin(GL_LINES); + + immBegin(GL_LINES, 16); for (axis = 0; axis < 8; axis++) { - glVertex3fv(v1); - glVertex3fv(v2); + immVertex3fv(pos, v1); + immVertex3fv(pos, v2); mul_m3_v3(mat, v1); mul_m3_v3(mat, v2); } - glEnd(); - - glTranslatef(-vec[0], -vec[1], -vec[2]); + immEnd(); + gpuPopMatrix(); } - + if (la->type == LA_LOCAL) { if (la->mode & LA_SPHERE) { - drawcircball(GL_LINE_LOOP, vec, la->dist, imat); + imm_drawcircball(vec, la->dist, imat, pos); } } - - glPopMatrix(); /* back in object space */ + + gpuPopMatrix(); /* back in object space */ zero_v3(vec); - + if (is_view) { /* skip drawing extra info */ } @@ -1362,24 +1450,18 @@ static void drawlamp(View3D *v3d, RegionView3D *rv3d, Base *base, {z_abs, -z_abs, x}, {-z_abs, z_abs, x}, }; - const unsigned char indices[] = { - 0, 1, 3, - 0, 3, 2, - 0, 2, 4, - 0, 1, 4, - }; - - /* Draw call: - * activate and specify pointer to vertex array */ - glEnableClientState(GL_VERTEX_ARRAY); - glVertexPointer(3, GL_FLOAT, 0, vertices); - /* draw the pyramid */ - glDrawElements(GL_LINE_STRIP, 12, GL_UNSIGNED_BYTE, indices); - /* deactivate vertex arrays after drawing */ - glDisableClientState(GL_VERTEX_ARRAY); + immBegin(GL_LINES, 16); + for (int i = 1; i <= 4; ++i) { + immVertex3fv(pos, vertices[0]); /* apex to corner */ + immVertex3fv(pos, vertices[i]); + int next_i = (i == 4) ? 1 : (i + 1); + immVertex3fv(pos, vertices[i]); /* corner to next corner */ + immVertex3fv(pos, vertices[next_i]); + } + immEnd(); - glTranslatef(0.0f, 0.0f, x); + gpuTranslate3f(0.0f, 0.0f, x); /* draw the square representing spotbl */ if (la->type == LA_SPOT) { @@ -1389,22 +1471,21 @@ static void drawlamp(View3D *v3d, RegionView3D *rv3d, Base *base, * previously it adjusted to always to show it but that seems * confusing because it doesn't show the actual blend size */ if (blend != 0.0f && blend != z_abs) { - fdrawbox(blend, -blend, -blend, blend); + imm_draw_line_box_3D(pos, blend, -blend, -blend, blend); } } } else { - /* draw the angled sides of the cone */ - glBegin(GL_LINE_STRIP); - glVertex3fv(vvec); - glVertex3fv(vec); - glVertex3fv(lvec); - glEnd(); + immBegin(GL_LINE_STRIP, 3); + immVertex3fv(pos, vvec); + immVertex3fv(pos, vec); + immVertex3fv(pos, lvec); + immEnd(); /* draw the circle at the end of the cone */ - glTranslatef(0.0f, 0.0f, x); - circ(0.0f, 0.0f, z_abs); + gpuTranslate3f(0.0f, 0.0f, x); + imm_draw_lined_circle_3D(pos, 0.0f, 0.0f, z_abs, 32); /* draw the circle representing spotbl */ if (la->type == LA_SPOT) { @@ -1414,17 +1495,17 @@ static void drawlamp(View3D *v3d, RegionView3D *rv3d, Base *base, * previously it adjusted to always to show it but that seems * confusing because it doesn't show the actual blend size */ if (blend != 0.0f && blend != z_abs) { - circ(0.0f, 0.0f, blend); + imm_draw_lined_circle_3D(pos, 0.0f, 0.0f, blend, 32); } } } if (drawcone) - draw_transp_spot_volume(la, x, z); + draw_transp_spot_volume(la, x, z, pos); /* draw clip start, useful for wide cones where its not obvious where the start is */ - glTranslatef(0.0, 0.0, -x); /* reverse translation above */ - glBegin(GL_LINES); + gpuTranslate3f(0.0f, 0.0f, -x); /* reverse translation above */ + immBegin(GL_LINES, 2); if (la->type == LA_SPOT && (la->mode & LA_SHAD_BUF)) { float lvec_clip[3]; float vvec_clip[3]; @@ -1433,41 +1514,40 @@ static void drawlamp(View3D *v3d, RegionView3D *rv3d, Base *base, interp_v3_v3v3(lvec_clip, vec, lvec, clipsta_fac); interp_v3_v3v3(vvec_clip, vec, vvec, clipsta_fac); - glVertex3fv(lvec_clip); - glVertex3fv(vvec_clip); + immVertex3fv(pos, lvec_clip); + immVertex3fv(pos, vvec_clip); } /* Else, draw spot direction (using distance as end limit, same as for Area lamp). */ else { - glVertex3f(0.0, 0.0, -circrad); - glVertex3f(0.0, 0.0, -la->dist); + immVertex3f(pos, 0.0f, 0.0f, -circrad); + immVertex3f(pos, 0.0f, 0.0f, -la->dist); } - glEnd(); + immEnd(); } else if (ELEM(la->type, LA_HEMI, LA_SUN)) { - /* draw the line from the circle along the dist */ - glBegin(GL_LINES); + immBegin(GL_LINES, 2); vec[2] = -circrad; - glVertex3fv(vec); + immVertex3fv(pos, vec); vec[2] = -la->dist; - glVertex3fv(vec); - glEnd(); - + immVertex3fv(pos, vec); + immEnd(); + if (la->type == LA_HEMI) { /* draw the hemisphere curves */ short axis, steps, dir; float outdist, zdist, mul; zero_v3(vec); - outdist = 0.14; mul = 1.4; dir = 1; - + outdist = 0.14f; mul = 1.4f; dir = 1; + setlinestyle(4); /* loop over the 4 compass points, and draw each arc as a LINE_STRIP */ for (axis = 0; axis < 4; axis++) { - float v[3] = {0.0, 0.0, 0.0}; - zdist = 0.02; - - glBegin(GL_LINE_STRIP); - + float v[3] = {0.0f, 0.0f, 0.0f}; + zdist = 0.02f; + + immBegin(GL_LINE_STRIP, 6); + for (steps = 0; steps < 6; steps++) { if (axis == 0 || axis == 1) { /* x axis up, x axis down */ /* make the arcs start at the edge of the energy circle */ @@ -1480,13 +1560,13 @@ static void drawlamp(View3D *v3d, RegionView3D *rv3d, Base *base, } v[2] = v[2] - steps * zdist; - - glVertex3fv(v); - + + immVertex3fv(pos, v); + zdist = zdist * mul; } - - glEnd(); + + immEnd(); /* flip the direction */ dir = -dir; } @@ -1494,96 +1574,92 @@ static void drawlamp(View3D *v3d, RegionView3D *rv3d, Base *base, #ifdef WITH_GAMEENGINE if (drawshadowbox) { - draw_transp_sun_volume(la); + draw_transp_sun_volume(la, pos); } #endif - } else if (la->type == LA_AREA) { setlinestyle(3); if (la->area_shape == LA_AREA_SQUARE) - fdrawbox(-la->area_size * 0.5f, -la->area_size * 0.5f, la->area_size * 0.5f, la->area_size * 0.5f); + imm_draw_line_box_3D(pos, -la->area_size * 0.5f, -la->area_size * 0.5f, la->area_size * 0.5f, la->area_size * 0.5f); else if (la->area_shape == LA_AREA_RECT) - fdrawbox(-la->area_size * 0.5f, -la->area_sizey * 0.5f, la->area_size * 0.5f, la->area_sizey * 0.5f); + imm_draw_line_box_3D(pos, -la->area_size * 0.5f, -la->area_sizey * 0.5f, la->area_size * 0.5f, la->area_sizey * 0.5f); - glBegin(GL_LINES); - glVertex3f(0.0, 0.0, -circrad); - glVertex3f(0.0, 0.0, -la->dist); - glEnd(); + immBegin(GL_LINES, 2); + immVertex3f(pos, 0.0f, 0.0f, -circrad); + immVertex3f(pos, 0.0f, 0.0f, -la->dist); + immEnd(); } - + /* and back to viewspace */ - glPushMatrix(); - glLoadMatrixf(rv3d->viewmat); + gpuPushMatrix(); + gpuLoadMatrix3D(rv3d->viewmat); copy_v3_v3(vec, ob->obmat[3]); setlinestyle(0); - + if ((la->type == LA_SPOT) && (la->mode & LA_SHAD_BUF) && (is_view == false)) { - drawshadbuflimits(la, ob->obmat); + drawshadbuflimits(la, ob->obmat, pos); } - + if ((dflag & DRAW_CONSTCOLOR) == 0) { - UI_GetThemeColor4ubv(TH_LAMP, col); - glColor4ubv(col); + immUniformThemeColor(TH_LAMP); } glEnable(GL_BLEND); - + if (vec[2] > 0) vec[2] -= circrad; else vec[2] += circrad; - - glBegin(GL_LINES); - glVertex3fv(vec); + + immBegin(GL_LINES, 2); + immVertex3fv(pos, vec); vec[2] = 0; - glVertex3fv(vec); - glEnd(); - - glPointSize(2.0); - glBegin(GL_POINTS); - glVertex3fv(vec); - glEnd(); - + immVertex3fv(pos, vec); + immEnd(); + + glPointSize(2.0f); + immBegin(GL_POINTS, 1); + immVertex3fv(pos, vec); + immEnd(); + glDisable(GL_BLEND); - - if ((dflag & DRAW_CONSTCOLOR) == 0) { - /* restore for drawing extra stuff */ - glColor3ubv(ob_wire_col); - } - /* and finally back to org object space! */ - glPopMatrix(); + + immUnbindProgram(); + gpuMatrixEnd(); } -static void draw_limit_line(float sta, float end, const short dflag, const unsigned char col[3]) +static void draw_limit_line(float sta, float end, const short dflag, const unsigned char col[3], unsigned pos) { - glBegin(GL_LINES); - glVertex3f(0.0, 0.0, -sta); - glVertex3f(0.0, 0.0, -end); - glEnd(); + immBegin(GL_LINES, 2); + immVertex3f(pos, 0.0f, 0.0f, -sta); + immVertex3f(pos, 0.0f, 0.0f, -end); + immEnd(); if (!(dflag & DRAW_PICKING)) { - glPointSize(3.0); - glBegin(GL_POINTS); + glPointSize(3.0f); + /* would like smooth round points here, but that means binding another shader... + * if it's really desired, pull these points into their own function to be called after */ + immBegin(GL_POINTS, 2); if ((dflag & DRAW_CONSTCOLOR) == 0) { - glColor3ubv(col); + immUniformColor3ubv(col); } - glVertex3f(0.0, 0.0, -sta); - glVertex3f(0.0, 0.0, -end); - glEnd(); + immVertex3f(pos, 0.0f, 0.0f, -sta); + immVertex3f(pos, 0.0f, 0.0f, -end); + immEnd(); } } /* yafray: draw camera focus point (cross, similar to aqsis code in tuhopuu) */ /* qdn: now also enabled for Blender to set focus point for defocus composite node */ -static void draw_focus_cross(float dist, float size) +static void draw_focus_cross(float dist, float size, unsigned pos) { - glBegin(GL_LINES); - glVertex3f(-size, 0.0f, -dist); - glVertex3f(size, 0.0f, -dist); - glVertex3f(0.0f, -size, -dist); - glVertex3f(0.0f, size, -dist); - glEnd(); + immBegin(GL_LINES, 4); + immVertex3f(pos, -size, 0.0f, -dist); + immVertex3f(pos, size, 0.0f, -dist); + immVertex3f(pos, 0.0f, -size, -dist); + immVertex3f(pos, 0.0f, size, -dist); + immEnd(); } #ifdef VIEW3D_CAMERA_BORDER_HACK @@ -1614,7 +1690,7 @@ static void draw_bundle_sphere(void) } static void draw_viewport_object_reconstruction( - Scene *scene, Base *base, const View3D *v3d, const RegionView3D *rv3d, + Scene *scene, BaseLegacy *base, const View3D *v3d, const RegionView3D *rv3d, MovieClip *clip, MovieTrackingObject *tracking_object, const short dflag, const unsigned char ob_wire_col[4], int *global_track_index, bool draw_selected) @@ -1679,16 +1755,19 @@ static void draw_viewport_object_reconstruction( const int v3d_drawtype = view3d_effective_drawtype(v3d); if (v3d_drawtype == OB_WIRE) { + unsigned char color[4]; + const unsigned char *color_ptr = NULL; if ((dflag & DRAW_CONSTCOLOR) == 0) { if (selected && (track->flag & TRACK_CUSTOMCOLOR) == 0) { - glColor3ubv(ob_wire_col); + color_ptr = ob_wire_col; } else { - glColor3fv(track->color); + rgba_float_to_uchar(color, track->color); + color_ptr = color; } } - drawaxes(rv3d->viewmatob, 0.05f, v3d->bundle_drawtype); + drawaxes(rv3d->viewmatob, 0.05f, v3d->bundle_drawtype, color_ptr); } else if (v3d_drawtype > OB_WIRE) { if (v3d->bundle_drawtype == OB_EMPTY_SPHERE) { @@ -1714,17 +1793,21 @@ static void draw_viewport_object_reconstruction( draw_bundle_sphere(); } else { + unsigned char color[4]; + const unsigned char *color_ptr = NULL; if ((dflag & DRAW_CONSTCOLOR) == 0) { if (selected) { - glColor3ubv(ob_wire_col); + color_ptr = ob_wire_col; } else { - if (track->flag & TRACK_CUSTOMCOLOR) glColor3fv(track->color); - else UI_ThemeColor(TH_WIRE); + if (track->flag & TRACK_CUSTOMCOLOR) rgba_float_to_uchar(color, track->color); + else UI_GetThemeColor4ubv(TH_WIRE, color); + + color_ptr = color; } } - drawaxes(rv3d->viewmatob, 0.05f, v3d->bundle_drawtype); + drawaxes(rv3d->viewmatob, 0.05f, v3d->bundle_drawtype, color_ptr); } } @@ -1769,7 +1852,7 @@ static void draw_viewport_object_reconstruction( } static void draw_viewport_reconstruction( - Scene *scene, Base *base, const View3D *v3d, const RegionView3D *rv3d, MovieClip *clip, + Scene *scene, BaseLegacy *base, const View3D *v3d, const RegionView3D *rv3d, MovieClip *clip, const short dflag, const unsigned char ob_wire_col[4], const bool draw_selected) { @@ -1806,59 +1889,68 @@ static void draw_viewport_reconstruction( GPU_select_load_id(base->selcol); } -static void drawcamera_volume(float near_plane[4][3], float far_plane[4][3], const GLenum mode) -{ - glBegin(mode); - glVertex3fv(near_plane[0]); - glVertex3fv(far_plane[0]); - glVertex3fv(far_plane[1]); - glVertex3fv(near_plane[1]); - glEnd(); - - glBegin(mode); - glVertex3fv(near_plane[1]); - glVertex3fv(far_plane[1]); - glVertex3fv(far_plane[2]); - glVertex3fv(near_plane[2]); - glEnd(); - - glBegin(mode); - glVertex3fv(near_plane[2]); - glVertex3fv(near_plane[1]); - glVertex3fv(far_plane[1]); - glVertex3fv(far_plane[2]); - glEnd(); - - glBegin(mode); - glVertex3fv(far_plane[0]); - glVertex3fv(near_plane[0]); - glVertex3fv(near_plane[3]); - glVertex3fv(far_plane[3]); - glEnd(); -} - /* camera frame */ -static void drawcamera_frame(float vec[4][3], const GLenum mode) +static void drawcamera_frame(float vec[4][3], bool filled, unsigned pos) { - glBegin(mode); - glVertex3fv(vec[0]); - glVertex3fv(vec[1]); - glVertex3fv(vec[2]); - glVertex3fv(vec[3]); - glEnd(); + immBegin(filled ? GL_QUADS : GL_LINE_LOOP, 4); + immVertex3fv(pos, vec[0]); + immVertex3fv(pos, vec[1]); + immVertex3fv(pos, vec[2]); + immVertex3fv(pos, vec[3]); + immEnd(); } /* center point to camera frame */ -static void drawcamera_framelines(float vec[4][3], float origin[3]) -{ - glBegin(GL_LINE_STRIP); - glVertex3fv(vec[1]); - glVertex3fv(origin); - glVertex3fv(vec[0]); - glVertex3fv(vec[3]); - glVertex3fv(origin); - glVertex3fv(vec[2]); - glEnd(); +static void drawcamera_framelines(float vec[4][3], float origin[3], unsigned pos) +{ + immBegin(GL_LINES, 8); + immVertex3fv(pos, origin); + immVertex3fv(pos, vec[0]); + immVertex3fv(pos, origin); + immVertex3fv(pos, vec[1]); + immVertex3fv(pos, origin); + immVertex3fv(pos, vec[2]); + immVertex3fv(pos, origin); + immVertex3fv(pos, vec[3]); + immEnd(); +} + +static void drawcamera_volume(float near_plane[4][3], float far_plane[4][3], bool filled, unsigned pos) +{ + drawcamera_frame(near_plane, filled, pos); + drawcamera_frame(far_plane, filled, pos); + + if (filled) { + immBegin(GL_QUADS, 16); /* TODO(merwin): use GL_TRIANGLE_STRIP here */ + immVertex3fv(pos, near_plane[0]); + immVertex3fv(pos, far_plane[0]); + immVertex3fv(pos, far_plane[1]); + immVertex3fv(pos, near_plane[1]); + + immVertex3fv(pos, near_plane[1]); + immVertex3fv(pos, far_plane[1]); + immVertex3fv(pos, far_plane[2]); + immVertex3fv(pos, near_plane[2]); + + immVertex3fv(pos, near_plane[2]); + immVertex3fv(pos, near_plane[1]); + immVertex3fv(pos, far_plane[1]); + immVertex3fv(pos, far_plane[2]); + + immVertex3fv(pos, far_plane[0]); + immVertex3fv(pos, near_plane[0]); + immVertex3fv(pos, near_plane[3]); + immVertex3fv(pos, far_plane[3]); + immEnd(); + } + else { + immBegin(GL_LINES, 8); + for (int i = 0; i < 4; ++i) { + immVertex3fv(pos, near_plane[i]); + immVertex3fv(pos, far_plane[i]); + } + immEnd(); + } } static bool drawcamera_is_stereo3d(Scene *scene, View3D *v3d, Object *ob) @@ -1870,7 +1962,7 @@ static bool drawcamera_is_stereo3d(Scene *scene, View3D *v3d, Object *ob) static void drawcamera_stereo3d( Scene *scene, View3D *v3d, RegionView3D *rv3d, Object *ob, const Camera *cam, - float vec[4][3], float drawsize, const float scale[3]) + float vec[4][3], float drawsize, const float scale[3], unsigned pos) { float obmat[4][4]; float vec_lr[2][4][3]; @@ -1886,15 +1978,15 @@ static void drawcamera_stereo3d( zero_v3(tvec); - glPushMatrix(); + /* caller bound GPU_SHADER_3D_UNIFORM_COLOR, passed in pos attribute ID */ for (int i = 0; i < 2; i++) { ob = BKE_camera_multiview_render(scene, ob, names[i]); cam_lr[i] = ob->data; - glLoadMatrixf(rv3d->viewmat); + gpuLoadMatrix3D(rv3d->viewmat); BKE_camera_multiview_model_matrix(&scene->r, ob, names[i], obmat); - glMultMatrixf(obmat); + gpuMultMatrix3D(obmat); copy_m3_m3(vec_lr[i], vec); copy_v3_v3(vec_lr[i][3], vec[3]); @@ -1911,10 +2003,10 @@ static void drawcamera_stereo3d( if (is_stereo3d_cameras) { /* camera frame */ - drawcamera_frame(vec_lr[i], GL_LINE_LOOP); + drawcamera_frame(vec_lr[i], false, pos); /* center point to camera frame */ - drawcamera_framelines(vec_lr[i], tvec); + drawcamera_framelines(vec_lr[i], tvec, pos); } /* connecting line */ @@ -1928,21 +2020,21 @@ static void drawcamera_stereo3d( } } - /* the remaining drawing takes place in the view space */ - glLoadMatrixf(rv3d->viewmat); + gpuLoadMatrix3D(rv3d->viewmat); if (is_stereo3d_cameras) { /* draw connecting lines */ - GPU_basic_shader_bind_enable(GPU_SHADER_LINE | GPU_SHADER_STIPPLE); - GPU_basic_shader_line_stipple(2, 0xAAAA); + glPushAttrib(GL_ENABLE_BIT); /* TODO(merwin): new state tracking! */ + glLineStipple(2, 0xAAAA); + glEnable(GL_LINE_STIPPLE); - glBegin(GL_LINES); - glVertex3fv(origin[0]); - glVertex3fv(origin[1]); - glEnd(); + immBegin(GL_LINES, 2); + immVertex3fv(pos, origin[0]); + immVertex3fv(pos, origin[1]); + immEnd(); - GPU_basic_shader_bind_disable(GPU_SHADER_LINE | GPU_SHADER_STIPPLE); + glPopAttrib(); } /* draw convergence plane */ @@ -1967,21 +2059,21 @@ static void drawcamera_stereo3d( add_v3_v3(local_plane[i], axis_center); } - glColor3f(0.0f, 0.0f, 0.0f); + immUniformColor3f(0.0f, 0.0f, 0.0f); /* camera frame */ - drawcamera_frame(local_plane, GL_LINE_LOOP); + drawcamera_frame(local_plane, false, pos); if (v3d->stereo3d_convergence_alpha > 0.0f) { glEnable(GL_BLEND); - glDepthMask(0); /* disable write in zbuffer, needed for nice transp */ + glDepthMask(GL_FALSE); /* disable write in zbuffer, needed for nice transp */ - glColor4f(0.0f, 0.0f, 0.0f, v3d->stereo3d_convergence_alpha); + immUniformColor4f(0.0f, 0.0f, 0.0f, v3d->stereo3d_convergence_alpha); - drawcamera_frame(local_plane, GL_QUADS); + drawcamera_frame(local_plane, true, pos); glDisable(GL_BLEND); - glDepthMask(1); /* restore write in zbuffer */ + glDepthMask(GL_TRUE); /* restore write in zbuffer */ } } @@ -2006,37 +2098,31 @@ static void drawcamera_stereo3d( } /* camera frame */ - glColor3f(0.0f, 0.0f, 0.0f); + immUniformColor3f(0.0f, 0.0f, 0.0f); - drawcamera_frame(near_plane, GL_LINE_LOOP); - drawcamera_frame(far_plane, GL_LINE_LOOP); - drawcamera_volume(near_plane, far_plane, GL_LINE_LOOP); + drawcamera_volume(near_plane, far_plane, false, pos); if (v3d->stereo3d_volume_alpha > 0.0f) { glEnable(GL_BLEND); - glDepthMask(0); /* disable write in zbuffer, needed for nice transp */ + glDepthMask(GL_FALSE); /* disable write in zbuffer, needed for nice transp */ if (i == 0) - glColor4f(0.0f, 1.0f, 1.0f, v3d->stereo3d_volume_alpha); + immUniformColor4f(0.0f, 1.0f, 1.0f, v3d->stereo3d_volume_alpha); else - glColor4f(1.0f, 0.0f, 0.0f, v3d->stereo3d_volume_alpha); + immUniformColor4f(1.0f, 0.0f, 0.0f, v3d->stereo3d_volume_alpha); - drawcamera_frame(near_plane, GL_QUADS); - drawcamera_frame(far_plane, GL_QUADS); - drawcamera_volume(near_plane, far_plane, GL_QUADS); + drawcamera_volume(near_plane, far_plane, true, pos); glDisable(GL_BLEND); - glDepthMask(1); /* restore write in zbuffer */ + glDepthMask(GL_TRUE); /* restore write in zbuffer */ } } } - - glPopMatrix(); } /* flag similar to draw_object() */ -static void drawcamera(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base *base, - const short dflag, const unsigned char ob_wire_col[4]) +void drawcamera(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base *base, + const short dflag, const unsigned char ob_wire_col[4]) { /* a standing up pyramid with (0,0,0) as top */ Camera *cam; @@ -2099,8 +2185,14 @@ static void drawcamera(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base *base BKE_camera_view_frame_ex(scene, cam, cam->drawsize, is_view, scale, asp, shift, &drawsize, vec); - glDisable(GL_CULL_FACE); - glLineWidth(1); + gpuMatrixBegin3D_legacy(); + + unsigned pos = add_attrib(immVertexFormat(), "pos", GL_FLOAT, 3, KEEP_FLOAT); + immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR); + if (ob_wire_col) { + immUniformColor3ubv(ob_wire_col); + } + glLineWidth(1.0f); /* camera frame */ if (!is_stereo3d_cameras) { @@ -2109,27 +2201,30 @@ static void drawcamera(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base *base float obmat[4][4]; bool is_left = v3d->multiview_eye == STEREO_LEFT_ID; - glPushMatrix(); - glLoadMatrixf(rv3d->viewmat); + gpuPushMatrix(); + gpuLoadMatrix3D(rv3d->viewmat); BKE_camera_multiview_model_matrix(&scene->r, ob, is_left ? STEREO_LEFT_NAME : STEREO_RIGHT_NAME, obmat); - glMultMatrixf(obmat); + gpuMultMatrix3D(obmat); - drawcamera_frame(vec, GL_LINE_LOOP); - glPopMatrix(); + drawcamera_frame(vec, false, pos); + gpuPopMatrix(); } else { - drawcamera_frame(vec, GL_LINE_LOOP); + drawcamera_frame(vec, false, pos); } } - if (is_view) + if (is_view) { + immUnbindProgram(); + gpuMatrixEnd(); return; + } zero_v3(tvec); /* center point to camera frame */ if (!is_stereo3d_cameras) - drawcamera_framelines(vec, tvec); + drawcamera_framelines(vec, tvec, pos); /* arrow on top */ tvec[2] = vec[1][2]; /* copy the depth */ @@ -2138,22 +2233,25 @@ static void drawcamera(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base *base * for active cameras. We actually draw both outline+filled * for active cameras so the wire can be seen side-on */ for (int i = 0; i < 2; i++) { - if (i == 0) glBegin(GL_LINE_LOOP); - else if (i == 1 && is_active) glBegin(GL_TRIANGLES); + if (i == 0) immBegin(GL_LINE_LOOP, 3); + else if (i == 1 && is_active) { + glDisable(GL_CULL_FACE); /* TODO: declarative state tracking */ + immBegin(GL_TRIANGLES, 3); + } else break; tvec[0] = shift[0] + ((-0.7f * drawsize) * scale[0]); tvec[1] = shift[1] + ((drawsize * (asp[1] + 0.1f)) * scale[1]); - glVertex3fv(tvec); /* left */ + immVertex3fv(pos, tvec); /* left */ tvec[0] = shift[0] + ((0.7f * drawsize) * scale[0]); - glVertex3fv(tvec); /* right */ + immVertex3fv(pos, tvec); /* right */ tvec[0] = shift[0]; tvec[1] = shift[1] + ((1.1f * drawsize * (asp[1] + 0.7f)) * scale[1]); - glVertex3fv(tvec); /* top */ + immVertex3fv(pos, tvec); /* top */ - glEnd(); + immEnd(); } if ((dflag & DRAW_SCENESET) == 0) { @@ -2164,16 +2262,15 @@ static void drawcamera(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base *base copy_m4_m4(nobmat, ob->obmat); normalize_m4(nobmat); - glPushMatrix(); - glLoadMatrixf(rv3d->viewmat); - glMultMatrixf(nobmat); + gpuLoadMatrix3D(rv3d->viewmat); + gpuMultMatrix3D(nobmat); if (cam->flag & CAM_SHOWLIMITS) { const unsigned char col[3] = {128, 128, 60}, col_hi[3] = {255, 255, 120}; - draw_limit_line(cam->clipsta, cam->clipend, dflag, (is_active ? col_hi : col)); + draw_limit_line(cam->clipsta, cam->clipend, dflag, (is_active ? col_hi : col), pos); /* qdn: was yafray only, now also enabled for Blender to be used with defocus composite node */ - draw_focus_cross(BKE_camera_object_dof_distance(ob), cam->drawsize); + draw_focus_cross(BKE_camera_object_dof_distance(ob), cam->drawsize, pos); } if (cam->flag & CAM_SHOWMIST) { @@ -2182,57 +2279,66 @@ static void drawcamera(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base *base if (world) { draw_limit_line(world->miststa, world->miststa + world->mistdist, - dflag, (is_active ? col_hi : col)); + dflag, (is_active ? col_hi : col), pos); } } - glPopMatrix(); } } /* stereo cameras drawing */ if (is_stereo3d) { - drawcamera_stereo3d(scene, v3d, rv3d, ob, cam, vec, drawsize, scale); + drawcamera_stereo3d(scene, v3d, rv3d, ob, cam, vec, drawsize, scale, pos); } + + immUnbindProgram(); + gpuMatrixEnd(); } /* flag similar to draw_object() */ -static void drawspeaker(Scene *UNUSED(scene), View3D *UNUSED(v3d), RegionView3D *UNUSED(rv3d), - Object *UNUSED(ob), int UNUSED(flag)) +void drawspeaker(const unsigned char ob_wire_col[3]) { - float vec[3]; + VertexFormat *format = immVertexFormat(); + unsigned int pos = add_attrib(format, "pos", GL_FLOAT, 3, KEEP_FLOAT); - glEnable(GL_BLEND); - glLineWidth(1); + immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR); + + if (ob_wire_col) { + immUniformColor3ubv(ob_wire_col); + } + + glLineWidth(1.0f); + + const int segments = 16; for (int j = 0; j < 3; j++) { - vec[2] = 0.25f * j - 0.125f; + float z = 0.25f * j - 0.125f; - glBegin(GL_LINE_LOOP); - for (int i = 0; i < 16; i++) { - vec[0] = cosf((float)M_PI * i / 8.0f) * (j == 0 ? 0.5f : 0.25f); - vec[1] = sinf((float)M_PI * i / 8.0f) * (j == 0 ? 0.5f : 0.25f); - glVertex3fv(vec); + immBegin(GL_LINE_LOOP, segments); + for (int i = 0; i < segments; i++) { + float x = cosf((float)M_PI * i / 8.0f) * (j == 0 ? 0.5f : 0.25f); + float y = sinf((float)M_PI * i / 8.0f) * (j == 0 ? 0.5f : 0.25f); + immVertex3f(pos, x, y, z); } - glEnd(); + immEnd(); } for (int j = 0; j < 4; j++) { - vec[0] = (((j + 1) % 2) * (j - 1)) * 0.5f; - vec[1] = ((j % 2) * (j - 2)) * 0.5f; - glBegin(GL_LINE_STRIP); + float x = (((j + 1) % 2) * (j - 1)) * 0.5f; + float y = ((j % 2) * (j - 2)) * 0.5f; + immBegin(GL_LINE_STRIP, 3); for (int i = 0; i < 3; i++) { if (i == 1) { - vec[0] *= 0.5f; - vec[1] *= 0.5f; + x *= 0.5f; + y *= 0.5f; } - vec[2] = 0.25f * i - 0.125f; - glVertex3fv(vec); + float z = 0.25f * i - 0.125f; + immVertex3f(pos, x, y, z); } - glEnd(); + immEnd(); } - glDisable(GL_BLEND); + immUnbindProgram(); } static void lattice_draw_verts(Lattice *lt, DispList *dl, BPoint *actbp, short sel) @@ -2357,7 +2463,7 @@ static void drawlattice(View3D *v3d, Object *ob) } } - glLineWidth(1); + glLineWidth(1.0f); glBegin(GL_LINES); for (w = 0; w < lt->pntsw; w++) { int wxt = (w == 0 || w == lt->pntsw - 1); @@ -3075,7 +3181,7 @@ static void draw_dm_creases(BMEditMesh *em, DerivedMesh *dm) data.cd_layer_offset = CustomData_get_offset(&em->bm->edata, CD_CREASE); if (data.cd_layer_offset != -1) { - glLineWidth(3.0); + glLineWidth(3.0f); dm->drawMappedEdges(dm, draw_dm_creases__setDrawOptions, &data); } } @@ -3121,7 +3227,7 @@ static void draw_dm_bweights(BMEditMesh *em, Scene *scene, DerivedMesh *dm) data.cd_layer_offset = CustomData_get_offset(&em->bm->vdata, CD_BWEIGHT); if (data.cd_layer_offset != -1) { - glPointSize(UI_GetThemeValuef(TH_VERTEX_SIZE) + 2); + glPointSize(UI_GetThemeValuef(TH_VERTEX_SIZE) + 2.0f); glBegin(GL_POINTS); dm->foreachMappedVert(dm, draw_dm_bweights__mapFunc, &data, DM_FOREACH_NOP); glEnd(); @@ -3134,7 +3240,7 @@ static void draw_dm_bweights(BMEditMesh *em, Scene *scene, DerivedMesh *dm) data.cd_layer_offset = CustomData_get_offset(&em->bm->edata, CD_BWEIGHT); if (data.cd_layer_offset != -1) { - glLineWidth(3.0); + glLineWidth(3.0f); dm->drawMappedEdges(dm, draw_dm_bweights__setDrawOptions, &data); } } @@ -3155,7 +3261,7 @@ static void draw_em_fancy_verts(Scene *scene, View3D *v3d, Object *obedit, { ToolSettings *ts = scene->toolsettings; - if (v3d->zbuf) glDepthMask(0); /* disable write in zbuffer, zbuf select */ + if (v3d->zbuf) glDepthMask(GL_FALSE); /* disable write in zbuffer, zbuf select */ for (int sel = 0; sel < 2; sel++) { unsigned char col[4], fcol[4]; @@ -3203,7 +3309,7 @@ static void draw_em_fancy_verts(Scene *scene, View3D *v3d, Object *obedit, } } - if (v3d->zbuf) glDepthMask(1); + if (v3d->zbuf) glDepthMask(GL_TRUE); } static void draw_em_fancy_edges(BMEditMesh *em, Scene *scene, View3D *v3d, @@ -3687,7 +3793,7 @@ static void draw_em_fancy(Scene *scene, ARegion *ar, View3D *v3d, const bool use_occlude_wire = (dt > OB_WIRE) && (v3d->flag2 & V3D_OCCLUDE_WIRE); bool use_depth_offset = false; - glLineWidth(1); + glLineWidth(1.0f); BM_mesh_elem_table_ensure(em->bm, BM_VERT | BM_EDGE | BM_FACE); @@ -3696,7 +3802,7 @@ static void draw_em_fancy(Scene *scene, ARegion *ar, View3D *v3d, draw_mesh_paint_weight_faces(finalDM, true, draw_em_fancy__setFaceOpts, me->edit_btmesh); ED_view3d_polygon_offset(rv3d, 1.0); - glDepthMask(0); + glDepthMask(GL_FALSE); use_depth_offset = true; } else { @@ -3743,7 +3849,7 @@ static void draw_em_fancy(Scene *scene, ARegion *ar, View3D *v3d, UI_ThemeColor(TH_WIRE_EDIT); ED_view3d_polygon_offset(rv3d, 1.0); - glDepthMask(0); + glDepthMask(GL_FALSE); use_depth_offset = true; } else { @@ -3793,7 +3899,7 @@ static void draw_em_fancy(Scene *scene, ARegion *ar, View3D *v3d, #endif glEnable(GL_BLEND); - glDepthMask(0); /* disable write in zbuffer, needed for nice transp */ + glDepthMask(GL_FALSE); /* disable write in zbuffer, needed for nice transp */ /* don't draw unselected faces, only selected, this is MUCH nicer when texturing */ if (check_object_draw_texture(scene, v3d, dt)) @@ -3809,7 +3915,7 @@ static void draw_em_fancy(Scene *scene, ARegion *ar, View3D *v3d, #endif glDisable(GL_BLEND); - glDepthMask(1); /* restore write in zbuffer */ + glDepthMask(GL_TRUE); /* restore write in zbuffer */ } else if (efa_act) { /* even if draw faces is off it would be nice to draw the stipple face @@ -3824,7 +3930,7 @@ static void draw_em_fancy(Scene *scene, ARegion *ar, View3D *v3d, UI_GetThemeColor4ubv(TH_EDITMESH_ACTIVE, col3); glEnable(GL_BLEND); - glDepthMask(0); /* disable write in zbuffer, needed for nice transp */ + glDepthMask(GL_FALSE); /* disable write in zbuffer, needed for nice transp */ #ifdef WITH_FREESTYLE draw_dm_faces_sel(em, cageDM, col1, col2, col3, col4, efa_act); @@ -3833,7 +3939,7 @@ static void draw_em_fancy(Scene *scene, ARegion *ar, View3D *v3d, #endif glDisable(GL_BLEND); - glDepthMask(1); /* restore write in zbuffer */ + glDepthMask(GL_TRUE); /* restore write in zbuffer */ } /* here starts all fancy draw-extra over */ @@ -3847,7 +3953,7 @@ static void draw_em_fancy(Scene *scene, ARegion *ar, View3D *v3d, else { if (me->drawflag & ME_DRAWSEAMS) { UI_ThemeColor(TH_EDGE_SEAM); - glLineWidth(2); + glLineWidth(2.0f); draw_dm_edges_seams(em, cageDM); @@ -3856,7 +3962,7 @@ static void draw_em_fancy(Scene *scene, ARegion *ar, View3D *v3d, if (me->drawflag & ME_DRAWSHARP) { UI_ThemeColor(TH_EDGE_SHARP); - glLineWidth(2); + glLineWidth(2.0f); draw_dm_edges_sharp(em, cageDM); @@ -3866,7 +3972,7 @@ static void draw_em_fancy(Scene *scene, ARegion *ar, View3D *v3d, #ifdef WITH_FREESTYLE if (me->drawflag & ME_DRAW_FREESTYLE_EDGE && CustomData_has_layer(&em->bm->edata, CD_FREESTYLE_EDGE)) { UI_ThemeColor(TH_FREESTYLE_EDGE_MARK); - glLineWidth(2); + glLineWidth(2.0f); draw_dm_edges_freestyle(em, cageDM); @@ -3881,7 +3987,7 @@ static void draw_em_fancy(Scene *scene, ARegion *ar, View3D *v3d, draw_dm_bweights(em, scene, cageDM); } - glLineWidth(1); + glLineWidth(1.0f); draw_em_fancy_edges(em, scene, v3d, me, cageDM, 0, eed_act); } @@ -3919,7 +4025,7 @@ static void draw_em_fancy(Scene *scene, ARegion *ar, View3D *v3d, } if (use_depth_offset) { - glDepthMask(1); + glDepthMask(GL_TRUE); ED_view3d_polygon_offset(rv3d, 0.0); GPU_object_material_unbind(); } @@ -3930,15 +4036,93 @@ static void draw_em_fancy(Scene *scene, ARegion *ar, View3D *v3d, #endif } +static void draw_em_fancy_new(Scene *UNUSED(scene), ARegion *ar, View3D *UNUSED(v3d), + Object *UNUSED(ob), Mesh *me, BMEditMesh *UNUSED(em), DerivedMesh *UNUSED(cageDM), DerivedMesh *UNUSED(finalDM), const char UNUSED(dt)) +{ + /* for now... something simple! */ + Batch *surface = BKE_mesh_batch_cache_get_all_triangles(me); + + glEnable(GL_DEPTH_TEST); + glDepthFunc(GL_LEQUAL); + + glEnable(GL_BLEND); + + /* disable depth writes for transparent surface, so it doesn't interfere with itself */ + glDepthMask(GL_FALSE); + + Batch_set_builtin_program(surface, GPU_SHADER_3D_UNIFORM_COLOR); + Batch_Uniform4f(surface, "color", 1.0f, 0.5f, 0.0f, 0.5f); + Batch_draw(surface); + +#if 0 /* until I understand finalDM better */ + if (finalDM != cageDM) { + puts("finalDM != cageDM"); + Batch *finalSurface = MBC_get_all_triangles(finalDM); + Batch_set_builtin_program(finalSurface, GPU_SHADER_3D_UNIFORM_COLOR); + Batch_Uniform4f(finalSurface, "color", 0.0f, 0.0f, 0.0f, 0.05f); + Batch_draw(finalSurface); + } +#endif + + glDepthMask(GL_TRUE); + + /* now write surface depth so other objects won't poke through + * NOTE: does not help as much as desired + * TODO: draw edit object last to avoid this mess + */ + Batch_set_builtin_program(surface, GPU_SHADER_3D_DEPTH_ONLY); + Batch_draw(surface); + + if (GLEW_VERSION_3_2) { + Batch *overlay = BKE_mesh_batch_cache_get_overlay_edges(me); + Batch_set_builtin_program(overlay, GPU_SHADER_EDGES_OVERLAY); + Batch_Uniform2f(overlay, "viewportSize", ar->winx, ar->winy); + Batch_draw(overlay); + +#if 0 /* TODO: use this SIMPLE variant for pure triangle meshes */ + Batch_set_builtin_program(surface, GPU_SHADER_EDGES_OVERLAY_SIMPLE); + /* use these defaults: + * const float edgeColor[4] = { 0.0f, 0.0f, 0.0f, 1.0f }; + * Batch_Uniform4f(surface, "fillColor", edgeColor[0], edgeColor[1], edgeColor[2], 0.0f); + * Batch_Uniform4fv(surface, "outlineColor", edgeColor); + * Batch_Uniform1f(surface, "outlineWidth", 1.0f); + */ + Batch_Uniform2f(surface, "viewportSize", ar->winx, ar->winy); + Batch_draw(surface); +#endif + } + else { + Batch *edges = BKE_mesh_batch_cache_get_all_edges(me); + Batch_set_builtin_program(edges, GPU_SHADER_3D_UNIFORM_COLOR); + Batch_Uniform4f(edges, "color", 0.0f, 0.0f, 0.0f, 1.0f); + glEnable(GL_LINE_SMOOTH); + glLineWidth(1.5f); + Batch_draw(edges); + glDisable(GL_LINE_SMOOTH); + } + +#if 0 /* looks good even without points */ + Batch *verts = MBC_get_all_verts(me); + glEnable(GL_BLEND); + + Batch_set_builtin_program(verts, GPU_SHADER_3D_POINT_UNIFORM_SIZE_UNIFORM_COLOR_SMOOTH); + Batch_Uniform4f(verts, "color", 0.0f, 0.0f, 0.0f, 1.0f); + Batch_Uniform1f(verts, "size", UI_GetThemeValuef(TH_VERTEX_SIZE) * 1.5f); + Batch_draw(verts); + + glDisable(GL_BLEND); +#endif +} + /* Mesh drawing routines */ -static void draw_mesh_object_outline(View3D *v3d, Object *ob, DerivedMesh *dm) +void draw_mesh_object_outline(View3D *v3d, Object *ob, DerivedMesh *dm) /* LEGACY */ { if ((v3d->transp == false) && /* not when we draw the transparent pass */ (ob->mode & OB_MODE_ALL_PAINT) == false) /* not when painting (its distracting) - campbell */ { glLineWidth(UI_GetThemeValuef(TH_OUTLINE_WIDTH) * 2.0f); - glDepthMask(0); + glDepthMask(GL_FALSE); /* if transparent, we cannot draw the edges for solid select... edges * have no material info. GPU_object_material_visible will skip the @@ -3952,7 +4136,49 @@ static void draw_mesh_object_outline(View3D *v3d, Object *ob, DerivedMesh *dm) dm->drawEdges(dm, 0, 1); } - glDepthMask(1); + glDepthMask(GL_TRUE); + } +} + +static void draw_mesh_object_outline_new(View3D *v3d, RegionView3D *rv3d, Object *ob, Mesh *me, const bool is_active) +{ + if ((v3d->transp == false) && /* not when we draw the transparent pass */ + (ob->mode & OB_MODE_ALL_PAINT) == false) /* not when painting (its distracting) - campbell */ + { + glLineWidth(UI_GetThemeValuef(TH_OUTLINE_WIDTH) * 2.0f); + glDepthMask(GL_FALSE); + + float outline_color[4]; + UI_GetThemeColor4fv((is_active ? TH_ACTIVE : TH_SELECT), outline_color); + +#if 1 /* new version that draws only silhouette edges */ + Batch *fancy_edges = BKE_mesh_batch_cache_get_fancy_edges(me); + + if (rv3d->persp == RV3D_ORTHO) { + Batch_set_builtin_program(fancy_edges, GPU_SHADER_EDGES_FRONT_BACK_ORTHO); + /* set eye vector, transformed to object coords */ + float eye[3] = { 0.0f, 0.0f, 1.0f }; /* looking into the screen */ + mul_m3_v3((float (*)[3])gpuGetNormalMatrixInverse(NULL), eye); + Batch_Uniform3fv(fancy_edges, "eye", eye); + } + else { + Batch_set_builtin_program(fancy_edges, GPU_SHADER_EDGES_FRONT_BACK_PERSP); + } + + Batch_Uniform1b(fancy_edges, "drawFront", false); + Batch_Uniform1b(fancy_edges, "drawBack", false); + Batch_Uniform1b(fancy_edges, "drawSilhouette", true); + Batch_Uniform4fv(fancy_edges, "silhouetteColor", outline_color); + + Batch_draw(fancy_edges); +#else /* alternate version that matches look of old viewport (but more efficient) */ + Batch *batch = MBC_get_all_edges(dm); + Batch_set_builtin_program(batch, GPU_SHADER_3D_UNIFORM_COLOR); + Batch_Uniform4fv(batch, "color", outline_color); + Batch_draw(batch); +#endif + + glDepthMask(GL_TRUE); } } @@ -3962,7 +4188,7 @@ static bool object_is_halo(Scene *scene, Object *ob) return (ma && (ma->material_type == MA_TYPE_HALO) && !BKE_scene_use_new_shading_nodes(scene)); } -static void draw_mesh_fancy(Scene *scene, ARegion *ar, View3D *v3d, RegionView3D *rv3d, Base *base, +static void draw_mesh_fancy(Scene *scene, ARegion *ar, View3D *v3d, RegionView3D *rv3d, BaseLegacy *base, const char dt, const unsigned char ob_wire_col[4], const short dflag) { #ifdef WITH_GAMEENGINE @@ -4015,7 +4241,7 @@ static void draw_mesh_fancy(Scene *scene, ARegion *ar, View3D *v3d, RegionView3D else if ((no_faces && no_edges) || ((!is_obact || (ob->mode == OB_MODE_OBJECT)) && object_is_halo(scene, ob))) { - glPointSize(1.5); + glPointSize(1.5f); dm->drawVerts(dm); } else if ((dt == OB_WIRE) || no_faces) { @@ -4028,7 +4254,7 @@ static void draw_mesh_fancy(Scene *scene, ARegion *ar, View3D *v3d, RegionView3D if ((v3d->flag & V3D_SELECT_OUTLINE) && ((v3d->flag2 & V3D_RENDER_OVERRIDE) == 0) && - (base->flag & SELECT) && + (base->flag & BASE_SELECTED) && !(G.f & G_PICKSEL || (draw_flags & DRAW_FACE_SELECT)) && (draw_wire == OBDRAW_WIRE_OFF)) { @@ -4099,7 +4325,7 @@ static void draw_mesh_fancy(Scene *scene, ARegion *ar, View3D *v3d, RegionView3D /* draw outline */ if ((v3d->flag & V3D_SELECT_OUTLINE) && ((v3d->flag2 & V3D_RENDER_OVERRIDE) == 0) && - (base->flag & SELECT) && + (base->flag & BASE_SELECTED) && (draw_wire == OBDRAW_WIRE_OFF) && (ob->sculpt == NULL)) { @@ -4123,7 +4349,7 @@ static void draw_mesh_fancy(Scene *scene, ARegion *ar, View3D *v3d, RegionView3D if ((v3d->flag & V3D_SELECT_OUTLINE) && ((v3d->flag2 & V3D_RENDER_OVERRIDE) == 0) && - (base->flag & SELECT) && + (base->flag & BASE_SELECTED) && (draw_wire == OBDRAW_WIRE_OFF) && (ob->sculpt == NULL)) { @@ -4198,14 +4424,14 @@ static void draw_mesh_fancy(Scene *scene, ARegion *ar, View3D *v3d, RegionView3D */ if (dt != OB_WIRE && (draw_wire == OBDRAW_WIRE_ON_DEPTH)) { ED_view3d_polygon_offset(rv3d, 1.0); - glDepthMask(0); /* disable write in zbuffer, selected edge wires show better */ + glDepthMask(GL_FALSE); /* disable write in zbuffer, selected edge wires show better */ } glLineWidth(1.0f); dm->drawEdges(dm, ((dt == OB_WIRE) || no_faces), (ob->dtx & OB_DRAW_ALL_EDGES) != 0); if (dt != OB_WIRE && (draw_wire == OBDRAW_WIRE_ON_DEPTH)) { - glDepthMask(1); + glDepthMask(GL_TRUE); ED_view3d_polygon_offset(rv3d, 0.0); } } @@ -4225,7 +4451,7 @@ static void draw_mesh_fancy(Scene *scene, ARegion *ar, View3D *v3d, RegionView3D } /* returns true if nothing was drawn, for detecting to draw an object center */ -static bool draw_mesh_object(Scene *scene, ARegion *ar, View3D *v3d, RegionView3D *rv3d, Base *base, +static bool draw_mesh_object(Scene *scene, ARegion *ar, View3D *v3d, RegionView3D *rv3d, BaseLegacy *base, const char dt, const unsigned char ob_wire_col[4], const short dflag) { Object *ob = base->object; @@ -4237,7 +4463,7 @@ static bool draw_mesh_object(Scene *scene, ARegion *ar, View3D *v3d, RegionView3 /* If we are drawing shadows and any of the materials don't cast a shadow, * then don't draw the object */ if (v3d->flag2 & V3D_RENDER_SHADOW) { - for (int i = 1; i <= ob->totcol; ++i) { + for (int i = 0; i < ob->totcol; ++i) { Material *ma = give_current_material(ob, i); if (ma && !(ma->mode2 & MA_CASTSHADOW)) { return true; @@ -4315,7 +4541,7 @@ static bool draw_mesh_object(Scene *scene, ARegion *ar, View3D *v3d, RegionView3 } } - if ((dflag & DRAW_PICKING) == 0 && (base->flag & OB_FROMDUPLI) == 0 && (v3d->flag2 & V3D_RENDER_SHADOW) == 0) { + if ((dflag & DRAW_PICKING) == 0 && (base->flag_legacy & OB_FROMDUPLI) == 0 && (v3d->flag2 & V3D_RENDER_SHADOW) == 0) { /* GPU_begin_object_materials checked if this is needed */ if (do_alpha_after) { if (ob->dtx & OB_DRAWXRAY) { @@ -4339,6 +4565,455 @@ static bool draw_mesh_object(Scene *scene, ARegion *ar, View3D *v3d, RegionView3 return retval; } +static void make_color_variations(const unsigned char base_ubyte[4], float low[4], float med[4], float high[4], const bool other_obedit) +{ + /* original idea: nice variations (lighter & darker shades) of base color + * current implementation uses input color as high; med & low get closer to background color + */ + + float bg[3]; + UI_GetThemeColor3fv(TH_BACK, bg); + + float base[4]; + rgba_uchar_to_float(base, base_ubyte); + + if (other_obedit) { + /* this object should fade away so user can focus on the object being edited */ + interp_v3_v3v3(low, bg, base, 0.1f); + interp_v3_v3v3(med, bg, base, 0.2f); + interp_v3_v3v3(high, bg, base, 0.25f); + } + else { + interp_v3_v3v3(low, bg, base, 0.333f); + interp_v3_v3v3(med, bg, base, 0.667f); + copy_v3_v3(high, base); + } + + /* use original alpha */ + low[3] = base[3]; + med[3] = base[3]; + high[3] = base[3]; +} + +static void draw_mesh_fancy_new(Scene *scene, ARegion *ar, View3D *v3d, RegionView3D *rv3d, BaseLegacy *base, + const char dt, const unsigned char ob_wire_col[4], const short dflag, const bool other_obedit) +{ + if (dflag & (DRAW_PICKING | DRAW_CONSTCOLOR)) { + /* too complicated! use existing methods */ + /* TODO: move this into a separate depth pre-pass */ + draw_mesh_fancy(scene, ar, v3d, rv3d, base, dt, ob_wire_col, dflag); + return; + } + +#ifdef WITH_GAMEENGINE + Object *ob = (rv3d->rflag & RV3D_IS_GAME_ENGINE) ? BKE_object_lod_meshob_get(base->object, scene) : base->object; +#else + Object *ob = base->object; +#endif + Mesh *me = ob->data; + eWireDrawMode draw_wire = OBDRAW_WIRE_OFF; /* could be bool draw_wire_overlay */ + bool no_edges, no_faces; + DerivedMesh *dm = mesh_get_derived_final(scene, ob, scene->customdata_mask); + const bool is_obact = (ob == OBACT); + int draw_flags = (is_obact && BKE_paint_select_face_test(ob)) ? DRAW_FACE_SELECT : 0; + + if (!dm) + return; + + const bool solid = dt >= OB_SOLID; + if (solid) { + DM_update_materials(dm, ob); + } + + /* Check to draw dynamic paint colors (or weights from WeightVG modifiers). + * Note: Last "preview-active" modifier in stack will win! */ + if (DM_get_loop_data_layer(dm, CD_PREVIEW_MLOOPCOL) && modifiers_isPreview(ob)) + draw_flags |= DRAW_MODIFIERS_PREVIEW; + + /* Unwanted combination */ + if (draw_flags & DRAW_FACE_SELECT) { + draw_wire = OBDRAW_WIRE_OFF; + } + else if (ob->dtx & OB_DRAWWIRE) { + draw_wire = OBDRAW_WIRE_ON; + } + + /* check polys instead of tessfaces because of dyntopo where tessfaces don't exist */ + if (dm->type == DM_TYPE_CCGDM) { + no_edges = !subsurf_has_edges(dm); + no_faces = !subsurf_has_faces(dm); + } + else { + no_edges = (dm->getNumEdges(dm) == 0); + no_faces = (dm->getNumPolys(dm) == 0); + } + + if (solid) { + /* vertexpaint, faceselect wants this, but it doesnt work for shaded? */ + glFrontFace((ob->transflag & OB_NEG_SCALE) ? GL_CW : GL_CCW); + } + + if (dt == OB_BOUNDBOX) { + if (((v3d->flag2 & V3D_RENDER_OVERRIDE) && v3d->drawtype >= OB_WIRE) == 0) + draw_bounding_volume(ob, ob->boundtype); + } + else if ((no_faces && no_edges) || + ((!is_obact || (ob->mode == OB_MODE_OBJECT)) && object_is_halo(scene, ob))) + { + glPointSize(1.5f); + // dm->drawVerts(dm); + // TODO: draw smooth round points as a batch + } + else if ((dt == OB_WIRE) || no_faces) { + draw_wire = OBDRAW_WIRE_ON; + + /* enable depth for wireframes */ + glEnable(GL_DEPTH_TEST); + glDepthFunc(GL_LESS); + + glLineWidth(1.0f); + +#if 1 /* fancy wireframes */ + + Batch *fancy_edges = BKE_mesh_batch_cache_get_fancy_edges(me); + + if (rv3d->persp == RV3D_ORTHO) { + Batch_set_builtin_program(fancy_edges, GPU_SHADER_EDGES_FRONT_BACK_ORTHO); + /* set eye vector, transformed to object coords */ + float eye[3] = { 0.0f, 0.0f, 1.0f }; /* looking into the screen */ + mul_m3_v3((float (*)[3])gpuGetNormalMatrixInverse(NULL), eye); + Batch_Uniform3fv(fancy_edges, "eye", eye); + } + else { + Batch_set_builtin_program(fancy_edges, GPU_SHADER_EDGES_FRONT_BACK_PERSP); + } + + float frontColor[4]; + float backColor[4]; + float outlineColor[4]; + make_color_variations(ob_wire_col, backColor, frontColor, outlineColor, other_obedit); + + Batch_Uniform4fv(fancy_edges, "frontColor", frontColor); + Batch_Uniform4fv(fancy_edges, "backColor", backColor); + Batch_Uniform1b(fancy_edges, "drawFront", true); + Batch_Uniform1b(fancy_edges, "drawBack", true); /* false here = backface cull */ + Batch_Uniform1b(fancy_edges, "drawSilhouette", false); + + Batch_draw(fancy_edges); + + /* extra oomph for the silhouette contours */ + glLineWidth(2.0f); + Batch_use_program(fancy_edges); /* hack to make the following uniforms stick */ + Batch_Uniform1b(fancy_edges, "drawFront", false); + Batch_Uniform1b(fancy_edges, "drawBack", false); + Batch_Uniform1b(fancy_edges, "drawSilhouette", true); + Batch_Uniform4fv(fancy_edges, "silhouetteColor", outlineColor); + + Batch_draw(fancy_edges); + +#else /* simple wireframes */ + + Batch *batch = MBC_get_all_edges(dm); + Batch_set_builtin_program(batch, GPU_SHADER_3D_UNIFORM_COLOR); + + float color[4]; + rgba_uchar_to_float(color, ob_wire_col); + + Batch_Uniform4fv(batch, "color", color); + + Batch_draw(batch); +#endif + } + else if (((is_obact && ob->mode & OB_MODE_TEXTURE_PAINT)) || + check_object_draw_texture(scene, v3d, dt)) + { + bool draw_loose = true; + + if ((v3d->flag & V3D_SELECT_OUTLINE) && + ((v3d->flag2 & V3D_RENDER_OVERRIDE) == 0) && + (base->flag & BASE_SELECTED) && + !(G.f & G_PICKSEL || (draw_flags & DRAW_FACE_SELECT)) && + (draw_wire == OBDRAW_WIRE_OFF)) + { + draw_mesh_object_outline_new(v3d, rv3d, ob, me, (ob == OBACT)); + } + + if (draw_glsl_material(scene, ob, v3d, dt) && !(draw_flags & DRAW_MODIFIERS_PREVIEW)) { + Paint *p; + + glFrontFace((ob->transflag & OB_NEG_SCALE) ? GL_CW : GL_CCW); + + if ((v3d->flag2 & V3D_SHOW_SOLID_MATCAP) && ob->sculpt && (p = BKE_paint_get_active(scene))) { + GPUVertexAttribs gattribs; + float planes[4][4]; + float (*fpl)[4] = NULL; + const bool fast = (p->flags & PAINT_FAST_NAVIGATE) && (rv3d->rflag & RV3D_NAVIGATING); + + if (ob->sculpt->partial_redraw) { + if (ar->do_draw & RGN_DRAW_PARTIAL) { + ED_sculpt_redraw_planes_get(planes, ar, rv3d, ob); + fpl = planes; + ob->sculpt->partial_redraw = 0; + } + } + + GPU_object_material_bind(1, &gattribs); + dm->drawFacesSolid(dm, fpl, fast, NULL); + draw_loose = false; + } + else + dm->drawFacesGLSL(dm, GPU_object_material_bind); + + GPU_object_material_unbind(); + + glFrontFace(GL_CCW); + + if (draw_flags & DRAW_FACE_SELECT) + draw_mesh_face_select(rv3d, me, dm, false); + } + else { + draw_mesh_textured(scene, v3d, rv3d, ob, dm, draw_flags); + } + + if (draw_loose && !(draw_flags & DRAW_FACE_SELECT)) { + if ((v3d->flag2 & V3D_RENDER_OVERRIDE) == 0) { + if ((dflag & DRAW_CONSTCOLOR) == 0) { + glColor3ubv(ob_wire_col); + } + glLineWidth(1.0f); + dm->drawLooseEdges(dm); + } + } + } + else if (dt == OB_SOLID) { + if (draw_flags & DRAW_MODIFIERS_PREVIEW) { + /* for object selection draws no shade */ + if (dflag & (DRAW_PICKING | DRAW_CONSTCOLOR)) { + /* TODO: draw basic faces with GPU_SHADER_3D_DEPTH_ONLY */ + } + else { + const float specular[3] = {0.47f, 0.47f, 0.47f}; + + /* draw outline */ + /* TODO: move this into a separate pass */ + if ((v3d->flag & V3D_SELECT_OUTLINE) && + ((v3d->flag2 & V3D_RENDER_OVERRIDE) == 0) && + (base->flag & BASE_SELECTED) && + (draw_wire == OBDRAW_WIRE_OFF) && + (ob->sculpt == NULL)) + { + draw_mesh_object_outline_new(v3d, rv3d, ob, me, (ob == OBACT)); + } + + /* materials arent compatible with vertex colors */ + GPU_end_object_materials(); + + /* set default specular */ + GPU_basic_shader_colors(NULL, specular, 35, 1.0f); + GPU_basic_shader_bind(GPU_SHADER_LIGHTING | GPU_SHADER_USE_COLOR); + + dm->drawMappedFaces(dm, NULL, NULL, NULL, NULL, DM_DRAW_USE_COLORS | DM_DRAW_NEED_NORMALS); + + GPU_basic_shader_bind(GPU_SHADER_USE_COLOR); + } + } + else { + Paint *p; + + if ((v3d->flag & V3D_SELECT_OUTLINE) && + ((v3d->flag2 & V3D_RENDER_OVERRIDE) == 0) && + (base->flag & BASE_SELECTED) && + (draw_wire == OBDRAW_WIRE_OFF) && + (ob->sculpt == NULL)) + { + /* TODO: move this into a separate pass */ + draw_mesh_object_outline_new(v3d, rv3d, ob, me, (ob == OBACT)); + } + + glFrontFace((ob->transflag & OB_NEG_SCALE) ? GL_CW : GL_CCW); + + if (ob->sculpt && (p = BKE_paint_get_active(scene))) { + float planes[4][4]; + float (*fpl)[4] = NULL; + const bool fast = (p->flags & PAINT_FAST_NAVIGATE) && (rv3d->rflag & RV3D_NAVIGATING); + + if (ob->sculpt->partial_redraw) { + if (ar->do_draw & RGN_DRAW_PARTIAL) { + ED_sculpt_redraw_planes_get(planes, ar, rv3d, ob); + fpl = planes; + ob->sculpt->partial_redraw = 0; + } + } + + dm->drawFacesSolid(dm, fpl, fast, GPU_object_material_bind); + } + else + dm->drawFacesSolid(dm, NULL, 0, GPU_object_material_bind); + + glFrontFace(GL_CCW); + + GPU_object_material_unbind(); + + if (!ob->sculpt && (v3d->flag2 & V3D_RENDER_OVERRIDE) == 0) { + if ((dflag & DRAW_CONSTCOLOR) == 0) { + glColor3ubv(ob_wire_col); + } + glLineWidth(1.0f); + dm->drawLooseEdges(dm); + } + } + } + else if (dt == OB_PAINT) { + draw_mesh_paint(v3d, rv3d, ob, dm, draw_flags); + + /* since we already draw wire as wp guide, don't draw over the top */ + draw_wire = OBDRAW_WIRE_OFF; + } + + if ((draw_wire != OBDRAW_WIRE_OFF) && /* draw extra wire */ + /* when overriding with render only, don't bother */ + (((v3d->flag2 & V3D_RENDER_OVERRIDE) && v3d->drawtype >= OB_SOLID) == 0)) // <-- is this "== 0" in the right spot??? + { + /* When using wireframe object draw in particle edit mode + * the mesh gets in the way of seeing the particles, fade the wire color + * with the background. */ + + if ((dflag & DRAW_CONSTCOLOR) == 0) { + /* TODO: + * Batch_UniformColor4ubv(ob_wire_col); + */ + } + + /* If drawing wire and drawtype is not OB_WIRE then we are + * overlaying the wires. + * + * No need for polygon offset because new technique is AWESOME. + */ +#if 0 + glLineWidth(1.0f); + dm->drawEdges(dm, ((dt == OB_WIRE) || no_faces), (ob->dtx & OB_DRAW_ALL_EDGES) != 0); +#else + /* something */ +#endif + } + +#if 0 // (merwin) what is this for? + if (is_obact && BKE_paint_select_vert_test(ob)) { + const bool use_depth = (v3d->flag & V3D_ZBUF_SELECT) != 0; + glColor3f(0.0f, 0.0f, 0.0f); + glPointSize(UI_GetThemeValuef(TH_VERTEX_SIZE)); + + if (!use_depth) glDisable(GL_DEPTH_TEST); + else ED_view3d_polygon_offset(rv3d, 1.0); + drawSelectedVertices(dm, ob->data); + if (!use_depth) glEnable(GL_DEPTH_TEST); + else ED_view3d_polygon_offset(rv3d, 0.0); + } +#endif + + dm->release(dm); +} + +static bool draw_mesh_object_new(Scene *scene, ARegion *ar, View3D *v3d, RegionView3D *rv3d, BaseLegacy *base, + const char dt, const unsigned char ob_wire_col[4], const short dflag) +{ + Object *ob = base->object; + Object *obedit = scene->obedit; + Mesh *me = ob->data; + BMEditMesh *em = me->edit_btmesh; + bool do_alpha_after = false, drawlinked = false, retval = false; + + if (v3d->flag2 & V3D_RENDER_SHADOW) { + /* TODO: handle shadow pass separately */ + return true; + } + + if (obedit && ob != obedit && ob->data == obedit->data) { + if (BKE_key_from_object(ob) || BKE_key_from_object(obedit)) {} + else if (ob->modifiers.first || obedit->modifiers.first) {} + else drawlinked = true; + } + + /* backface culling */ + const bool solid = dt > OB_WIRE; + const bool cullBackface = solid && (v3d->flag2 & V3D_BACKFACE_CULLING); + if (cullBackface) { + glEnable(GL_CULL_FACE); + glCullFace(GL_BACK); + } + + if (ob == obedit || drawlinked) { + DerivedMesh *finalDM, *cageDM; + + if (obedit != ob) { + /* linked to the edit object */ + finalDM = cageDM = editbmesh_get_derived_base( + ob, em, scene->customdata_mask); + } + else { + cageDM = editbmesh_get_derived_cage_and_final( + scene, ob, em, scene->customdata_mask, + &finalDM); + } + + const bool use_material = solid && ((me->drawflag & ME_DRAWEIGHT) == 0); + +#if 0 // why update if not being used? + DM_update_materials(finalDM, ob); + if (cageDM != finalDM) { + DM_update_materials(cageDM, ob); + } +#endif // moved to below + + if (use_material) { + DM_update_materials(finalDM, ob); + if (cageDM != finalDM) { + DM_update_materials(cageDM, ob); + } + + const bool glsl = draw_glsl_material(scene, ob, v3d, dt); + + GPU_begin_object_materials(v3d, rv3d, scene, ob, glsl, NULL); + } + + draw_em_fancy_new(scene, ar, v3d, ob, me, em, cageDM, finalDM, dt); + + if (use_material) { + GPU_end_object_materials(); + } + + if (obedit != ob) + finalDM->release(finalDM); + } + else { + /* ob->bb was set by derived mesh system, do NULL check just to be sure */ + if (me->totpoly <= 4 || (!ob->bb || ED_view3d_boundbox_clip(rv3d, ob->bb))) { + if (solid) { + const bool glsl = draw_glsl_material(scene, ob, v3d, dt); + + if (dt == OB_SOLID || glsl) { + const bool check_alpha = check_alpha_pass(base); + GPU_begin_object_materials(v3d, rv3d, scene, ob, glsl, + (check_alpha) ? &do_alpha_after : NULL); + } + } + + const bool other_obedit = obedit && (obedit != ob); + + draw_mesh_fancy_new(scene, ar, v3d, rv3d, base, dt, ob_wire_col, dflag, other_obedit); + + GPU_end_object_materials(); + + if (me->totvert == 0) retval = true; + } + } + + if (cullBackface) + glDisable(GL_CULL_FACE); + + return retval; +} + /* ************** DRAW DISPLIST ****************** */ @@ -4578,7 +5253,7 @@ static void drawCurveDMWired(Object *ob) } /* return true when nothing was drawn */ -static bool drawCurveDerivedMesh(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base *base, const char dt) +static bool drawCurveDerivedMesh(Scene *scene, View3D *v3d, RegionView3D *rv3d, BaseLegacy *base, const char dt) { Object *ob = base->object; DerivedMesh *dm = ob->derivedFinal; @@ -4614,7 +5289,7 @@ static bool drawCurveDerivedMesh(Scene *scene, View3D *v3d, RegionView3D *rv3d, * Only called by #drawDispList * \return true when nothing was drawn */ -static bool drawDispList_nobackface(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base *base, +static bool drawDispList_nobackface(Scene *scene, View3D *v3d, RegionView3D *rv3d, BaseLegacy *base, const char dt, const short dflag, const unsigned char ob_wire_col[4]) { Object *ob = base->object; @@ -4735,7 +5410,7 @@ static bool drawDispList_nobackface(Scene *scene, View3D *v3d, RegionView3D *rv3 return false; } -static bool drawDispList(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base *base, +static bool drawDispList(Scene *scene, View3D *v3d, RegionView3D *rv3d, BaseLegacy *base, const char dt, const short dflag, const unsigned char ob_wire_col[4]) { bool retval; @@ -5022,7 +5697,7 @@ static void draw_new_particle_system(Scene *scene, View3D *v3d, RegionView3D *rv float cfra; float ma_col[3] = {0.0f, 0.0f, 0.0f}; int a, totpart, totpoint = 0, totve = 0, drawn, draw_as, totchild = 0; - bool select = (ob->flag & SELECT) != 0, create_cdata = false, need_v = false; + bool select = (base->flag & BASE_SELECTED) != 0, create_cdata = false, need_v = false; GLint polygonmode[2]; char numstr[32]; unsigned char tcol[4] = {0, 0, 0, 255}; @@ -5093,7 +5768,7 @@ static void draw_new_particle_system(Scene *scene, View3D *v3d, RegionView3D *rv timestep = psys_get_timestep(&sim); - if ((base->flag & OB_FROMDUPLI) && (ob->flag & OB_FROMGROUP)) { + if ((ob->flag & OB_FROMGROUP) != 0) { float mat[4][4]; mul_m4_m4m4(mat, ob->obmat, psys->imat); glMultMatrixf(mat); @@ -5724,7 +6399,7 @@ static void draw_new_particle_system(Scene *scene, View3D *v3d, RegionView3D *rv pdd->ma_col = NULL; } - if ((base->flag & OB_FROMDUPLI) && (ob->flag & OB_FROMGROUP)) { + if ((ob->flag & OB_FROMGROUP) != 0) { glLoadMatrixf(rv3d->viewmat); } } @@ -6093,7 +6768,7 @@ static void drawhandlesN_active(Nurb *nu) if (nu->hide) return; UI_ThemeColor(TH_ACTIVE_SPLINE); - glLineWidth(2); + glLineWidth(2.0f); glBegin(GL_LINES); @@ -6118,72 +6793,100 @@ static void drawhandlesN_active(Nurb *nu) glColor3ub(0, 0, 0); } -static void drawvertsN(Nurb *nu, const char sel, const bool hide_handles, const void *vert) +static void drawvertsN(const Nurb *nurb, const bool hide_handles, const void *vert) { - if (nu->hide) return; + const Nurb *nu; - const int color = sel ? TH_VERTEX_SELECT : TH_VERTEX; + // just quick guesstimate of how many verts to draw + int count = 0; + for (nu = nurb; nu; nu = nu->next) { + if (!nu->hide) { + if (nu->type == CU_BEZIER) { + count += nu->pntsu * 3; + } + else { + count += nu->pntsu * nu->pntsv; + } + } + } + if (count == 0) return; - UI_ThemeColor(color); + VertexFormat *format = immVertexFormat(); + unsigned pos = add_attrib(format, "pos", GL_FLOAT, 3, KEEP_FLOAT); + unsigned color = add_attrib(format, "color", GL_UNSIGNED_BYTE, 3, NORMALIZE_INT_TO_FLOAT); + immBindBuiltinProgram(GPU_SHADER_3D_FLAT_COLOR); + + unsigned char vert_color[3]; + unsigned char vert_color_select[3]; + unsigned char vert_color_active[3]; + UI_GetThemeColor3ubv(TH_VERTEX, vert_color); + UI_GetThemeColor3ubv(TH_VERTEX_SELECT, vert_color_select); + UI_GetThemeColor3ubv(TH_ACTIVE_VERT, vert_color_active); glPointSize(UI_GetThemeValuef(TH_VERTEX_SIZE)); + + immBeginAtMost(GL_POINTS, count); - glBegin(GL_POINTS); - - if (nu->type == CU_BEZIER) { + for (nu = nurb; nu; nu = nu->next) { - BezTriple *bezt = nu->bezt; - int a = nu->pntsu; - while (a--) { - if (bezt->hide == 0) { - if (sel == 1 && bezt == vert) { - UI_ThemeColor(TH_ACTIVE_VERT); + if (nu->hide) continue; - if (bezt->f2 & SELECT) glVertex3fv(bezt->vec[1]); - if (!hide_handles) { - if (bezt->f1 & SELECT) glVertex3fv(bezt->vec[0]); - if (bezt->f3 & SELECT) glVertex3fv(bezt->vec[2]); - } + if (nu->type == CU_BEZIER) { - UI_ThemeColor(color); - } - else if (hide_handles) { - if ((bezt->f2 & SELECT) == sel) glVertex3fv(bezt->vec[1]); - } - else { - if ((bezt->f1 & SELECT) == sel) glVertex3fv(bezt->vec[0]); - if ((bezt->f2 & SELECT) == sel) glVertex3fv(bezt->vec[1]); - if ((bezt->f3 & SELECT) == sel) glVertex3fv(bezt->vec[2]); + const BezTriple *bezt = nu->bezt; + int a = nu->pntsu; + while (a--) { + if (bezt->hide == 0) { + if (bezt == vert) { + immAttrib3ubv(color, bezt->f2 & SELECT ? vert_color_active : vert_color); + immVertex3fv(pos, bezt->vec[1]); + if (!hide_handles) { + immAttrib3ubv(color, bezt->f1 & SELECT ? vert_color_active : vert_color); + immVertex3fv(pos, bezt->vec[0]); + immAttrib3ubv(color, bezt->f3 & SELECT ? vert_color_active : vert_color); + immVertex3fv(pos, bezt->vec[2]); + } + } + else { + immAttrib3ubv(color, bezt->f2 & SELECT ? vert_color_select : vert_color); + immVertex3fv(pos, bezt->vec[1]); + if (!hide_handles) { + immAttrib3ubv(color, bezt->f1 & SELECT ? vert_color_select : vert_color); + immVertex3fv(pos, bezt->vec[0]); + immAttrib3ubv(color, bezt->f3 & SELECT ? vert_color_select : vert_color); + immVertex3fv(pos, bezt->vec[2]); + } + } } + bezt++; } - bezt++; } - } - else { - BPoint *bp = nu->bp; - int a = nu->pntsu * nu->pntsv; - while (a--) { - if (bp->hide == 0) { - if (bp == vert) { - UI_ThemeColor(TH_ACTIVE_VERT); - glVertex3fv(bp->vec); - UI_ThemeColor(color); - } - else { - if ((bp->f1 & SELECT) == sel) glVertex3fv(bp->vec); + else { + const BPoint *bp = nu->bp; + int a = nu->pntsu * nu->pntsv; + while (a--) { + if (bp->hide == 0) { + if (bp == vert) { + immAttrib3ubv(color, vert_color_active); + } + else { + immAttrib3ubv(color, bp->f1 & SELECT ? vert_color_select : vert_color); + } + immVertex3fv(pos, bp->vec); } + bp++; } - bp++; } } - - glEnd(); + + immEnd(); + immUnbindProgram(); } static void editnurb_draw_active_poly(Nurb *nu) { UI_ThemeColor(TH_ACTIVE_SPLINE); - glLineWidth(2); + glLineWidth(2.0f); BPoint *bp = nu->bp; for (int b = 0; b < nu->pntsv; b++) { @@ -6203,7 +6906,7 @@ static void editnurb_draw_active_poly(Nurb *nu) static void editnurb_draw_active_nurbs(Nurb *nu) { UI_ThemeColor(TH_ACTIVE_SPLINE); - glLineWidth(2); + glLineWidth(2.0f); glBegin(GL_LINES); BPoint *bp = nu->bp; @@ -6258,7 +6961,7 @@ static void draw_editnurb_splines(Object *ob, Nurb *nurb, const bool sel) editnurb_draw_active_poly(nu); } - glLineWidth(1); + glLineWidth(1.0f); UI_ThemeColor(TH_NURB_ULINE); bp = nu->bp; @@ -6279,7 +6982,7 @@ static void draw_editnurb_splines(Object *ob, Nurb *nurb, const bool sel) editnurb_draw_active_nurbs(nu); } - glLineWidth(1); + glLineWidth(1.0f); glBegin(GL_LINES); @@ -6356,7 +7059,7 @@ static void draw_editnurb_splines(Object *ob, Nurb *nurb, const bool sel) } static void draw_editnurb( - Scene *scene, View3D *v3d, RegionView3D *rv3d, Base *base, Nurb *nurb, + Scene *scene, View3D *v3d, RegionView3D *rv3d, BaseLegacy *base, Nurb *nurb, const char dt, const short dflag, const unsigned char ob_wire_col[4]) { ToolSettings *ts = scene->toolsettings; @@ -6395,7 +7098,6 @@ static void draw_editnurb( for (nu = nurb; nu; nu = nu->next) { if (nu->type == CU_BEZIER && (cu->drawflag & CU_HIDE_HANDLES) == 0) drawhandlesN(nu, 1, hide_handles); - drawvertsN(nu, 0, hide_handles, NULL); } if (v3d->zbuf) glDepthFunc(GL_LEQUAL); @@ -6446,11 +7148,9 @@ static void draw_editnurb( } if (v3d->zbuf) glDepthFunc(GL_ALWAYS); - - for (nu = nurb; nu; nu = nu->next) { - drawvertsN(nu, 1, hide_handles, vert); - } - + + drawvertsN(nu, hide_handles, vert); + if (v3d->zbuf) glDepthFunc(GL_LEQUAL); } @@ -6469,7 +7169,7 @@ static void draw_editfont_textcurs(RegionView3D *rv3d, float textcurs[4][2]) ED_view3d_polygon_offset(rv3d, 0.0); } -static void draw_editfont(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base *base, +static void draw_editfont(Scene *scene, View3D *v3d, RegionView3D *rv3d, BaseLegacy *base, const char dt, const short dflag, const unsigned char ob_wire_col[4]) { Object *ob = base->object; @@ -6598,56 +7298,58 @@ static void draw_editfont(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base *b } /* draw a sphere for use as an empty drawtype */ -static void draw_empty_sphere(float size) -{ - static GLuint displist = 0; - - if (displist == 0) { - GLUquadricObj *qobj; - - displist = glGenLists(1); - glNewList(displist, GL_COMPILE); - - glPushMatrix(); - - qobj = gluNewQuadric(); - gluQuadricDrawStyle(qobj, GLU_SILHOUETTE); - gluDisk(qobj, 0.0, 1, 16, 1); - - glRotatef(90, 0, 1, 0); - gluDisk(qobj, 0.0, 1, 16, 1); - - glRotatef(90, 1, 0, 0); - gluDisk(qobj, 0.0, 1, 16, 1); - - gluDeleteQuadric(qobj); - - glPopMatrix(); - glEndList(); - } - - glScalef(size, size, size); - glCallList(displist); - glScalef(1.0f / size, 1.0f / size, 1.0f / size); +static void draw_empty_sphere(float size, unsigned pos) +{ +#define NSEGMENTS 16 + /* 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] = size * cosf(angle); + p[i][1] = size * sinf(angle); + } + + immBegin(GL_LINE_LOOP, NSEGMENTS); + for (int i = 0; i < NSEGMENTS; ++i) + immVertex3f(pos, p[i][0], p[i][1], 0.0f); + immEnd(); + immBegin(GL_LINE_LOOP, NSEGMENTS); + for (int i = 0; i < NSEGMENTS; ++i) + immVertex3f(pos, p[i][0], 0.0f, p[i][1]); + immEnd(); + immBegin(GL_LINE_LOOP, NSEGMENTS); + for (int i = 0; i < NSEGMENTS; ++i) + immVertex3f(pos, 0.0f, p[i][0], p[i][1]); + immEnd(); +#undef NSEGMENTS } /* draw a cone for use as an empty drawtype */ -static void draw_empty_cone(float size) +static void draw_empty_cone(float size, unsigned pos) { - const float radius = size; +#define NSEGMENTS 8 + /* 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] = size * cosf(angle); + p[i][1] = size * sinf(angle); + } - GLUquadricObj *qobj = gluNewQuadric(); - gluQuadricDrawStyle(qobj, GLU_SILHOUETTE); - - glPushMatrix(); - - glScalef(radius, size * 2.0f, radius); - glRotatef(-90.0, 1.0, 0.0, 0.0); - gluCylinder(qobj, 1.0, 0.0, 1.0, 8, 1); + /* cone sides */ + immBegin(GL_LINES, NSEGMENTS * 2); + for (int i = 0; i < NSEGMENTS; ++i) { + immVertex3f(pos, 0.0f, 2.0f * size, 0.0f); + immVertex3f(pos, p[i][0], 0.0f, p[i][1]); + } + immEnd(); - glPopMatrix(); - - gluDeleteQuadric(qobj); + /* end ring */ + immBegin(GL_LINE_LOOP, NSEGMENTS); + for (int i = 0; i < NSEGMENTS; ++i) + immVertex3f(pos, p[i][0], 0.0f, p[i][1]); + immEnd(); +#undef NSEGMENTS } static void drawspiral(const float cent[3], float rad, float tmat[4][4], int start) @@ -6718,20 +7420,19 @@ static void drawspiral(const float cent[3], float rad, float tmat[4][4], int sta /* draws a circle on x-z plane given the scaling of the circle, assuming that * all required matrices have been set (used for drawing empties) */ -static void drawcircle_size(float size) +static void drawcircle_size(float size, unsigned pos) { - glBegin(GL_LINE_LOOP); + immBegin(GL_LINE_LOOP, CIRCLE_RESOL); /* coordinates are: cos(degrees * 11.25) = x, sin(degrees * 11.25) = y, 0.0f = z */ for (short degrees = 0; degrees < CIRCLE_RESOL; degrees++) { float x = cosval[degrees]; float y = sinval[degrees]; - - glVertex3f(x * size, 0.0f, y * size); + + immVertex3f(pos, x * size, 0.0f, y * size); } - - glEnd(); + immEnd(); } /* needs fixing if non-identity matrix used */ @@ -6758,6 +7459,29 @@ static void drawtube(const float vec[3], float radius, float height, float tmat[ } /* needs fixing if non-identity matrix used */ +static void UNUSED_FUNCTION(imm_drawtube)(const float vec[3], float radius, float height, float tmat[4][4], unsigned pos) +{ + float cur[3]; + imm_drawcircball(vec, radius, tmat, pos); + + copy_v3_v3(cur, vec); + cur[2] += height; + + imm_drawcircball(cur, radius, tmat, pos); + + immBegin(GL_LINES, 8); + immVertex3f(pos, vec[0] + radius, vec[1], vec[2]); + immVertex3f(pos, cur[0] + radius, cur[1], cur[2]); + immVertex3f(pos, vec[0] - radius, vec[1], vec[2]); + immVertex3f(pos, cur[0] - radius, cur[1], cur[2]); + immVertex3f(pos, vec[0], vec[1] + radius, vec[2]); + immVertex3f(pos, cur[0], cur[1] + radius, cur[2]); + immVertex3f(pos, vec[0], vec[1] - radius, vec[2]); + immVertex3f(pos, cur[0], cur[1] - radius, cur[2]); + immEnd(); +} + +/* needs fixing if non-identity matrix used */ static void drawcone(const float vec[3], float radius, float height, float tmat[4][4]) { float cur[3]; @@ -6773,14 +7497,37 @@ static void drawcone(const float vec[3], float radius, float height, float tmat[ glVertex3f(vec[0], vec[1], vec[2]); glVertex3f(cur[0] - radius, cur[1], cur[2]); glVertex3f(vec[0], vec[1], vec[2]); + glVertex3f(cur[0], cur[1] + radius, cur[2]); glVertex3f(vec[0], vec[1], vec[2]); glVertex3f(cur[0], cur[1] - radius, cur[2]); glEnd(); } +/* needs fixing if non-identity matrix used */ +static void UNUSED_FUNCTION(imm_drawcone)(const float vec[3], float radius, float height, float tmat[4][4], unsigned pos) +{ + float cur[3]; + + copy_v3_v3(cur, vec); + cur[2] += height; + + imm_drawcircball(cur, radius, tmat, pos); + + immBegin(GL_LINES, 8); + immVertex3f(pos, vec[0], vec[1], vec[2]); + immVertex3f(pos, cur[0] + radius, cur[1], cur[2]); + immVertex3f(pos, vec[0], vec[1], vec[2]); + immVertex3f(pos, cur[0] - radius, cur[1], cur[2]); + immVertex3f(pos, vec[0], vec[1], vec[2]); + immVertex3f(pos, cur[0], cur[1] + radius, cur[2]); + immVertex3f(pos, vec[0], vec[1], vec[2]); + immVertex3f(pos, cur[0], cur[1] - radius, cur[2]); + immEnd(); +} + /* return true if nothing was drawn */ -static bool drawmball(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base *base, +static bool drawmball(Scene *scene, View3D *v3d, RegionView3D *rv3d, BaseLegacy *base, const char dt, const short dflag, const unsigned char ob_wire_col[4]) { Object *ob = base->object; @@ -6801,7 +7548,7 @@ static bool drawmball(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base *base, ml = mb->editelems->first; } else { - if ((base->flag & OB_FROMDUPLI) == 0) { + if ((base->flag_legacy & OB_FROMDUPLI) == 0) { drawDispList(scene, v3d, rv3d, base, dt, dflag, ob_wire_col); } ml = mb->elems.first; @@ -7027,6 +7774,30 @@ static void draw_box(const float vec[8][3], bool solid) glDisableClientState(GL_VERTEX_ARRAY); } +static void imm_draw_box(const float vec[8][3], bool solid, unsigned pos) +{ + static const GLubyte quad_indices[24] = {0,1,2,3,7,6,5,4,4,5,1,0,3,2,6,7,3,7,4,0,1,5,6,2}; + static const GLubyte line_indices[24] = {0,1,1,2,2,3,3,0,0,4,4,5,5,6,6,7,7,4,1,5,2,6,3,7}; + + const GLubyte *indices; + GLenum prim_type; + + if (solid) { + indices = quad_indices; + prim_type = GL_QUADS; + } + else { + indices = line_indices; + prim_type = GL_LINES; + } + + immBegin(prim_type, 24); + for (int i = 0; i < 24; ++i) { + immVertex3fv(pos, vec[indices[i]]); + } + immEnd(); +} + static void draw_bb_quadric(BoundBox *bb, char type, bool around_origin) { float size[3], cent[3]; @@ -7076,7 +7847,7 @@ static void draw_bb_quadric(BoundBox *bb, char type, bool around_origin) gluDeleteQuadric(qobj); } -static void draw_bounding_volume(Object *ob, char type) +void draw_bounding_volume(Object *ob, char type) { BoundBox bb_local; BoundBox *bb = NULL; @@ -7171,13 +7942,13 @@ static void drawtexspace(Object *ob) } /* draws wire outline */ -static void drawObjectSelect(Scene *scene, View3D *v3d, ARegion *ar, Base *base, +static void drawObjectSelect(Scene *scene, SceneLayer *sl, View3D *v3d, ARegion *ar, Base *base, const unsigned char ob_wire_col[4]) { RegionView3D *rv3d = ar->regiondata; Object *ob = base->object; - glDepthMask(0); + glDepthMask(GL_FALSE); if (ELEM(ob->type, OB_FONT, OB_CURVE, OB_SURF)) { bool has_faces = false; @@ -7211,20 +7982,20 @@ static void drawObjectSelect(Scene *scene, View3D *v3d, ARegion *ar, Base *base, } else if (ob->type == OB_MBALL) { if (BKE_mball_is_basis(ob)) { - if ((base->flag & OB_FROMDUPLI) == 0) { + if ((base->flag_legacy & OB_FROMDUPLI) == 0) { glLineWidth(UI_GetThemeValuef(TH_OUTLINE_WIDTH) * 2.0f); drawDispListwire(&ob->curve_cache->disp, ob->type); } } } else if (ob->type == OB_ARMATURE) { - if (!(ob->mode & OB_MODE_POSE && base == scene->basact)) { + if (!(ob->mode & OB_MODE_POSE && base == sl->basact)) { glLineWidth(UI_GetThemeValuef(TH_OUTLINE_WIDTH) * 2.0f); - draw_armature(scene, v3d, ar, base, OB_WIRE, 0, ob_wire_col, true); + draw_armature(scene, sl, v3d, ar, base, OB_WIRE, 0, ob_wire_col, true); } } - glDepthMask(1); + glDepthMask(GL_TRUE); } static void draw_wire_extra(Scene *scene, RegionView3D *rv3d, Object *ob, const unsigned char ob_wire_col[4]) @@ -7239,8 +8010,8 @@ static void draw_wire_extra(Scene *scene, RegionView3D *rv3d, Object *ob, const } ED_view3d_polygon_offset(rv3d, 1.0); - glDepthMask(0); /* disable write in zbuffer, selected edge wires show better */ - glLineWidth(1); + glDepthMask(GL_FALSE); /* disable write in zbuffer, selected edge wires show better */ + glLineWidth(1.0f); if (ELEM(ob->type, OB_FONT, OB_CURVE, OB_SURF)) { if (ED_view3d_boundbox_clip(rv3d, ob->bb)) { @@ -7259,7 +8030,7 @@ static void draw_wire_extra(Scene *scene, RegionView3D *rv3d, Object *ob, const } } - glDepthMask(1); + glDepthMask(GL_TRUE); ED_view3d_polygon_offset(rv3d, 0.0); } } @@ -7283,7 +8054,7 @@ static void draw_hooks(Object *ob) setlinestyle(0); } - glPointSize(3.0); + glPointSize(3.0f); glBegin(GL_POINTS); glVertex3fv(vec); glEnd(); @@ -7324,7 +8095,7 @@ static void draw_rigid_body_pivot(bRigidBodyJointConstraint *data, setlinestyle(0); } -static void draw_object_wire_color(Scene *scene, Base *base, unsigned char r_ob_wire_col[4]) +void draw_object_wire_color(Scene *scene, SceneLayer *sl, Base *base, unsigned char r_ob_wire_col[4]) { Object *ob = base->object; int colindex = 0; @@ -7338,19 +8109,19 @@ static void draw_object_wire_color(Scene *scene, Base *base, unsigned char r_ob_ if ((scene->obedit == NULL) && (G.moving & G_TRANSFORM_OBJ) && - (base->flag & (SELECT + BA_WAS_SEL))) + ((base->flag & BASE_SELECTED) || (base->flag_legacy & BA_WAS_SEL))) { theme_id = TH_TRANSFORM; } else { /* Sets the 'colindex' */ if (ID_IS_LINKED_DATABLOCK(ob)) { - colindex = (base->flag & (SELECT + BA_WAS_SEL)) ? 2 : 1; + colindex = ((base->flag & BASE_SELECTED) || (base->flag_legacy & BA_WAS_SEL)) ? 2 : 1; } /* Sets the 'theme_id' or fallback to wire */ else { - if (ob->flag & OB_FROMGROUP) { - if (base->flag & (SELECT + BA_WAS_SEL)) { + if ((ob->flag & OB_FROMGROUP) != 0) { + if ((base->flag & BASE_SELECTED) || (base->flag_legacy & BA_WAS_SEL)) { /* uses darker active color for non-active + selected */ theme_id = TH_GROUP_ACTIVE; @@ -7363,8 +8134,8 @@ static void draw_object_wire_color(Scene *scene, Base *base, unsigned char r_ob_ } } else { - if (base->flag & (SELECT + BA_WAS_SEL)) { - theme_id = scene->basact == base ? TH_ACTIVE : TH_SELECT; + if ((base->flag & BASE_SELECTED) || (base->flag_legacy & BA_WAS_SEL)) { + theme_id = sl->basact == base ? TH_ACTIVE : TH_SELECT; } else { if (ob->type == OB_LAMP) theme_id = TH_LAMP; @@ -7418,7 +8189,7 @@ static void draw_object_matcap_check(View3D *v3d, Object *ob) v3d->flag2 |= V3D_SHOW_SOLID_MATCAP; } -static void draw_rigidbody_shape(Object *ob) +void draw_rigidbody_shape(Object *ob) { BoundBox *bb = NULL; float size[3], vec[8][3]; @@ -7462,7 +8233,7 @@ static void draw_rigidbody_shape(Object *ob) * main object drawing function, draws in selection * \param dflag (draw flag) can be DRAW_PICKING and/or DRAW_CONSTCOLOR, DRAW_SCENESET */ -void draw_object(Scene *scene, ARegion *ar, View3D *v3d, Base *base, const short dflag) +void draw_object(Scene *scene, SceneLayer *sl, ARegion *ar, View3D *v3d, Base *base, const short dflag) { ModifierData *md = NULL; Object *ob = base->object; @@ -7472,7 +8243,7 @@ void draw_object(Scene *scene, ARegion *ar, View3D *v3d, Base *base, const short unsigned char _ob_wire_col[4]; /* dont initialize this */ const unsigned char *ob_wire_col = NULL; /* dont initialize this, use NULL crashes as a way to find invalid use */ bool zbufoff = false, is_paint = false, empty_object = false; - const bool is_obact = (ob == OBACT); + const bool is_obact = (ob == OBACT_NEW); const bool render_override = (v3d->flag2 & V3D_RENDER_OVERRIDE) != 0; const bool is_picking = (G.f & G_PICKSEL) != 0; const bool has_particles = (ob->particlesystem.first != NULL); @@ -7512,7 +8283,7 @@ void draw_object(Scene *scene, ARegion *ar, View3D *v3d, Base *base, const short } } - if (((base->flag & OB_FROMDUPLI) == 0) && + if (((base->flag_legacy & OB_FROMDUPLI) == 0) && (md = modifiers_findByType(ob, eModifierType_Smoke)) && (modifier_isEnabled(scene, md, eModifierMode_Realtime))) { @@ -7536,7 +8307,7 @@ void draw_object(Scene *scene, ARegion *ar, View3D *v3d, Base *base, const short /* xray delay? */ - if ((dflag & DRAW_PICKING) == 0 && (base->flag & OB_FROMDUPLI) == 0 && (v3d->flag2 & V3D_RENDER_SHADOW) == 0) { + if ((dflag & DRAW_PICKING) == 0 && (base->flag_legacy & OB_FROMDUPLI) == 0 && (v3d->flag2 & V3D_RENDER_SHADOW) == 0) { /* don't do xray in particle mode, need the z-buffer */ if (!(ob->mode & OB_MODE_PARTICLE_EDIT)) { /* xray and transp are set when it is drawing the 2nd/3rd pass */ @@ -7589,7 +8360,7 @@ void draw_object(Scene *scene, ARegion *ar, View3D *v3d, Base *base, const short ED_view3d_project_base(ar, base); - draw_object_wire_color(scene, base, _ob_wire_col); + draw_object_wire_color(scene, sl, base, _ob_wire_col); ob_wire_col = _ob_wire_col; glColor3ubv(ob_wire_col); @@ -7644,15 +8415,29 @@ void draw_object(Scene *scene, ARegion *ar, View3D *v3d, Base *base, const short /* draw outline for selected objects, mesh does itself */ if ((v3d->flag & V3D_SELECT_OUTLINE) && !render_override && ob->type != OB_MESH) { if (dt > OB_WIRE && (ob->mode & OB_MODE_EDIT) == 0 && (dflag & DRAW_SCENESET) == 0) { - if (!(ob->dtx & OB_DRAWWIRE) && (ob->flag & SELECT) && !(dflag & (DRAW_PICKING | DRAW_CONSTCOLOR))) { - drawObjectSelect(scene, v3d, ar, base, ob_wire_col); + if (!(ob->dtx & OB_DRAWWIRE) && (base->flag & BASE_SELECTED) && !(dflag & (DRAW_PICKING | DRAW_CONSTCOLOR))) { + drawObjectSelect(scene, sl, v3d, ar, base, ob_wire_col); + } + } + } + + /* TODO Viewport: draw only for selection */ + if (!IS_VIEWPORT_LEGACY(v3d)) { + if ((dflag & DRAW_PICKING) == 0) { + if ((dt == OB_BOUNDBOX) || ELEM(ob->type, OB_EMPTY, OB_LAMP, OB_CAMERA, OB_SPEAKER)) { + goto afterdraw; } } } switch (ob->type) { case OB_MESH: - empty_object = draw_mesh_object(scene, ar, v3d, rv3d, base, dt, ob_wire_col, dflag); + if (IS_VIEWPORT_LEGACY(v3d)) { + empty_object = draw_mesh_object(scene, ar, v3d, rv3d, base, dt, ob_wire_col, dflag); + } + else { + empty_object = draw_mesh_object_new(scene, ar, v3d, rv3d, base, dt, ob_wire_col, dflag); + } if ((dflag & DRAW_CONSTCOLOR) == 0) { /* mesh draws wire itself */ dtx &= ~OB_DRAWWIRE; @@ -7721,7 +8506,7 @@ void draw_object(Scene *scene, ARegion *ar, View3D *v3d, Base *base, const short draw_empty_image(ob, dflag, ob_wire_col, v3d->multiview_eye); } else { - drawaxes(rv3d->viewmatob, ob->empty_drawsize, ob->empty_drawtype); + drawaxes(rv3d->viewmatob, ob->empty_drawsize, ob->empty_drawtype, ob_wire_col); } } break; @@ -7739,7 +8524,7 @@ void draw_object(Scene *scene, ARegion *ar, View3D *v3d, Base *base, const short break; case OB_SPEAKER: if (!render_override) - drawspeaker(scene, v3d, rv3d, ob, dflag); + drawspeaker(ob_wire_col); break; case OB_LATTICE: if (!render_override) { @@ -7766,18 +8551,31 @@ void draw_object(Scene *scene, ARegion *ar, View3D *v3d, Base *base, const short draw_bounding_volume(ob, ob->boundtype); } else { + unsigned char arm_col[4]; glLineWidth(1.0f); - empty_object = draw_armature(scene, v3d, ar, base, dt, dflag, ob_wire_col, false); + + if (ob_wire_col == NULL) { + float fcol[4]; + glGetFloatv(GL_CURRENT_COLOR, fcol); + rgba_float_to_uchar(arm_col, fcol); + } + else + copy_v4_v4_uchar(arm_col, ob_wire_col); + + empty_object = draw_armature(scene, sl, v3d, ar, base, dt, dflag, arm_col, false); } } break; default: if (!render_override) { - drawaxes(rv3d->viewmatob, 1.0, OB_ARROWS); + drawaxes(rv3d->viewmatob, 1.0, OB_ARROWS, ob_wire_col); } break; } + /* TODO Viewport: some elements are being drawn for object selection only */ +afterdraw: + if (!render_override) { if (ob->soft /*&& dflag & OB_SBMOTION*/) { float mrt[3][3], msc[3][3], mtr[3][3]; @@ -7810,7 +8608,7 @@ void draw_object(Scene *scene, ARegion *ar, View3D *v3d, Base *base, const short if ((dflag & DRAW_CONSTCOLOR) == 0) { /* for visibility, also while wpaint */ - if (col || (ob->flag & SELECT)) { + if (col || (base->flag & BASE_SELECTED)) { cpack(0xFFFFFF); } } @@ -7858,6 +8656,7 @@ void draw_object(Scene *scene, ARegion *ar, View3D *v3d, Base *base, const short /* draw code for smoke, only draw domains */ if (smd && smd->domain) { SmokeDomainSettings *sds = smd->domain; + const bool show_smoke = (CFRA >= sds->point_cache[0]->startframe); float viewnormal[3]; glLoadMatrixf(rv3d->viewmat); @@ -7890,7 +8689,7 @@ void draw_object(Scene *scene, ARegion *ar, View3D *v3d, Base *base, const short } /* don't show smoke before simulation starts, this could be made an option in the future */ - if (sds->fluid && CFRA >= sds->point_cache[0]->startframe) { + if (sds->fluid && show_smoke) { float p0[3], p1[3]; /* get view vector */ @@ -7954,7 +8753,13 @@ void draw_object(Scene *scene, ARegion *ar, View3D *v3d, Base *base, const short if (dtx && (G.f & G_RENDER_OGL) == 0) { if (dtx & OB_AXIS) { - drawaxes(rv3d->viewmatob, 1.0f, OB_ARROWS); + if ((dflag & DRAW_CONSTCOLOR) == 0) { + /* prevent random colors being used */ + drawaxes(rv3d->viewmatob, 1.0f, OB_ARROWS, ob_wire_col); + } + else { + drawaxes(rv3d->viewmatob, 1.0f, OB_ARROWS, NULL); + } } if (dtx & OB_DRAWBOUNDOX) { draw_bounding_volume(ob, ob->boundtype); @@ -8016,7 +8821,7 @@ void draw_object(Scene *scene, ARegion *ar, View3D *v3d, Base *base, const short glDisable(GL_DEPTH_TEST); } - if ((base->flag & OB_FROMDUPLI) || render_override) { + if ((base->flag_legacy & OB_FROMDUPLI) || render_override) { ED_view3d_clear_mats_rv3d(rv3d); return; } @@ -8030,7 +8835,7 @@ void draw_object(Scene *scene, ARegion *ar, View3D *v3d, Base *base, const short } else if (is_obact) do_draw_center = ACTIVE; - else if (base->flag & SELECT) + else if (base->flag & BASE_SELECTED) do_draw_center = SELECT; else if (empty_object || (v3d->flag & V3D_DRAW_CENTERS)) do_draw_center = DESELECT; @@ -8041,10 +8846,15 @@ void draw_object(Scene *scene, ARegion *ar, View3D *v3d, Base *base, const short if ((base->sx != IS_CLIPPED) && (U.obcenter_dia != 0.0)) { + unsigned pos = add_attrib(immVertexFormat(), "pos", GL_FLOAT, 3, KEEP_FLOAT); + immBindBuiltinProgram(GPU_SHADER_3D_POINT_FIXED_SIZE_UNIFORM_COLOR); + /* TODO: short term, use DEPTH_ONLY shader or set appropriate color */ + /* TODO: long term, solve picking & selection problem better */ glPointSize(U.obcenter_dia); - glBegin(GL_POINTS); - glVertex3fv(ob->obmat[3]); - glEnd(); + immBegin(GL_POINTS, 1); + immVertex3fv(pos, ob->obmat[3]); + immEnd(); + immUnbindProgram(); } } else if ((dflag & DRAW_CONSTCOLOR) == 0) { @@ -8486,11 +9296,13 @@ static void draw_object_mesh_instance(Scene *scene, View3D *v3d, RegionView3D *r if (dm) dm->release(dm); } -void draw_object_instance(Scene *scene, View3D *v3d, RegionView3D *rv3d, Object *ob, const char dt, int outline) +void draw_object_instance(Scene *scene, View3D *v3d, RegionView3D *rv3d, Object *ob, const char dt, int outline, float wire_col[4]) { if (ob == NULL) return; + glColor4fv(wire_col); + switch (ob->type) { case OB_MESH: draw_object_mesh_instance(scene, v3d, rv3d, ob, dt, outline); @@ -8501,7 +9313,7 @@ void draw_object_instance(Scene *scene, View3D *v3d, RegionView3D *rv3d, Object draw_empty_image(ob, DRAW_CONSTCOLOR, NULL, v3d->multiview_eye); } else { - drawaxes(rv3d->viewmatob, ob->empty_drawsize, ob->empty_drawtype); + drawaxes(rv3d->viewmatob, ob->empty_drawsize, ob->empty_drawtype, NULL); /* TODO: use proper color */ } break; } diff --git a/source/blender/editors/space_view3d/drawsimdebug.c b/source/blender/editors/space_view3d/drawsimdebug.c index 9414d39467d..e47adbea657 100644 --- a/source/blender/editors/space_view3d/drawsimdebug.c +++ b/source/blender/editors/space_view3d/drawsimdebug.c @@ -40,6 +40,8 @@ #include "BKE_effect.h" +#include "GPU_immediate.h" + #include "view3d_intern.h" #include "BIF_gl.h" @@ -47,95 +49,129 @@ static void draw_sim_debug_elements(SimDebugData *debug_data, float imat[4][4]) { + VertexFormat *format = immVertexFormat(); + unsigned int pos = add_attrib(format, "pos", GL_FLOAT, 3, KEEP_FLOAT); + unsigned int color = add_attrib(format, "color", GL_FLOAT, 3, KEEP_FLOAT); + + immBindBuiltinProgram(GPU_SHADER_3D_FLAT_COLOR); + + /* count element types */ GHashIterator iter; + int num_dots = 0; + int num_circles = 0; + int num_lines = 0; + int num_vectors = 0; + for (BLI_ghashIterator_init(&iter, debug_data->gh); !BLI_ghashIterator_done(&iter); BLI_ghashIterator_step(&iter)) { + SimDebugElement *elem = BLI_ghashIterator_getValue(&iter); + switch (elem->type) { + case SIM_DEBUG_ELEM_DOT: ++num_dots; break; + case SIM_DEBUG_ELEM_CIRCLE: ++num_circles; break; + case SIM_DEBUG_ELEM_LINE: ++num_lines; break; + case SIM_DEBUG_ELEM_VECTOR: ++num_vectors; break; + } + } /**** dots ****/ glPointSize(3.0f); - glBegin(GL_POINTS); + immBegin(GL_POINTS, num_dots); for (BLI_ghashIterator_init(&iter, debug_data->gh); !BLI_ghashIterator_done(&iter); BLI_ghashIterator_step(&iter)) { SimDebugElement *elem = BLI_ghashIterator_getValue(&iter); if (elem->type != SIM_DEBUG_ELEM_DOT) continue; - glColor3f(elem->color[0], elem->color[1], elem->color[2]); - glVertex3f(elem->v1[0], elem->v1[1], elem->v1[2]); + immAttrib3fv(color, elem->color); + immVertex3fv(pos, elem->v1); } - glEnd(); + immEnd(); /**** circles ****/ { - float circle[16][2] = { +#define CIRCLERES 16 + float circle[CIRCLERES][2] = { {0.000000, 1.000000}, {0.382683, 0.923880}, {0.707107, 0.707107}, {0.923880, 0.382683}, {1.000000, -0.000000}, {0.923880, -0.382683}, {0.707107, -0.707107}, {0.382683, -0.923880}, {-0.000000, -1.000000}, {-0.382683, -0.923880}, {-0.707107, -0.707107}, {-0.923879, -0.382684}, {-1.000000, 0.000000}, {-0.923879, 0.382684}, {-0.707107, 0.707107}, {-0.382683, 0.923880} }; + + immBegin(GL_LINES, num_circles * CIRCLERES * 2); + for (BLI_ghashIterator_init(&iter, debug_data->gh); !BLI_ghashIterator_done(&iter); BLI_ghashIterator_step(&iter)) { SimDebugElement *elem = BLI_ghashIterator_getValue(&iter); float radius = elem->v2[0]; - float co[3]; + float co[3], nco[3]; int i; if (elem->type != SIM_DEBUG_ELEM_CIRCLE) continue; - glColor3f(elem->color[0], elem->color[1], elem->color[2]); - glBegin(GL_LINE_LOOP); - for (i = 0; i < 16; ++i) { - co[0] = radius * circle[i][0]; - co[1] = radius * circle[i][1]; - co[2] = 0.0f; - mul_mat3_m4_v3(imat, co); - add_v3_v3(co, elem->v1); + immAttrib3fv(color, elem->color); + zero_v3(co); + for (i = 0; i <= CIRCLERES; ++i) { + int ni = i % CIRCLERES; + nco[0] = radius * circle[ni][0]; + nco[1] = radius * circle[ni][1]; + nco[2] = 0.0f; + mul_mat3_m4_v3(imat, nco); + add_v3_v3(nco, elem->v1); - glVertex3f(co[0], co[1], co[2]); + if (i > 0) { + immVertex3fv(pos, co); + immVertex3fv(pos, nco); + } + + copy_v3_v3(co, nco); } - glEnd(); } + + immEnd(); +#undef CIRCLERES } /**** lines ****/ - glBegin(GL_LINES); + immBegin(GL_LINES, num_lines * 2); for (BLI_ghashIterator_init(&iter, debug_data->gh); !BLI_ghashIterator_done(&iter); BLI_ghashIterator_step(&iter)) { SimDebugElement *elem = BLI_ghashIterator_getValue(&iter); if (elem->type != SIM_DEBUG_ELEM_LINE) continue; - glColor3f(elem->color[0], elem->color[1], elem->color[2]); - glVertex3f(elem->v1[0], elem->v1[1], elem->v1[2]); - glVertex3f(elem->v2[0], elem->v2[1], elem->v2[2]); + immAttrib3fv(color, elem->color); + immVertex3fv(pos, elem->v1); + immVertex3fv(pos, elem->v2); } - glEnd(); + immEnd(); /**** vectors ****/ glPointSize(2.0f); - glBegin(GL_POINTS); + immBegin(GL_POINTS, num_vectors); for (BLI_ghashIterator_init(&iter, debug_data->gh); !BLI_ghashIterator_done(&iter); BLI_ghashIterator_step(&iter)) { SimDebugElement *elem = BLI_ghashIterator_getValue(&iter); if (elem->type != SIM_DEBUG_ELEM_VECTOR) continue; - glColor3f(elem->color[0], elem->color[1], elem->color[2]); - glVertex3f(elem->v1[0], elem->v1[1], elem->v1[2]); + immAttrib3fv(color, elem->color); + immVertex3fv(pos, elem->v1); } - glEnd(); + immEnd(); - glBegin(GL_LINES); + immBegin(GL_LINES, num_vectors * 2); for (BLI_ghashIterator_init(&iter, debug_data->gh); !BLI_ghashIterator_done(&iter); BLI_ghashIterator_step(&iter)) { SimDebugElement *elem = BLI_ghashIterator_getValue(&iter); float t[3]; if (elem->type != SIM_DEBUG_ELEM_VECTOR) continue; - glColor3f(elem->color[0], elem->color[1], elem->color[2]); - glVertex3f(elem->v1[0], elem->v1[1], elem->v1[2]); + immAttrib3fv(color, elem->color); + immVertex3fv(pos, elem->v1); add_v3_v3v3(t, elem->v1, elem->v2); - glVertex3f(t[0], t[1], t[2]); + immVertex3fv(pos, t); } - glEnd(); + immEnd(); + + immUnbindProgram(); /**** strings ****/ @@ -163,9 +199,6 @@ void draw_sim_debug_data(Scene *UNUSED(scene), View3D *v3d, ARegion *ar) invert_m4_m4(imat, rv3d->viewmatob); -// glDepthMask(GL_FALSE); -// glEnable(GL_BLEND); - glPushMatrix(); glLoadMatrixf(rv3d->viewmat); @@ -174,7 +207,4 @@ void draw_sim_debug_data(Scene *UNUSED(scene), View3D *v3d, ARegion *ar) view3d_cached_text_draw_end(v3d, ar, false, NULL); glPopMatrix(); - -// glDepthMask(GL_TRUE); -// glDisable(GL_BLEND); } diff --git a/source/blender/editors/space_view3d/drawvolume.c b/source/blender/editors/space_view3d/drawvolume.c index 27ecbf83db5..debdcb58d71 100644 --- a/source/blender/editors/space_view3d/drawvolume.c +++ b/source/blender/editors/space_view3d/drawvolume.c @@ -160,7 +160,7 @@ static GPUTexture *create_field_texture(SmokeDomainSettings *sds) default: return NULL; } - return GPU_texture_create_3D(sds->res[0], sds->res[1], sds->res[2], 1, field); + return GPU_texture_create_3D_custom(sds->res[0], sds->res[1], sds->res[2], 1, GPU_R8, field, NULL); } typedef struct VolumeSlicer { diff --git a/source/blender/editors/space_view3d/space_view3d.c b/source/blender/editors/space_view3d/space_view3d.c index e73cc507f3e..b57f8e9d40f 100644 --- a/source/blender/editors/space_view3d/space_view3d.c +++ b/source/blender/editors/space_view3d/space_view3d.c @@ -57,6 +57,7 @@ #include "GPU_compositing.h" #include "GPU_framebuffer.h" #include "GPU_material.h" +#include "GPU_viewport.h" #include "BIF_gl.h" @@ -582,6 +583,12 @@ static void view3d_main_region_exit(wmWindowManager *wm, ARegion *ar) GPU_fx_compositor_destroy(rv3d->compositor); rv3d->compositor = NULL; } + + if (rv3d->viewport) { + GPU_viewport_free(rv3d->viewport); + MEM_freeN(rv3d->viewport); + rv3d->viewport = NULL; + } } static int view3d_ob_drop_poll(bContext *UNUSED(C), wmDrag *drag, const wmEvent *UNUSED(event)) @@ -641,7 +648,7 @@ static int view3d_ima_bg_drop_poll(bContext *C, wmDrag *drag, const wmEvent *eve static int view3d_ima_empty_drop_poll(bContext *C, wmDrag *drag, const wmEvent *event) { - Base *base = ED_view3d_give_base_under_cursor(C, event->mval); + BaseLegacy *base = ED_view3d_give_base_under_cursor(C, event->mval); /* either holding and ctrl and no object, or dropping to empty */ if (((base == NULL) && event->ctrl) || @@ -655,7 +662,7 @@ static int view3d_ima_empty_drop_poll(bContext *C, wmDrag *drag, const wmEvent * static int view3d_ima_mesh_drop_poll(bContext *C, wmDrag *drag, const wmEvent *event) { - Base *base = ED_view3d_give_base_under_cursor(C, event->mval); + BaseLegacy *base = ED_view3d_give_base_under_cursor(C, event->mval); if (base && base->object->type == OB_MESH) return view3d_ima_drop_poll(C, drag, event); @@ -739,6 +746,10 @@ static void view3d_main_region_free(ARegion *ar) if (rv3d->compositor) { GPU_fx_compositor_destroy(rv3d->compositor); } + if (rv3d->viewport) { + GPU_viewport_free(rv3d->viewport); + MEM_freeN(rv3d->viewport); + } MEM_freeN(rv3d); ar->regiondata = NULL; @@ -763,6 +774,7 @@ static void *view3d_main_region_duplicate(void *poin) new->sms = NULL; new->smooth_timer = NULL; new->compositor = NULL; + new->viewport = NULL; return new; } @@ -774,7 +786,7 @@ static void view3d_recalc_used_layers(ARegion *ar, wmNotifier *wmn, Scene *scene wmWindow *win = wmn->wm->winactive; ScrArea *sa; unsigned int lay_used = 0; - Base *base; + BaseLegacy *base; if (!win) return; @@ -927,21 +939,13 @@ static void view3d_main_region_listener(bScreen *sc, ScrArea *sa, ARegion *ar, w switch (wmn->data) { case ND_SHADING: case ND_NODES: - { -#ifdef WITH_LEGACY_DEPSGRAPH - Object *ob = OBACT; - if ((v3d->drawtype == OB_MATERIAL) || - (ob && (ob->mode == OB_MODE_TEXTURE_PAINT)) || - (v3d->drawtype == OB_TEXTURE && - (scene->gm.matmode == GAME_MAT_GLSL || - BKE_scene_use_new_shading_nodes(scene))) || - !DEG_depsgraph_use_legacy()) -#endif - { - ED_region_tag_redraw(ar); - } + /* TODO(sergey) This is a bit too much updates, but needed to + * have proper material drivers update in the viewport. + * + * How to solve? + */ + ED_region_tag_redraw(ar); break; - } case ND_SHADING_DRAW: case ND_SHADING_LINKS: ED_region_tag_redraw(ar); @@ -958,12 +962,10 @@ static void view3d_main_region_listener(bScreen *sc, ScrArea *sa, ARegion *ar, w case NC_LAMP: switch (wmn->data) { case ND_LIGHTING: - if ((v3d->drawtype == OB_MATERIAL) || - (v3d->drawtype == OB_TEXTURE && (scene->gm.matmode == GAME_MAT_GLSL)) || - !DEG_depsgraph_use_legacy()) - { - ED_region_tag_redraw(ar); - } + /* TODO(sergey): This is a bit too much, but needed to + * handle updates from new depsgraph. + */ + ED_region_tag_redraw(ar); break; case ND_LIGHTING_DRAW: ED_region_tag_redraw(ar); @@ -1259,8 +1261,6 @@ static void space_view3d_listener(bScreen *UNUSED(sc), ScrArea *sa, struct wmNot } const char *view3d_context_dir[] = { - "selected_objects", "selected_bases", "selected_editable_objects", - "selected_editable_bases", "visible_objects", "visible_bases", "selectable_objects", "selectable_bases", "active_base", "active_object", NULL }; @@ -1271,109 +1271,27 @@ static int view3d_context(const bContext *C, const char *member, bContextDataRes if (CTX_data_dir(member)) { CTX_data_dir_set(result, view3d_context_dir); } - else if (CTX_data_equals(member, "selected_objects") || CTX_data_equals(member, "selected_bases")) { - View3D *v3d = CTX_wm_view3d(C); - Scene *scene = CTX_data_scene(C); - const unsigned int lay = v3d ? v3d->lay : scene->lay; - Base *base; - const bool selected_objects = CTX_data_equals(member, "selected_objects"); - - for (base = scene->base.first; base; base = base->next) { - if ((base->flag & SELECT) && (base->lay & lay)) { - if ((base->object->restrictflag & OB_RESTRICT_VIEW) == 0) { - if (selected_objects) - CTX_data_id_list_add(result, &base->object->id); - else - CTX_data_list_add(result, &scene->id, &RNA_ObjectBase, base); - } - } - } - CTX_data_type_set(result, CTX_DATA_TYPE_COLLECTION); - return 1; - } - else if (CTX_data_equals(member, "selected_editable_objects") || CTX_data_equals(member, "selected_editable_bases")) { - View3D *v3d = CTX_wm_view3d(C); - Scene *scene = CTX_data_scene(C); - const unsigned int lay = v3d ? v3d->lay : scene->lay; - Base *base; - const bool selected_editable_objects = CTX_data_equals(member, "selected_editable_objects"); - - for (base = scene->base.first; base; base = base->next) { - if ((base->flag & SELECT) && (base->lay & lay)) { - if ((base->object->restrictflag & OB_RESTRICT_VIEW) == 0) { - if (0 == BKE_object_is_libdata(base->object)) { - if (selected_editable_objects) - CTX_data_id_list_add(result, &base->object->id); - else - CTX_data_list_add(result, &scene->id, &RNA_ObjectBase, base); - } - } - } - } - CTX_data_type_set(result, CTX_DATA_TYPE_COLLECTION); - return 1; - } - else if (CTX_data_equals(member, "visible_objects") || CTX_data_equals(member, "visible_bases")) { - View3D *v3d = CTX_wm_view3d(C); - Scene *scene = CTX_data_scene(C); - const unsigned int lay = v3d ? v3d->lay : scene->lay; - Base *base; - const bool visible_objects = CTX_data_equals(member, "visible_objects"); - - for (base = scene->base.first; base; base = base->next) { - if (base->lay & lay) { - if ((base->object->restrictflag & OB_RESTRICT_VIEW) == 0) { - if (visible_objects) - CTX_data_id_list_add(result, &base->object->id); - else - CTX_data_list_add(result, &scene->id, &RNA_ObjectBase, base); - } - } - } - CTX_data_type_set(result, CTX_DATA_TYPE_COLLECTION); - return 1; - } - else if (CTX_data_equals(member, "selectable_objects") || CTX_data_equals(member, "selectable_bases")) { - View3D *v3d = CTX_wm_view3d(C); - Scene *scene = CTX_data_scene(C); - const unsigned int lay = v3d ? v3d->lay : scene->lay; - Base *base; - const bool selectable_objects = CTX_data_equals(member, "selectable_objects"); - - for (base = scene->base.first; base; base = base->next) { - if (base->lay & lay) { - if ((base->object->restrictflag & OB_RESTRICT_VIEW) == 0 && (base->object->restrictflag & OB_RESTRICT_SELECT) == 0) { - if (selectable_objects) - CTX_data_id_list_add(result, &base->object->id); - else - CTX_data_list_add(result, &scene->id, &RNA_ObjectBase, base); - } - } - } - CTX_data_type_set(result, CTX_DATA_TYPE_COLLECTION); - return 1; - } else if (CTX_data_equals(member, "active_base")) { - View3D *v3d = CTX_wm_view3d(C); Scene *scene = CTX_data_scene(C); - const unsigned int lay = v3d ? v3d->lay : scene->lay; - if (scene->basact && (scene->basact->lay & lay)) { - Object *ob = scene->basact->object; + SceneLayer *sl = CTX_data_scene_layer(C); + if (sl->basact) { + Object *ob = sl->basact->object; /* if hidden but in edit mode, we still display, can happen with animation */ - if ((ob->restrictflag & OB_RESTRICT_VIEW) == 0 || (ob->mode & OB_MODE_EDIT)) - CTX_data_pointer_set(result, &scene->id, &RNA_ObjectBase, scene->basact); + if ((sl->basact->flag & BASE_VISIBLED) != 0 || (ob->mode & OB_MODE_EDIT)) { + CTX_data_pointer_set(result, &scene->id, &RNA_ObjectBase, sl->basact); + } } return 1; } else if (CTX_data_equals(member, "active_object")) { - View3D *v3d = CTX_wm_view3d(C); - Scene *scene = CTX_data_scene(C); - const unsigned int lay = v3d ? v3d->lay : scene->lay; - if (scene->basact && (scene->basact->lay & lay)) { - Object *ob = scene->basact->object; - if ((ob->restrictflag & OB_RESTRICT_VIEW) == 0 || (ob->mode & OB_MODE_EDIT)) - CTX_data_id_pointer_set(result, &scene->basact->object->id); + SceneLayer *sl = CTX_data_scene_layer(C); + if (sl->basact) { + Object *ob = sl->basact->object; + /* if hidden but in edit mode, we still display, can happen with animation */ + if ((sl->basact->flag & BASE_VISIBLED) != 0 || (ob->mode & OB_MODE_EDIT) != 0) { + CTX_data_id_pointer_set(result, &ob->id); + } } return 1; diff --git a/source/blender/editors/space_view3d/view3d_draw.c b/source/blender/editors/space_view3d/view3d_draw.c index f23e587e55d..325c81a3fd2 100644 --- a/source/blender/editors/space_view3d/view3d_draw.c +++ b/source/blender/editors/space_view3d/view3d_draw.c @@ -28,945 +28,338 @@ * \ingroup spview3d */ -#include <string.h> -#include <stdio.h> #include <math.h> -#include "DNA_armature_types.h" -#include "DNA_camera_types.h" -#include "DNA_customdata_types.h" -#include "DNA_object_types.h" -#include "DNA_group_types.h" -#include "DNA_mesh_types.h" -#include "DNA_key_types.h" -#include "DNA_lamp_types.h" -#include "DNA_scene_types.h" -#include "DNA_world_types.h" -#include "DNA_brush_types.h" - -#include "MEM_guardedalloc.h" - -#include "BLI_blenlib.h" -#include "BLI_math.h" -#include "BLI_jitter.h" -#include "BLI_utildefines.h" -#include "BLI_endian_switch.h" -#include "BLI_threads.h" +#include "BIF_gl.h" +#include "BIF_glutil.h" -#include "BKE_anim.h" #include "BKE_camera.h" #include "BKE_context.h" -#include "BKE_customdata.h" -#include "BKE_DerivedMesh.h" -#include "BKE_image.h" #include "BKE_key.h" -#include "BKE_main.h" +#include "BKE_scene.h" #include "BKE_object.h" -#include "BKE_global.h" #include "BKE_paint.h" -#include "BKE_scene.h" -#include "BKE_screen.h" #include "BKE_unit.h" -#include "BKE_movieclip.h" -#include "RE_engine.h" - -#include "IMB_imbuf_types.h" -#include "IMB_imbuf.h" -#include "IMB_colormanagement.h" - -#include "BIF_gl.h" -#include "BIF_glutil.h" +#include "BLF_api.h" -#include "WM_api.h" +#include "BLI_listbase.h" +#include "BLI_math.h" +#include "BLI_rect.h" +#include "BLI_string.h" +#include "BLI_threads.h" -#include "BLF_api.h" #include "BLT_translation.h" -#include "ED_armature.h" +#include "DNA_armature_types.h" +#include "DNA_brush_types.h" +#include "DNA_camera_types.h" +#include "DNA_key_types.h" +#include "DNA_mesh_types.h" +#include "DNA_object_types.h" +#include "DNA_view3d_types.h" +#include "DNA_windowmanager_types.h" + #include "ED_keyframing.h" -#include "ED_gpencil.h" +#include "ED_armature.h" #include "ED_screen.h" -#include "ED_space_api.h" -#include "ED_screen_types.h" #include "ED_transform.h" +#include "ED_gpencil.h" + +#include "GPU_matrix.h" +#include "GPU_immediate.h" +#include "GPU_material.h" +#include "GPU_viewport.h" + +#include "MEM_guardedalloc.h" #include "UI_interface.h" -#include "UI_interface_icons.h" #include "UI_resources.h" -#include "GPU_draw.h" -#include "GPU_framebuffer.h" -#include "GPU_material.h" -#include "GPU_compositing.h" -#include "GPU_extensions.h" +#include "RE_engine.h" + +#include "WM_api.h" #include "view3d_intern.h" /* own include */ /* prototypes */ -static void view3d_stereo3d_setup(Scene *scene, View3D *v3d, ARegion *ar); -static void view3d_stereo3d_setup_offscreen(Scene *scene, View3D *v3d, ARegion *ar, - float winmat[4][4], const char *viewname); - -/* handy utility for drawing shapes in the viewport for arbitrary code. - * could add lines and points too */ -// #define DEBUG_DRAW -#ifdef DEBUG_DRAW -static void bl_debug_draw(void); -/* add these locally when using these functions for testing */ -extern void bl_debug_draw_quad_clear(void); -extern void bl_debug_draw_quad_add(const float v0[3], const float v1[3], const float v2[3], const float v3[3]); -extern void bl_debug_draw_edge_add(const float v0[3], const float v1[3]); -extern void bl_debug_color_set(const unsigned int col); -#endif +static void draw_all_objects(const bContext *C, ARegion *ar, const bool only_depth, const bool use_depth); -void circf(float x, float y, float rad) -{ - GLUquadricObj *qobj = gluNewQuadric(); - - gluQuadricDrawStyle(qobj, GLU_FILL); - - glPushMatrix(); - - glTranslatef(x, y, 0.0); - - gluDisk(qobj, 0.0, rad, 32, 1); - - glPopMatrix(); - - gluDeleteQuadric(qobj); -} - -void circ(float x, float y, float rad) -{ - GLUquadricObj *qobj = gluNewQuadric(); - - gluQuadricDrawStyle(qobj, GLU_SILHOUETTE); - - glPushMatrix(); - - glTranslatef(x, y, 0.0); - - gluDisk(qobj, 0.0, rad, 32, 1); - - glPopMatrix(); - - gluDeleteQuadric(qobj); -} - - -/* ********* custom clipping *********** */ - -static void view3d_draw_clipping(RegionView3D *rv3d) -{ - BoundBox *bb = rv3d->clipbb; - - if (bb) { - const unsigned int clipping_index[6][4] = { - {0, 1, 2, 3}, - {0, 4, 5, 1}, - {4, 7, 6, 5}, - {7, 3, 2, 6}, - {1, 5, 6, 2}, - {7, 4, 0, 3} - }; - - /* fill in zero alpha for rendering & re-projection [#31530] */ - unsigned char col[4]; - UI_GetThemeColor4ubv(TH_V3D_CLIPPING_BORDER, col); - glColor4ubv(col); - - glEnable(GL_BLEND); - glEnableClientState(GL_VERTEX_ARRAY); - glVertexPointer(3, GL_FLOAT, 0, bb->vec); - glDrawElements(GL_QUADS, sizeof(clipping_index) / sizeof(unsigned int), GL_UNSIGNED_INT, clipping_index); - glDisableClientState(GL_VERTEX_ARRAY); - glDisable(GL_BLEND); - } -} +typedef struct DrawData { + rcti border_rect; + bool render_border; + bool clip_border; + bool is_render; + GPUViewport *viewport; +} DrawData; -void ED_view3d_clipping_set(RegionView3D *rv3d) +static void view3d_draw_data_init(const bContext *C, ARegion *ar, RegionView3D *rv3d, DrawData *draw_data) { - double plane[4]; - const unsigned int tot = (rv3d->viewlock & RV3D_BOXCLIP) ? 4 : 6; - unsigned int a; + Scene *scene = CTX_data_scene(C); + View3D *v3d = CTX_wm_view3d(C); - for (a = 0; a < tot; a++) { - copy_v4db_v4fl(plane, rv3d->clip[a]); - glClipPlane(GL_CLIP_PLANE0 + a, plane); - glEnable(GL_CLIP_PLANE0 + a); - } -} + draw_data->is_render = (v3d->drawtype == OB_RENDER); -/* use these to temp disable/enable clipping when 'rv3d->rflag & RV3D_CLIPPING' is set */ -void ED_view3d_clipping_disable(void) -{ - unsigned int a; + draw_data->render_border = ED_view3d_calc_render_border(scene, v3d, ar, &draw_data->border_rect); + draw_data->clip_border = (draw_data->render_border && !BLI_rcti_compare(&ar->drawrct, &draw_data->border_rect)); - for (a = 0; a < 6; a++) { - glDisable(GL_CLIP_PLANE0 + a); - } + draw_data->viewport = rv3d->viewport; } -void ED_view3d_clipping_enable(void) -{ - unsigned int a; - for (a = 0; a < 6; a++) { - glEnable(GL_CLIP_PLANE0 + a); - } -} +/* ******************** general functions ***************** */ -static bool view3d_clipping_test(const float co[3], const float clip[6][4]) +static bool use_depth_doit(Scene *scene, View3D *v3d) { - if (plane_point_side_v3(clip[0], co) > 0.0f) - if (plane_point_side_v3(clip[1], co) > 0.0f) - if (plane_point_side_v3(clip[2], co) > 0.0f) - if (plane_point_side_v3(clip[3], co) > 0.0f) - return false; + if (v3d->drawtype > OB_WIRE) + return true; - return true; + /* special case (depth for wire color) */ + if (v3d->drawtype <= OB_WIRE) { + if (scene->obedit && scene->obedit->type == OB_MESH) { + Mesh *me = scene->obedit->data; + if (me->drawflag & ME_DRAWEIGHT) { + return true; + } + } + } + return false; } -/* for 'local' ED_view3d_clipping_local must run first - * then all comparisons can be done in localspace */ -bool ED_view3d_clipping_test(const RegionView3D *rv3d, const float co[3], const bool is_local) +static bool use_depth(const bContext *C) { - return view3d_clipping_test(co, is_local ? rv3d->clip_local : rv3d->clip); -} - -/* ********* end custom clipping *********** */ - - -static void drawgrid_draw(ARegion *ar, double wx, double wy, double x, double y, double dx) -{ - double verts[2][2]; - - x += (wx); - y += (wy); - - /* set fixed 'Y' */ - verts[0][1] = 0.0f; - verts[1][1] = (double)ar->winy; - - /* iter over 'X' */ - verts[0][0] = verts[1][0] = x - dx * floor(x / dx); - glEnableClientState(GL_VERTEX_ARRAY); - glVertexPointer(2, GL_DOUBLE, 0, verts); - - while (verts[0][0] < ar->winx) { - glDrawArrays(GL_LINES, 0, 2); - verts[0][0] = verts[1][0] = verts[0][0] + dx; - } - - /* set fixed 'X' */ - verts[0][0] = 0.0f; - verts[1][0] = (double)ar->winx; - - /* iter over 'Y' */ - verts[0][1] = verts[1][1] = y - dx * floor(y / dx); - while (verts[0][1] < ar->winy) { - glDrawArrays(GL_LINES, 0, 2); - verts[0][1] = verts[1][1] = verts[0][1] + dx; - } - - glDisableClientState(GL_VERTEX_ARRAY); + View3D *v3d = CTX_wm_view3d(C); + Scene *scene = CTX_data_scene(C); + return use_depth_doit(scene, v3d); } -#define GRID_MIN_PX_D 6.0 -#define GRID_MIN_PX_F 6.0f - -static void drawgrid(UnitSettings *unit, ARegion *ar, View3D *v3d, const char **grid_unit) +/** + * \note keep this synced with #ED_view3d_mats_rv3d_backup/#ED_view3d_mats_rv3d_restore + */ +void ED_view3d_update_viewmat(Scene *scene, View3D *v3d, ARegion *ar, float viewmat[4][4], float winmat[4][4]) { - /* extern short bgpicmode; */ RegionView3D *rv3d = ar->regiondata; - double wx, wy, x, y, fw, fx, fy, dx; - double vec4[4]; - unsigned char col[3], col2[3]; - - fx = rv3d->persmat[3][0]; - fy = rv3d->persmat[3][1]; - fw = rv3d->persmat[3][3]; - - wx = (ar->winx / 2.0); /* because of rounding errors, grid at wrong location */ - wy = (ar->winy / 2.0); - x = (wx) * fx / fw; - y = (wy) * fy / fw; - vec4[0] = vec4[1] = v3d->grid; - - vec4[2] = 0.0; - vec4[3] = 1.0; - mul_m4_v4d(rv3d->persmat, vec4); - fx = vec4[0]; - fy = vec4[1]; - fw = vec4[3]; - - dx = fabs(x - (wx) * fx / fw); - if (dx == 0) dx = fabs(y - (wy) * fy / fw); - - glLineWidth(1.0f); - - glDepthMask(GL_FALSE); /* disable write in zbuffer */ - - /* check zoom out */ - UI_ThemeColor(TH_GRID); - - if (unit->system) { - /* Use GRID_MIN_PX * 2 for units because very very small grid - * items are less useful when dealing with units */ - const void *usys; - int len, i; - double dx_scalar; - float blend_fac; - - bUnit_GetSystem(unit->system, B_UNIT_LENGTH, &usys, &len); - - if (usys) { - i = len; - while (i--) { - double scalar = bUnit_GetScaler(usys, i); - - dx_scalar = dx * scalar / (double)unit->scale_length; - if (dx_scalar < (GRID_MIN_PX_D * 2.0)) - continue; + /* setup window matrices */ + if (winmat) + copy_m4_m4(rv3d->winmat, winmat); + else + view3d_winmatrix_set(ar, v3d, NULL); - /* Store the smallest drawn grid size units name so users know how big each grid cell is */ - if (*grid_unit == NULL) { - *grid_unit = bUnit_GetNameDisplay(usys, i); - rv3d->gridview = (float)((scalar * (double)v3d->grid) / (double)unit->scale_length); - } - blend_fac = 1.0f - ((GRID_MIN_PX_F * 2.0f) / (float)dx_scalar); + /* setup view matrix */ + if (viewmat) + copy_m4_m4(rv3d->viewmat, viewmat); + else + view3d_viewmatrix_set(scene, v3d, rv3d); /* note: calls BKE_object_where_is_calc for camera... */ - /* tweak to have the fade a bit nicer */ - blend_fac = (blend_fac * blend_fac) * 2.0f; - CLAMP(blend_fac, 0.3f, 1.0f); + /* update utility matrices */ + mul_m4_m4m4(rv3d->persmat, rv3d->winmat, rv3d->viewmat); + invert_m4_m4(rv3d->persinv, rv3d->persmat); + invert_m4_m4(rv3d->viewinv, rv3d->viewmat); + /* calculate GLSL view dependent values */ - UI_ThemeColorBlend(TH_HIGH_GRAD, TH_GRID, blend_fac); + /* store window coordinates scaling/offset */ + if (rv3d->persp == RV3D_CAMOB && v3d->camera) { + rctf cameraborder; + ED_view3d_calc_camera_border(scene, ar, v3d, rv3d, &cameraborder, false); + rv3d->viewcamtexcofac[0] = (float)ar->winx / BLI_rctf_size_x(&cameraborder); + rv3d->viewcamtexcofac[1] = (float)ar->winy / BLI_rctf_size_y(&cameraborder); - drawgrid_draw(ar, wx, wy, x, y, dx_scalar); - } - } + rv3d->viewcamtexcofac[2] = -rv3d->viewcamtexcofac[0] * cameraborder.xmin / (float)ar->winx; + rv3d->viewcamtexcofac[3] = -rv3d->viewcamtexcofac[1] * cameraborder.ymin / (float)ar->winy; } else { - const double sublines = v3d->gridsubdiv; - const float sublines_fl = v3d->gridsubdiv; - - if (dx < GRID_MIN_PX_D) { - rv3d->gridview *= sublines_fl; - dx *= sublines; - - if (dx < GRID_MIN_PX_D) { - rv3d->gridview *= sublines_fl; - dx *= sublines; - - if (dx < GRID_MIN_PX_D) { - rv3d->gridview *= sublines_fl; - dx *= sublines; - if (dx < GRID_MIN_PX_D) { - /* pass */ - } - else { - UI_ThemeColor(TH_GRID); - drawgrid_draw(ar, wx, wy, x, y, dx); - } - } - else { /* start blending out */ - UI_ThemeColorBlend(TH_HIGH_GRAD, TH_GRID, dx / (GRID_MIN_PX_D * 6.0)); - drawgrid_draw(ar, wx, wy, x, y, dx); - - UI_ThemeColor(TH_GRID); - drawgrid_draw(ar, wx, wy, x, y, sublines * dx); - } - } - else { /* start blending out (GRID_MIN_PX < dx < (GRID_MIN_PX * 10)) */ - UI_ThemeColorBlend(TH_HIGH_GRAD, TH_GRID, dx / (GRID_MIN_PX_D * 6.0)); - drawgrid_draw(ar, wx, wy, x, y, dx); - - UI_ThemeColor(TH_GRID); - drawgrid_draw(ar, wx, wy, x, y, sublines * dx); - } - } - else { - if (dx > (GRID_MIN_PX_D * 10.0)) { /* start blending in */ - rv3d->gridview /= sublines_fl; - dx /= sublines; - if (dx > (GRID_MIN_PX_D * 10.0)) { /* start blending in */ - rv3d->gridview /= sublines_fl; - dx /= sublines; - if (dx > (GRID_MIN_PX_D * 10.0)) { - UI_ThemeColor(TH_GRID); - drawgrid_draw(ar, wx, wy, x, y, dx); - } - else { - UI_ThemeColorBlend(TH_HIGH_GRAD, TH_GRID, dx / (GRID_MIN_PX_D * 6.0)); - drawgrid_draw(ar, wx, wy, x, y, dx); - UI_ThemeColor(TH_GRID); - drawgrid_draw(ar, wx, wy, x, y, dx * sublines); - } - } - else { - UI_ThemeColorBlend(TH_HIGH_GRAD, TH_GRID, dx / (GRID_MIN_PX_D * 6.0)); - drawgrid_draw(ar, wx, wy, x, y, dx); - UI_ThemeColor(TH_GRID); - drawgrid_draw(ar, wx, wy, x, y, dx * sublines); - } - } - else { - UI_ThemeColorBlend(TH_HIGH_GRAD, TH_GRID, dx / (GRID_MIN_PX_D * 6.0)); - drawgrid_draw(ar, wx, wy, x, y, dx); - UI_ThemeColor(TH_GRID); - drawgrid_draw(ar, wx, wy, x, y, dx * sublines); - } - } + rv3d->viewcamtexcofac[0] = rv3d->viewcamtexcofac[1] = 1.0f; + rv3d->viewcamtexcofac[2] = rv3d->viewcamtexcofac[3] = 0.0f; } + /* calculate pixelsize factor once, is used for lamps and obcenters */ + { + /* note: '1.0f / len_v3(v1)' replaced 'len_v3(rv3d->viewmat[0])' + * because of float point precision problems at large values [#23908] */ + float v1[3], v2[3]; + float len_px, len_sc; - x += (wx); - y += (wy); - UI_GetThemeColor3ubv(TH_GRID, col); + v1[0] = rv3d->persmat[0][0]; + v1[1] = rv3d->persmat[1][0]; + v1[2] = rv3d->persmat[2][0]; - setlinestyle(0); - - /* center cross */ - /* horizontal line */ - if (ELEM(rv3d->view, RV3D_VIEW_RIGHT, RV3D_VIEW_LEFT)) - UI_make_axis_color(col, col2, 'Y'); - else UI_make_axis_color(col, col2, 'X'); - glColor3ubv(col2); - - fdrawline(0.0, y, (float)ar->winx, y); - - /* vertical line */ - if (ELEM(rv3d->view, RV3D_VIEW_TOP, RV3D_VIEW_BOTTOM)) - UI_make_axis_color(col, col2, 'Y'); - else UI_make_axis_color(col, col2, 'Z'); - glColor3ubv(col2); + v2[0] = rv3d->persmat[0][1]; + v2[1] = rv3d->persmat[1][1]; + v2[2] = rv3d->persmat[2][1]; - fdrawline(x, 0.0, x, (float)ar->winy); + len_px = 2.0f / sqrtf(min_ff(len_squared_v3(v1), len_squared_v3(v2))); + len_sc = (float)MAX2(ar->winx, ar->winy); - glDepthMask(GL_TRUE); /* enable write in zbuffer */ + rv3d->pixsize = len_px / len_sc; + } } -#undef GRID_MIN_PX -/** could move this elsewhere, but tied into #ED_view3d_grid_scale */ -float ED_scene_grid_scale(Scene *scene, const char **grid_unit) +static void view3d_main_region_setup_view(Scene *scene, View3D *v3d, ARegion *ar, float viewmat[4][4], float winmat[4][4]) { - /* apply units */ - if (scene->unit.system) { - const void *usys; - int len; - - bUnit_GetSystem(scene->unit.system, B_UNIT_LENGTH, &usys, &len); - - if (usys) { - int i = bUnit_GetBaseUnit(usys); - if (grid_unit) - *grid_unit = bUnit_GetNameDisplay(usys, i); - return (float)bUnit_GetScaler(usys, i) / scene->unit.scale_length; - } - } + RegionView3D *rv3d = ar->regiondata; - return 1.0f; -} + ED_view3d_update_viewmat(scene, v3d, ar, viewmat, winmat); -float ED_view3d_grid_scale(Scene *scene, View3D *v3d, const char **grid_unit) -{ - return v3d->grid * ED_scene_grid_scale(scene, grid_unit); + /* set for opengl */ + /* TODO(merwin): transition to GPU_matrix API */ + glMatrixMode(GL_PROJECTION); + glLoadMatrixf(rv3d->winmat); + glMatrixMode(GL_MODELVIEW); + glLoadMatrixf(rv3d->viewmat); } -static void drawfloor(Scene *scene, View3D *v3d, const char **grid_unit, bool write_depth) +static bool view3d_stereo3d_active(const bContext *C, Scene *scene, View3D *v3d, RegionView3D *rv3d) { - float grid, grid_scale; - unsigned char col_grid[3]; - const int gridlines = v3d->gridlines / 2; - - if (v3d->gridlines < 3) return; - - /* use 'grid_scale' instead of 'v3d->grid' from now on */ - grid_scale = ED_view3d_grid_scale(scene, v3d, grid_unit); - grid = gridlines * grid_scale; - - if (!write_depth) - glDepthMask(GL_FALSE); - - UI_GetThemeColor3ubv(TH_GRID, col_grid); - - glLineWidth(1); - - /* draw the Y axis and/or grid lines */ - if (v3d->gridflag & V3D_SHOW_FLOOR) { - const int sublines = v3d->gridsubdiv; - float vert[4][3] = {{0.0f}}; - unsigned char col_bg[3]; - unsigned char col_grid_emphasise[3], col_grid_light[3]; - int a; - int prev_emphasise = -1; - - UI_GetThemeColor3ubv(TH_BACK, col_bg); - - /* emphasise division lines lighter instead of darker, if background is darker than grid */ - UI_GetColorPtrShade3ubv(col_grid, col_grid_light, 10); - UI_GetColorPtrShade3ubv(col_grid, col_grid_emphasise, - (((col_grid[0] + col_grid[1] + col_grid[2]) + 30) > - (col_bg[0] + col_bg[1] + col_bg[2])) ? 20 : -10); - - /* set fixed axis */ - vert[0][0] = vert[2][1] = grid; - vert[1][0] = vert[3][1] = -grid; - - glEnableClientState(GL_VERTEX_ARRAY); - glVertexPointer(3, GL_FLOAT, 0, vert); + wmWindow *win = CTX_wm_window(C); - for (a = -gridlines; a <= gridlines; a++) { - const float line = a * grid_scale; - const int is_emphasise = (a % sublines) == 0; + if ((scene->r.scemode & R_MULTIVIEW) == 0) + return false; - if (is_emphasise != prev_emphasise) { - glColor3ubv(is_emphasise ? col_grid_emphasise : col_grid_light); - prev_emphasise = is_emphasise; - } + if (WM_stereo3d_enabled(win, true) == false) + return false; - /* set variable axis */ - vert[0][1] = vert[1][1] = vert[2][0] = vert[3][0] = line; + if ((v3d->camera == NULL) || (v3d->camera->type != OB_CAMERA) || rv3d->persp != RV3D_CAMOB) + return false; - glDrawArrays(GL_LINES, 0, 4); - } + if (scene->r.views_format & SCE_VIEWS_FORMAT_MULTIVIEW) { + if (v3d->stereo3d_camera == STEREO_MONO_ID) + return false; - glDisableClientState(GL_VERTEX_ARRAY); - } - - /* draw the Z axis line */ - /* check for the 'show Z axis' preference */ - if (v3d->gridflag & (V3D_SHOW_X | V3D_SHOW_Y | V3D_SHOW_Z)) { - glBegin(GL_LINES); - int axis; - for (axis = 0; axis < 3; axis++) { - if (v3d->gridflag & (V3D_SHOW_X << axis)) { - float vert[3]; - unsigned char tcol[3]; - - UI_make_axis_color(col_grid, tcol, 'X' + axis); - glColor3ubv(tcol); - - zero_v3(vert); - vert[axis] = grid; - glVertex3fv(vert); - vert[axis] = -grid; - glVertex3fv(vert); - } - } - glEnd(); + return BKE_scene_multiview_is_stereo3d(&scene->r); } - - glDepthMask(GL_TRUE); -} - -static void drawcursor(Scene *scene, ARegion *ar, View3D *v3d) -{ - int co[2]; - - /* we don't want the clipping for cursor */ - if (ED_view3d_project_int_global(ar, ED_view3d_cursor3d_get(scene, v3d), co, V3D_PROJ_TEST_NOP) == V3D_PROJ_RET_OK) { - const float f5 = 0.25f * U.widget_unit; - const float f10 = 0.5f * U.widget_unit; - const float f20 = U.widget_unit; - - glLineWidth(1); - setlinestyle(0); - cpack(0xFF); - circ((float)co[0], (float)co[1], f10); - setlinestyle(4); - cpack(0xFFFFFF); - circ((float)co[0], (float)co[1], f10); - setlinestyle(0); - - UI_ThemeColor(TH_VIEW_OVERLAY); - sdrawline(co[0] - f20, co[1], co[0] - f5, co[1]); - sdrawline(co[0] + f5, co[1], co[0] + f20, co[1]); - sdrawline(co[0], co[1] - f20, co[0], co[1] - f5); - sdrawline(co[0], co[1] + f5, co[0], co[1] + f20); - } + return true; } -/* Draw a live substitute of the view icon, which is always shown - * colors copied from transform_manipulator.c, we should keep these matching. */ -static void draw_view_axis(RegionView3D *rv3d, rcti *rect) +/* setup the view and win matrices for the multiview cameras + * + * unlike view3d_stereo3d_setup_offscreen, when view3d_stereo3d_setup is called + * we have no winmatrix (i.e., projection matrix) defined at that time. + * Since the camera and the camera shift are needed for the winmat calculation + * we do a small hack to replace it temporarily so we don't need to change the + * view3d)main_region_setup_view() code to account for that. + */ +static void view3d_stereo3d_setup(Scene *scene, View3D *v3d, ARegion *ar) { - const float k = U.rvisize * U.pixelsize; /* axis size */ - const float toll = 0.5; /* used to see when view is quasi-orthogonal */ - float startx = k + 1.0f; /* axis center in screen coordinates, x=y */ - float starty = k + 1.0f; - float ydisp = 0.0; /* vertical displacement to allow obj info text */ - int bright = - 20 * (10 - U.rvibright); /* axis alpha offset (rvibright has range 0-10) */ - float vec[3]; - float dx, dy; + bool is_left; + const char *names[2] = { STEREO_LEFT_NAME, STEREO_RIGHT_NAME }; + const char *viewname; - int axis_order[3] = {0, 1, 2}; - int axis_i; + /* show only left or right camera */ + if (v3d->stereo3d_camera != STEREO_3D_ID) + v3d->multiview_eye = v3d->stereo3d_camera; - startx += rect->xmin; - starty += rect->ymin; + is_left = v3d->multiview_eye == STEREO_LEFT_ID; + viewname = names[is_left ? STEREO_LEFT_ID : STEREO_RIGHT_ID]; - axis_sort_v3(rv3d->viewinv[2], axis_order); + /* update the viewport matrices with the new camera */ + if (scene->r.views_format == SCE_VIEWS_FORMAT_STEREO_3D) { + Camera *data; + float viewmat[4][4]; + float shiftx; - /* thickness of lines is proportional to k */ - glLineWidth(2); + data = (Camera *)v3d->camera->data; + shiftx = data->shiftx; - glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + BLI_lock_thread(LOCK_VIEW3D); + data->shiftx = BKE_camera_multiview_shift_x(&scene->r, v3d->camera, viewname); - for (axis_i = 0; axis_i < 3; axis_i++) { - int i = axis_order[axis_i]; - const char axis_text[2] = {'x' + i, '\0'}; + BKE_camera_multiview_view_matrix(&scene->r, v3d->camera, is_left, viewmat); + view3d_main_region_setup_view(scene, v3d, ar, viewmat, NULL); - zero_v3(vec); - vec[i] = 1.0f; - mul_qt_v3(rv3d->viewquat, vec); - dx = vec[0] * k; - dy = vec[1] * k; + data->shiftx = shiftx; + BLI_unlock_thread(LOCK_VIEW3D); + } + else { /* SCE_VIEWS_FORMAT_MULTIVIEW */ + float viewmat[4][4]; + Object *view_ob = v3d->camera; + Object *camera = BKE_camera_multiview_render(scene, v3d->camera, viewname); - UI_ThemeColorShadeAlpha(TH_AXIS_X + i, 0, bright); - glBegin(GL_LINES); - glVertex2f(startx, starty + ydisp); - glVertex2f(startx + dx, starty + dy + ydisp); - glEnd(); + BLI_lock_thread(LOCK_VIEW3D); + v3d->camera = camera; - if (fabsf(dx) > toll || fabsf(dy) > toll) { - BLF_draw_default_ascii(startx + dx + 2, starty + dy + ydisp + 2, 0.0f, axis_text, 1); + BKE_camera_multiview_view_matrix(&scene->r, camera, false, viewmat); + view3d_main_region_setup_view(scene, v3d, ar, viewmat, NULL); - /* BLF_draw_default disables blending */ - glEnable(GL_BLEND); - } + v3d->camera = view_ob; + BLI_unlock_thread(LOCK_VIEW3D); } - - glDisable(GL_BLEND); } -#ifdef WITH_INPUT_NDOF -/* draw center and axis of rotation for ongoing 3D mouse navigation */ -static void draw_rotation_guide(RegionView3D *rv3d) -{ - float o[3]; /* center of rotation */ - float end[3]; /* endpoints for drawing */ +/* ******************** debug ***************** */ - float color[4] = {0.0f, 0.4235f, 1.0f, 1.0f}; /* bright blue so it matches device LEDs */ +#define VIEW3D_DRAW_DEBUG 1 +/* TODO: expand scope of this flag so UI reflects the underlying code */ - negate_v3_v3(o, rv3d->ofs); +#if VIEW3D_DRAW_DEBUG - glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - glPointSize(5); - glEnable(GL_POINT_SMOOTH); - glDepthMask(0); /* don't overwrite zbuf */ - - if (rv3d->rot_angle != 0.0f) { - /* -- draw rotation axis -- */ - float scaled_axis[3]; - const float scale = rv3d->dist; - mul_v3_v3fl(scaled_axis, rv3d->rot_axis, scale); - - - glBegin(GL_LINE_STRIP); - color[3] = 0.0f; /* more transparent toward the ends */ - glColor4fv(color); - add_v3_v3v3(end, o, scaled_axis); - glVertex3fv(end); - -#if 0 - color[3] = 0.2f + fabsf(rv3d->rot_angle); /* modulate opacity with angle */ - /* ^^ neat idea, but angle is frame-rate dependent, so it's usually close to 0.2 */ -#endif +static void view3d_draw_debug_store_depth(ARegion *UNUSED(ar), DrawData *draw_data) +{ + GPUViewport *viewport = draw_data->viewport; + GLint viewport_size[4]; + glGetIntegerv(GL_VIEWPORT, viewport_size); - color[3] = 0.5f; /* more opaque toward the center */ - glColor4fv(color); - glVertex3fv(o); + const int x = viewport_size[0]; + const int y = viewport_size[1]; + const int w = viewport_size[2]; + const int h = viewport_size[3]; - color[3] = 0.0f; - glColor4fv(color); - sub_v3_v3v3(end, o, scaled_axis); - glVertex3fv(end); - glEnd(); - - /* -- draw ring around rotation center -- */ + if (GPU_viewport_debug_depth_is_valid(viewport)) { + if ((GPU_viewport_debug_depth_width(viewport) != w) || + (GPU_viewport_debug_depth_height(viewport) != h)) { -#define ROT_AXIS_DETAIL 13 - - const float s = 0.05f * scale; - const float step = 2.0f * (float)(M_PI / ROT_AXIS_DETAIL); - float angle; - int i; - - float q[4]; /* rotate ring so it's perpendicular to axis */ - const int upright = fabsf(rv3d->rot_axis[2]) >= 0.95f; - if (!upright) { - const float up[3] = {0.0f, 0.0f, 1.0f}; - float vis_angle, vis_axis[3]; - - cross_v3_v3v3(vis_axis, up, rv3d->rot_axis); - vis_angle = acosf(dot_v3v3(up, rv3d->rot_axis)); - axis_angle_to_quat(q, vis_axis, vis_angle); - } - - color[3] = 0.25f; /* somewhat faint */ - glColor4fv(color); - glBegin(GL_LINE_LOOP); - for (i = 0, angle = 0.0f; i < ROT_AXIS_DETAIL; ++i, angle += step) { - float p[3] = {s * cosf(angle), s * sinf(angle), 0.0f}; - - if (!upright) { - mul_qt_v3(q, p); - } - - add_v3_v3(p, o); - glVertex3fv(p); - } - glEnd(); - -#undef ROT_AXIS_DETAIL + GPU_viewport_debug_depth_free(viewport); } - - color[3] = 1.0f; /* solid dot */ } - else - color[3] = 0.5f; /* see-through dot */ - /* -- draw rotation center -- */ - glColor4fv(color); - glBegin(GL_POINTS); - glVertex3fv(o); - glEnd(); - -#if 0 - /* find screen coordinates for rotation center, then draw pretty icon */ - mul_m4_v3(rv3d->persinv, rot_center); - UI_icon_draw(rot_center[0], rot_center[1], ICON_NDOF_TURN); - /* ^^ just playing around, does not work */ -#endif - - glDisable(GL_BLEND); - glDisable(GL_POINT_SMOOTH); - glDepthMask(1); -} -#endif /* WITH_INPUT_NDOF */ - -static void draw_view_icon(RegionView3D *rv3d, rcti *rect) -{ - BIFIconID icon; - - if (ELEM(rv3d->view, RV3D_VIEW_TOP, RV3D_VIEW_BOTTOM)) - icon = ICON_AXIS_TOP; - else if (ELEM(rv3d->view, RV3D_VIEW_FRONT, RV3D_VIEW_BACK)) - icon = ICON_AXIS_FRONT; - else if (ELEM(rv3d->view, RV3D_VIEW_RIGHT, RV3D_VIEW_LEFT)) - icon = ICON_AXIS_SIDE; - else return; - - glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - - UI_icon_draw(5.0 + rect->xmin, 5.0 + rect->ymin, icon); - - glDisable(GL_BLEND); -} - -static const char *view3d_get_name(View3D *v3d, RegionView3D *rv3d) -{ - const char *name = NULL; - - switch (rv3d->view) { - case RV3D_VIEW_FRONT: - if (rv3d->persp == RV3D_ORTHO) name = IFACE_("Front Ortho"); - else name = IFACE_("Front Persp"); - break; - case RV3D_VIEW_BACK: - if (rv3d->persp == RV3D_ORTHO) name = IFACE_("Back Ortho"); - else name = IFACE_("Back Persp"); - break; - case RV3D_VIEW_TOP: - if (rv3d->persp == RV3D_ORTHO) name = IFACE_("Top Ortho"); - else name = IFACE_("Top Persp"); - break; - case RV3D_VIEW_BOTTOM: - if (rv3d->persp == RV3D_ORTHO) name = IFACE_("Bottom Ortho"); - else name = IFACE_("Bottom Persp"); - break; - case RV3D_VIEW_RIGHT: - if (rv3d->persp == RV3D_ORTHO) name = IFACE_("Right Ortho"); - else name = IFACE_("Right Persp"); - break; - case RV3D_VIEW_LEFT: - if (rv3d->persp == RV3D_ORTHO) name = IFACE_("Left Ortho"); - else name = IFACE_("Left Persp"); - break; - - default: - if (rv3d->persp == RV3D_CAMOB) { - if ((v3d->camera) && (v3d->camera->type == OB_CAMERA)) { - Camera *cam; - cam = v3d->camera->data; - if (cam->type == CAM_PERSP) { - name = IFACE_("Camera Persp"); - } - else if (cam->type == CAM_ORTHO) { - name = IFACE_("Camera Ortho"); - } - else { - BLI_assert(cam->type == CAM_PANO); - name = IFACE_("Camera Pano"); - } - } - else { - name = IFACE_("Object as Camera"); - } - } - else { - name = (rv3d->persp == RV3D_ORTHO) ? IFACE_("User Ortho") : IFACE_("User Persp"); - } - break; + if (!GPU_viewport_debug_depth_is_valid(viewport)) { + char error[256]; + if (!GPU_viewport_debug_depth_create(viewport, w, h, error)) { + fprintf(stderr, "Failed to create depth buffer for debug: %s\n", error); + return; + } } - - return name; + + GPU_viewport_debug_depth_store(viewport, x, y); } -static void draw_viewport_name(ARegion *ar, View3D *v3d, rcti *rect) +static void view3d_draw_debug_post_solid(const bContext *C, ARegion *ar, DrawData *draw_data) { - RegionView3D *rv3d = ar->regiondata; - const char *name = view3d_get_name(v3d, rv3d); - /* increase size for unicode languages (Chinese in utf-8...) */ -#ifdef WITH_INTERNATIONAL - char tmpstr[96]; -#else - char tmpstr[32]; -#endif + View3D *v3d = CTX_wm_view3d(C); - if (v3d->localvd) { - BLI_snprintf(tmpstr, sizeof(tmpstr), IFACE_("%s (Local)"), name); - name = tmpstr; + if ((v3d->tmp_compat_flag & V3D_DEBUG_SHOW_SCENE_DEPTH) != 0) { + view3d_draw_debug_store_depth(ar, draw_data); } - - UI_ThemeColor(TH_TEXT_HI); -#ifdef WITH_INTERNATIONAL - BLF_draw_default(U.widget_unit + rect->xmin, rect->ymax - U.widget_unit, 0.0f, name, sizeof(tmpstr)); -#else - BLF_draw_default_ascii(U.widget_unit + rect->xmin, rect->ymax - U.widget_unit, 0.0f, name, sizeof(tmpstr)); -#endif } -/* draw info beside axes in bottom left-corner: - * framenum, object name, bone name (if available), marker name (if available) - */ - -static void draw_selected_name(Scene *scene, Object *ob, rcti *rect) +static void view3d_draw_debug(const bContext *C, ARegion *ar, DrawData *draw_data) { - const int cfra = CFRA; - const char *msg_pin = " (Pinned)"; - const char *msg_sep = " : "; - - char info[300]; - const char *markern; - char *s = info; - short offset = 1.5f * UI_UNIT_X + rect->xmin; - - s += sprintf(s, "(%d)", cfra); - - /* - * info can contain: - * - a frame (7 + 2) - * - 3 object names (MAX_NAME) - * - 2 BREAD_CRUMB_SEPARATORs (6) - * - a SHAPE_KEY_PINNED marker and a trailing '\0' (9+1) - translated, so give some room! - * - a marker name (MAX_NAME + 3) - */ - - /* get name of marker on current frame (if available) */ - markern = BKE_scene_find_marker_name(scene, cfra); - - /* check if there is an object */ - if (ob) { - *s++ = ' '; - s += BLI_strcpy_rlen(s, ob->id.name + 2); - - /* name(s) to display depends on type of object */ - if (ob->type == OB_ARMATURE) { - bArmature *arm = ob->data; - - /* show name of active bone too (if possible) */ - if (arm->edbo) { - if (arm->act_edbone) { - s += BLI_strcpy_rlen(s, msg_sep); - s += BLI_strcpy_rlen(s, arm->act_edbone->name); - } - } - else if (ob->mode & OB_MODE_POSE) { - if (arm->act_bone) { - - if (arm->act_bone->layer & arm->layer) { - s += BLI_strcpy_rlen(s, msg_sep); - s += BLI_strcpy_rlen(s, arm->act_bone->name); - } - } - } - } - else if (ELEM(ob->type, OB_MESH, OB_LATTICE, OB_CURVE)) { - Key *key = NULL; - KeyBlock *kb = NULL; - - /* try to display active bone and active shapekey too (if they exist) */ + View3D *v3d = CTX_wm_view3d(C); - if (ob->type == OB_MESH && ob->mode & OB_MODE_WEIGHT_PAINT) { - Object *armobj = BKE_object_pose_armature_get(ob); - if (armobj && armobj->mode & OB_MODE_POSE) { - bArmature *arm = armobj->data; - if (arm->act_bone) { - if (arm->act_bone->layer & arm->layer) { - s += BLI_strcpy_rlen(s, msg_sep); - s += BLI_strcpy_rlen(s, arm->act_bone->name); - } - } - } - } + if ((v3d->tmp_compat_flag & V3D_DEBUG_SHOW_COMBINED_DEPTH) != 0) { + /* store */ + view3d_draw_debug_store_depth(ar, draw_data); + } - key = BKE_key_from_object(ob); - if (key) { - kb = BLI_findlink(&key->block, ob->shapenr - 1); - if (kb) { - s += BLI_strcpy_rlen(s, msg_sep); - s += BLI_strcpy_rlen(s, kb->name); - if (ob->shapeflag & OB_SHAPE_LOCK) { - s += BLI_strcpy_rlen(s, IFACE_(msg_pin)); - } - } - } + if (((v3d->tmp_compat_flag & V3D_DEBUG_SHOW_SCENE_DEPTH) != 0) || + ((v3d->tmp_compat_flag & V3D_DEBUG_SHOW_COMBINED_DEPTH) != 0)) + { + /* draw */ + if (GPU_viewport_debug_depth_is_valid(draw_data->viewport)) { + GPU_viewport_debug_depth_draw(draw_data->viewport, v3d->debug.znear, v3d->debug.zfar); } - - /* color depends on whether there is a keyframe */ - if (id_frame_has_keyframe((ID *)ob, /* BKE_scene_frame_get(scene) */ (float)cfra, ANIMFILTER_KEYS_LOCAL)) - UI_ThemeColor(TH_TIME_KEYFRAME); - else if (ED_gpencil_has_keyframe_v3d(scene, ob, cfra)) - UI_ThemeColor(TH_TIME_GP_KEYFRAME); - else - UI_ThemeColor(TH_TEXT_HI); } else { - /* no object */ - if (ED_gpencil_has_keyframe_v3d(scene, NULL, cfra)) - UI_ThemeColor(TH_TIME_GP_KEYFRAME); - else - UI_ThemeColor(TH_TEXT_HI); + /* cleanup */ + GPU_viewport_debug_depth_free(draw_data->viewport); } +} - if (markern) { - s += sprintf(s, " <%s>", markern); - } - - if (U.uiflag & USER_SHOW_ROTVIEWICON) - offset = U.widget_unit + (U.rvisize * 2) + rect->xmin; +#endif /* VIEW3D_DRAW_DEBUG */ - BLF_draw_default(offset, 0.5f * U.widget_unit, 0.0f, info, sizeof(info)); -} +/* ******************** view border ***************** */ static void view3d_camera_border( const Scene *scene, const ARegion *ar, const View3D *v3d, const RegionView3D *rv3d, @@ -1021,7 +414,7 @@ void ED_view3d_calc_camera_border( view3d_camera_border(scene, ar, v3d, rv3d, r_viewborder, no_shift, false); } -static void drawviewborder_grid3(float x1, float x2, float y1, float y2, float fac) +static void drawviewborder_grid3(unsigned pos, float x1, float x2, float y1, float y2, float fac) { float x3, y3, x4, y4; @@ -1030,29 +423,29 @@ static void drawviewborder_grid3(float x1, float x2, float y1, float y2, float f x4 = x1 + (1.0f - fac) * (x2 - x1); y4 = y1 + (1.0f - fac) * (y2 - y1); - glBegin(GL_LINES); - glVertex2f(x1, y3); - glVertex2f(x2, y3); + immBegin(GL_LINES, 8); + immVertex2f(pos, x1, y3); + immVertex2f(pos, x2, y3); - glVertex2f(x1, y4); - glVertex2f(x2, y4); + immVertex2f(pos, x1, y4); + immVertex2f(pos, x2, y4); - glVertex2f(x3, y1); - glVertex2f(x3, y2); + immVertex2f(pos, x3, y1); + immVertex2f(pos, x3, y2); - glVertex2f(x4, y1); - glVertex2f(x4, y2); - glEnd(); + immVertex2f(pos, x4, y1); + immVertex2f(pos, x4, y2); + immEnd(); } /* harmonious triangle */ -static void drawviewborder_triangle(float x1, float x2, float y1, float y2, const char golden, const char dir) +static void drawviewborder_triangle(unsigned pos, float x1, float x2, float y1, float y2, const char golden, const char dir) { float ofs; float w = x2 - x1; float h = y2 - y1; - glBegin(GL_LINES); + immBegin(GL_LINES, 6); if (w > h) { if (golden) { ofs = w * (1.0f - (1.0f / 1.61803399f)); @@ -1062,14 +455,14 @@ static void drawviewborder_triangle(float x1, float x2, float y1, float y2, cons } if (dir == 'B') SWAP(float, y1, y2); - glVertex2f(x1, y1); - glVertex2f(x2, y2); + immVertex2f(pos, x1, y1); + immVertex2f(pos, x2, y2); - glVertex2f(x2, y1); - glVertex2f(x1 + (w - ofs), y2); + immVertex2f(pos, x2, y1); + immVertex2f(pos, x1 + (w - ofs), y2); - glVertex2f(x1, y2); - glVertex2f(x1 + ofs, y1); + immVertex2f(pos, x1, y2); + immVertex2f(pos, x1 + ofs, y1); } else { if (golden) { @@ -1080,16 +473,16 @@ static void drawviewborder_triangle(float x1, float x2, float y1, float y2, cons } if (dir == 'B') SWAP(float, x1, x2); - glVertex2f(x1, y1); - glVertex2f(x2, y2); + immVertex2f(pos, x1, y1); + immVertex2f(pos, x2, y2); - glVertex2f(x2, y1); - glVertex2f(x1, y1 + ofs); + immVertex2f(pos, x2, y1); + immVertex2f(pos, x1, y1 + ofs); - glVertex2f(x1, y2); - glVertex2f(x2, y1 + (h - ofs)); + immVertex2f(pos, x1, y2); + immVertex2f(pos, x2, y1 + (h - ofs)); } - glEnd(); + immEnd(); } static void drawviewborder(Scene *scene, ARegion *ar, View3D *v3d) @@ -1105,14 +498,14 @@ static void drawviewborder(Scene *scene, ARegion *ar, View3D *v3d) return; if (v3d->camera->type == OB_CAMERA) ca = v3d->camera->data; - + ED_view3d_calc_camera_border(scene, ar, v3d, rv3d, &viewborder, false); /* the offsets */ x1 = viewborder.xmin; y1 = viewborder.ymin; x2 = viewborder.xmax; y2 = viewborder.ymax; - + glLineWidth(1.0f); /* apply offsets so the real 3D camera shows through */ @@ -1126,43 +519,47 @@ static void drawviewborder(Scene *scene, ARegion *ar, View3D *v3d) y1i = (int)(y1 - 1.0001f); x2i = (int)(x2 + (1.0f - 0.0001f)); y2i = (int)(y2 + (1.0f - 0.0001f)); - + + /* use the same program for everything */ + unsigned pos = add_attrib(immVertexFormat(), "pos", COMP_F32, 2, KEEP_FLOAT); + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + /* passepartout, specified in camera edit buttons */ if (ca && (ca->flag & CAM_SHOWPASSEPARTOUT) && ca->passepartalpha > 0.000001f) { const float winx = (ar->winx + 1); const float winy = (ar->winy + 1); - if (ca->passepartalpha == 1.0f) { - glColor3f(0, 0, 0); - } - else { + float alpha = 1.0f; + + if (ca->passepartalpha != 1.0f) { glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glEnable(GL_BLEND); - glColor4f(0, 0, 0, ca->passepartalpha); + alpha = ca->passepartalpha; } + immUniformColor4f(0.0f, 0.0f, 0.0f, alpha); + if (x1i > 0.0f) - glRectf(0.0, winy, x1i, 0.0); + immRectf(pos, 0.0f, winy, x1i, 0.0f); if (x2i < winx) - glRectf(x2i, winy, winx, 0.0); + immRectf(pos, x2i, winy, winx, 0.0f); if (y2i < winy) - glRectf(x1i, winy, x2i, y2i); + immRectf(pos, x1i, winy, x2i, y2i); if (y2i > 0.0f) - glRectf(x1i, y1i, x2i, 0.0); - + immRectf(pos, x1i, y1i, x2i, 0.0f); + glDisable(GL_BLEND); } setlinestyle(0); - UI_ThemeColor(TH_BACK); - - fdrawbox(x1i, y1i, x2i, y2i); + immUniformThemeColor(TH_BACK); + imm_draw_line_box(pos, x1i, y1i, x2i, y2i); #ifdef VIEW3D_CAMERA_BORDER_HACK if (view3d_camera_border_hack_test == true) { - glColor3ubv(view3d_camera_border_hack_col); - fdrawbox(x1i + 1, y1i + 1, x2i - 1, y2i - 1); + immUniformColor3ubv(view3d_camera_border_hack_col); + imm_draw_line_box(pos, x1i + 1, y1i + 1, x2i - 1, y2i - 1); view3d_camera_border_hack_test = false; } #endif @@ -1171,12 +568,12 @@ static void drawviewborder(Scene *scene, ARegion *ar, View3D *v3d) /* outer line not to confuse with object selecton */ if (v3d->flag2 & V3D_LOCK_CAMERA) { - UI_ThemeColor(TH_REDALERT); - fdrawbox(x1i - 1, y1i - 1, x2i + 1, y2i + 1); + immUniformThemeColor(TH_REDALERT); + imm_draw_line_box(pos, x1i - 1, y1i - 1, x2i + 1, y2i + 1); } - UI_ThemeColor(TH_VIEW_OVERLAY); - fdrawbox(x1i, y1i, x2i, y2i); + immUniformThemeColor(TH_VIEW_OVERLAY); + imm_draw_line_box(pos, x1i, y1i, x2i, y2i); /* border */ if (scene->r.mode & R_BORDER) { @@ -1187,84 +584,90 @@ static void drawviewborder(Scene *scene, ARegion *ar, View3D *v3d) x4 = floorf(x1 + (scene->r.border.xmax * (x2 - x1))) + (U.pixelsize - 1); y4 = floorf(y1 + (scene->r.border.ymax * (y2 - y1))) + (U.pixelsize - 1); - cpack(0x4040FF); - sdrawbox(x3, y3, x4, y4); + imm_cpack(0x4040FF); + imm_draw_line_box(pos, x3, y3, x4, y4); } + immUnbindProgram(); /* safety border */ if (ca) { + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); if (ca->dtx & CAM_DTX_CENTER) { float x3, y3; - UI_ThemeColorBlendShade(TH_VIEW_OVERLAY, TH_BACK, 0.25, 0); - x3 = x1 + 0.5f * (x2 - x1); y3 = y1 + 0.5f * (y2 - y1); - glBegin(GL_LINES); - glVertex2f(x1, y3); - glVertex2f(x2, y3); + immUniformThemeColorBlendShade(TH_VIEW_OVERLAY, TH_BACK, 0.25f, 0); + immBegin(GL_LINES, 4); - glVertex2f(x3, y1); - glVertex2f(x3, y2); - glEnd(); + immVertex2f(pos, x1, y3); + immVertex2f(pos, x2, y3); + + immVertex2f(pos, x3, y1); + immVertex2f(pos, x3, y2); + + immEnd(); } if (ca->dtx & CAM_DTX_CENTER_DIAG) { - UI_ThemeColorBlendShade(TH_VIEW_OVERLAY, TH_BACK, 0.25, 0); - glBegin(GL_LINES); - glVertex2f(x1, y1); - glVertex2f(x2, y2); + immUniformThemeColorBlendShade(TH_VIEW_OVERLAY, TH_BACK, 0.25f, 0); + immBegin(GL_LINES, 4); - glVertex2f(x1, y2); - glVertex2f(x2, y1); - glEnd(); + immVertex2f(pos, x1, y1); + immVertex2f(pos, x2, y2); + + immVertex2f(pos, x1, y2); + immVertex2f(pos, x2, y1); + + immEnd(); } if (ca->dtx & CAM_DTX_THIRDS) { - UI_ThemeColorBlendShade(TH_VIEW_OVERLAY, TH_BACK, 0.25, 0); - drawviewborder_grid3(x1, x2, y1, y2, 1.0f / 3.0f); + immUniformThemeColorBlendShade(TH_VIEW_OVERLAY, TH_BACK, 0.25f, 0); + drawviewborder_grid3(pos, x1, x2, y1, y2, 1.0f / 3.0f); } if (ca->dtx & CAM_DTX_GOLDEN) { - UI_ThemeColorBlendShade(TH_VIEW_OVERLAY, TH_BACK, 0.25, 0); - drawviewborder_grid3(x1, x2, y1, y2, 1.0f - (1.0f / 1.61803399f)); + immUniformThemeColorBlendShade(TH_VIEW_OVERLAY, TH_BACK, 0.25f, 0); + drawviewborder_grid3(pos, x1, x2, y1, y2, 1.0f - (1.0f / 1.61803399f)); } if (ca->dtx & CAM_DTX_GOLDEN_TRI_A) { - UI_ThemeColorBlendShade(TH_VIEW_OVERLAY, TH_BACK, 0.25, 0); - drawviewborder_triangle(x1, x2, y1, y2, 0, 'A'); + immUniformThemeColorBlendShade(TH_VIEW_OVERLAY, TH_BACK, 0.25f, 0); + drawviewborder_triangle(pos, x1, x2, y1, y2, 0, 'A'); } if (ca->dtx & CAM_DTX_GOLDEN_TRI_B) { - UI_ThemeColorBlendShade(TH_VIEW_OVERLAY, TH_BACK, 0.25, 0); - drawviewborder_triangle(x1, x2, y1, y2, 0, 'B'); + immUniformThemeColorBlendShade(TH_VIEW_OVERLAY, TH_BACK, 0.25f, 0); + drawviewborder_triangle(pos, x1, x2, y1, y2, 0, 'B'); } if (ca->dtx & CAM_DTX_HARMONY_TRI_A) { - UI_ThemeColorBlendShade(TH_VIEW_OVERLAY, TH_BACK, 0.25, 0); - drawviewborder_triangle(x1, x2, y1, y2, 1, 'A'); + immUniformThemeColorBlendShade(TH_VIEW_OVERLAY, TH_BACK, 0.25f, 0); + drawviewborder_triangle(pos, x1, x2, y1, y2, 1, 'A'); } if (ca->dtx & CAM_DTX_HARMONY_TRI_B) { - UI_ThemeColorBlendShade(TH_VIEW_OVERLAY, TH_BACK, 0.25, 0); - drawviewborder_triangle(x1, x2, y1, y2, 1, 'B'); + immUniformThemeColorBlendShade(TH_VIEW_OVERLAY, TH_BACK, 0.25f, 0); + drawviewborder_triangle(pos, x1, x2, y1, y2, 1, 'B'); } if (ca->flag & CAM_SHOW_SAFE_MARGINS) { UI_draw_safe_areas( - x1, x2, y1, y2, + pos, x1, x2, y1, y2, scene->safe_areas.title, scene->safe_areas.action); if (ca->flag & CAM_SHOW_SAFE_CENTER) { UI_draw_safe_areas( - x1, x2, y1, y2, + pos, x1, x2, y1, y2, scene->safe_areas.title_center, scene->safe_areas.action_center); } } + immUnbindProgram(); if (ca->flag & CAM_SHOWSENSOR) { /* determine sensor fit, and get sensor x/y, for auto fit we @@ -1298,8 +701,9 @@ static void drawviewborder(Scene *scene, ARegion *ar, View3D *v3d) } /* draw */ - UI_ThemeColorShade(TH_VIEW_OVERLAY, 100); - UI_draw_roundbox_gl_mode(GL_LINE_LOOP, rect.xmin, rect.ymin, rect.xmax, rect.ymax, 2.0f); + float color[4]; + UI_GetThemeColorShade4fv(TH_VIEW_OVERLAY, 100, color); + UI_draw_roundbox_gl_mode(GL_LINE_LOOP, rect.xmin, rect.ymin, rect.xmax, rect.ymax, 2.0f, color); } } @@ -1307,1392 +711,757 @@ static void drawviewborder(Scene *scene, ARegion *ar, View3D *v3d) /* camera name - draw in highlighted text color */ if (ca && (ca->flag & CAM_SHOWNAME)) { - UI_ThemeColor(TH_TEXT_HI); + UI_FontThemeColor(BLF_default(), TH_TEXT_HI); BLF_draw_default( x1i, y1i - (0.7f * U.widget_unit), 0.0f, v3d->camera->id.name + 2, sizeof(v3d->camera->id.name) - 2); } + } -/* *********************** backdraw for selection *************** */ +static void drawrenderborder(ARegion *ar, View3D *v3d) +{ + /* use the same program for everything */ + unsigned pos = add_attrib(immVertexFormat(), "pos", COMP_F32, 2, KEEP_FLOAT); + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + + glLineWidth(1.0f); + setlinestyle(3); + imm_cpack(0x4040FF); -static void backdrawview3d(Scene *scene, wmWindow *win, ARegion *ar, View3D *v3d) + imm_draw_line_box( + pos, v3d->render_border.xmin * ar->winx, v3d->render_border.ymin * ar->winy, + v3d->render_border.xmax * ar->winx, v3d->render_border.ymax * ar->winy); + + setlinestyle(0); + + immUnbindProgram(); +} + +/* ******************** offline engine ***************** */ + +static bool view3d_draw_render_draw(const bContext *C, Scene *scene, + ARegion *ar, View3D *UNUSED(v3d), + bool clip_border, const rcti *border_rect) { RegionView3D *rv3d = ar->regiondata; - struct Base *base = scene->basact; - int multisample_enabled; + RenderEngineType *type; + GLint scissor[4]; - BLI_assert(ar->regiontype == RGN_TYPE_WINDOW); + /* create render engine */ + if (!rv3d->render_engine) { + RenderEngine *engine; - if (base && (base->object->mode & (OB_MODE_VERTEX_PAINT | OB_MODE_WEIGHT_PAINT) || - BKE_paint_select_face_test(base->object))) - { - /* do nothing */ - } - /* texture paint mode sampling */ - else if (base && (base->object->mode & OB_MODE_TEXTURE_PAINT) && - (v3d->drawtype > OB_WIRE)) - { - /* do nothing */ - } - else if ((base && (base->object->mode & OB_MODE_PARTICLE_EDIT)) && - V3D_IS_ZBUF(v3d)) - { - /* do nothing */ - } - else if (scene->obedit && - V3D_IS_ZBUF(v3d)) - { - /* do nothing */ - } - else { - v3d->flag &= ~V3D_INVALID_BACKBUF; - return; - } + type = RE_engines_find(scene->r.engine); - if (!(v3d->flag & V3D_INVALID_BACKBUF)) - return; + if (!(type->view_update && type->view_draw)) + return false; -#if 0 - if (test) { - if (qtest()) { - addafterqueue(ar->win, BACKBUFDRAW, 1); - return; - } - } -#endif + engine = RE_engine_create_ex(type, true); - if (v3d->drawtype > OB_WIRE) v3d->zbuf = true; - - /* dithering and AA break color coding, so disable */ - glDisable(GL_DITHER); - - multisample_enabled = glIsEnabled(GL_MULTISAMPLE); - if (multisample_enabled) - glDisable(GL_MULTISAMPLE); - - if (win->multisamples != USER_MULTISAMPLE_NONE) { - /* for multisample we use an offscreen FBO. multisample drawing can fail - * with color coded selection drawing, and reading back depths from such - * a buffer can also cause a few seconds freeze on OS X / NVidia. */ - int w = BLI_rcti_size_x(&ar->winrct); - int h = BLI_rcti_size_y(&ar->winrct); - char error[256]; + engine->tile_x = scene->r.tilex; + engine->tile_y = scene->r.tiley; - if (rv3d->gpuoffscreen) { - if (GPU_offscreen_width(rv3d->gpuoffscreen) != w || - GPU_offscreen_height(rv3d->gpuoffscreen) != h) - { - GPU_offscreen_free(rv3d->gpuoffscreen); - rv3d->gpuoffscreen = NULL; - } - } + type->view_update(engine, C); + + rv3d->render_engine = engine; + } - if (!rv3d->gpuoffscreen) { - rv3d->gpuoffscreen = GPU_offscreen_create(w, h, 0, error); + /* background draw */ + glMatrixMode(GL_PROJECTION); + glPushMatrix(); + glMatrixMode(GL_MODELVIEW); + glPushMatrix(); + ED_region_pixelspace(ar); - if (!rv3d->gpuoffscreen) - fprintf(stderr, "Failed to create offscreen selection buffer for multisample: %s\n", error); + if (clip_border) { + /* for border draw, we only need to clear a subset of the 3d view */ + if (border_rect->xmax > border_rect->xmin && border_rect->ymax > border_rect->ymin) { + glGetIntegerv(GL_SCISSOR_BOX, scissor); + glScissor(border_rect->xmin, border_rect->ymin, + BLI_rcti_size_x(border_rect), BLI_rcti_size_y(border_rect)); + } + else { + return false; } } - if (rv3d->gpuoffscreen) - GPU_offscreen_bind(rv3d->gpuoffscreen, true); - else - glScissor(ar->winrct.xmin, ar->winrct.ymin, BLI_rcti_size_x(&ar->winrct), BLI_rcti_size_y(&ar->winrct)); + glClearColor(0.0f, 0.0f, 0.0f, 0.0f); + /* don't change depth buffer */ + glClear(GL_COLOR_BUFFER_BIT); /* is this necessary? -- merwin */ - glClearColor(0.0, 0.0, 0.0, 0.0); - if (v3d->zbuf) { - glEnable(GL_DEPTH_TEST); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - } - else { - glClear(GL_COLOR_BUFFER_BIT); - glDisable(GL_DEPTH_TEST); - } - - if (rv3d->rflag & RV3D_CLIPPING) - ED_view3d_clipping_set(rv3d); - - G.f |= G_BACKBUFSEL; - - if (base && (base->lay & v3d->lay)) - draw_object_backbufsel(scene, v3d, rv3d, base->object); - - if (rv3d->gpuoffscreen) - GPU_offscreen_unbind(rv3d->gpuoffscreen, true); - else - ar->swap = 0; /* mark invalid backbuf for wm draw */ + /* render result draw */ + type = rv3d->render_engine->type; + type->view_draw(rv3d->render_engine, C); - v3d->flag &= ~V3D_INVALID_BACKBUF; + if (clip_border) { + /* restore scissor as it was before */ + glScissor(scissor[0], scissor[1], scissor[2], scissor[3]); + } - G.f &= ~G_BACKBUFSEL; - v3d->zbuf = false; - glDisable(GL_DEPTH_TEST); - glEnable(GL_DITHER); - if (multisample_enabled) - glEnable(GL_MULTISAMPLE); + glMatrixMode(GL_PROJECTION); + glPopMatrix(); + glMatrixMode(GL_MODELVIEW); + glPopMatrix(); - if (rv3d->rflag & RV3D_CLIPPING) - ED_view3d_clipping_disable(); + return true; } -void view3d_opengl_read_pixels(ARegion *ar, int x, int y, int w, int h, int format, int type, void *data) +/* ******************** background plates ***************** */ + +static void view3d_draw_background_gradient(void) { - RegionView3D *rv3d = ar->regiondata; + gpuMatrixBegin3D(); /* TODO: finish 2D API */ - if (rv3d->gpuoffscreen) { - GPU_offscreen_bind(rv3d->gpuoffscreen, true); - glReadBuffer(GL_COLOR_ATTACHMENT0_EXT); - glReadPixels(x, y, w, h, format, type, data); - GPU_offscreen_unbind(rv3d->gpuoffscreen, true); - } - else { - glReadPixels(ar->winrct.xmin + x, ar->winrct.ymin + y, w, h, format, type, data); - } -} + glClear(GL_DEPTH_BUFFER_BIT); -/* XXX depth reading exception, for code not using gpu offscreen */ -static void view3d_opengl_read_Z_pixels(ARegion *ar, int x, int y, int w, int h, int format, int type, void *data) -{ + 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]; - glReadPixels(ar->winrct.xmin + x, ar->winrct.ymin + y, w, h, format, type, data); -} + immBindBuiltinProgram(GPU_SHADER_2D_SMOOTH_COLOR); -void ED_view3d_backbuf_validate(ViewContext *vc) -{ - if (vc->v3d->flag & V3D_INVALID_BACKBUF) - backdrawview3d(vc->scene, vc->win, vc->ar, vc->v3d); -} + UI_GetThemeColor3ubv(TH_LOW_GRAD, col_lo); + UI_GetThemeColor3ubv(TH_HIGH_GRAD, col_hi); -/** - * allow for small values [0.5 - 2.5], - * and large values, FLT_MAX by clamping by the area size - */ -int ED_view3d_backbuf_sample_size_clamp(ARegion *ar, const float dist) -{ - return (int)min_ff(ceilf(dist), (float)max_ii(ar->winx, ar->winx)); + 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(); } -/* samples a single pixel (copied from vpaint) */ -unsigned int ED_view3d_backbuf_sample(ViewContext *vc, int x, int y) +static void view3d_draw_background_none(void) { - unsigned int col; - - if (x >= vc->ar->winx || y >= vc->ar->winy) { - return 0; + if (UI_GetThemeValue(TH_SHOW_BACK_GRAD)) { + view3d_draw_background_gradient(); } - - ED_view3d_backbuf_validate(vc); - - view3d_opengl_read_pixels(vc->ar, x, y, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, &col); - glReadBuffer(GL_BACK); - - if (ENDIAN_ORDER == B_ENDIAN) { - BLI_endian_switch_uint32(&col); + else { + UI_ThemeClearColorAlpha(TH_HIGH_GRAD, 1.0f); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); } - - return GPU_select_to_index(col); } -/* reads full rect, converts indices */ -ImBuf *ED_view3d_backbuf_read(ViewContext *vc, int xmin, int ymin, int xmax, int ymax) +static void view3d_draw_background_world(Scene *scene, View3D *v3d, RegionView3D *rv3d) { - struct ImBuf *ibuf_clip; - /* clip */ - const rcti clip = { - max_ii(xmin, 0), min_ii(xmax, vc->ar->winx - 1), - max_ii(ymin, 0), min_ii(ymax, vc->ar->winy - 1)}; - const int size_clip[2] = { - BLI_rcti_size_x(&clip) + 1, - BLI_rcti_size_y(&clip) + 1}; - - if (UNLIKELY((clip.xmin > clip.xmax) || - (clip.ymin > clip.ymax))) - { - return NULL; - } + if (scene->world) { + GPUMaterial *gpumat = GPU_material_world(scene, scene->world); - ibuf_clip = IMB_allocImBuf(size_clip[0], size_clip[1], 32, IB_rect); + /* calculate full shader for background */ + GPU_material_bind(gpumat, 1, 1, 1.0f, false, rv3d->viewmat, rv3d->viewinv, rv3d->viewcamtexcofac, (v3d->scenelock != 0)); - ED_view3d_backbuf_validate(vc); + if (GPU_material_bound(gpumat)) { - view3d_opengl_read_pixels(vc->ar, clip.xmin, clip.ymin, size_clip[0], size_clip[1], GL_RGBA, GL_UNSIGNED_BYTE, ibuf_clip->rect); + glClear(GL_DEPTH_BUFFER_BIT); - glReadBuffer(GL_BACK); + /* TODO viewport (dfelinto): GPU_material_bind relies on immediate mode, + * we can't get rid of the following code without a bigger refactor + * or we dropping this functionality. */ - if (ENDIAN_ORDER == B_ENDIAN) { - IMB_convert_rgba_to_abgr(ibuf_clip); - } + glBegin(GL_TRIANGLE_STRIP); + glVertex2f(-1.0f, -1.0f); + glVertex2f(1.0f, -1.0f); + glVertex2f(-1.0f, 1.0f); + glVertex2f(1.0f, 1.0f); + glEnd(); - GPU_select_to_index_array(ibuf_clip->rect, size_clip[0] * size_clip[1]); - - if ((clip.xmin == xmin) && - (clip.xmax == xmax) && - (clip.ymin == ymin) && - (clip.ymax == ymax)) - { - return ibuf_clip; + GPU_material_unbind(gpumat); + } + else { + view3d_draw_background_none(); + } } else { - /* put clipped result into a non-clipped buffer */ - struct ImBuf *ibuf_full; - const int size[2] = { - (xmax - xmin + 1), - (ymax - ymin + 1)}; - - ibuf_full = IMB_allocImBuf(size[0], size[1], 32, IB_rect); - - IMB_rectcpy( - ibuf_full, ibuf_clip, - clip.xmin - xmin, clip.ymin - ymin, - 0, 0, - size_clip[0], size_clip[1]); - IMB_freeImBuf(ibuf_clip); - return ibuf_full; - } -} - -/* smart function to sample a rect spiralling outside, nice for backbuf selection */ -unsigned int ED_view3d_backbuf_sample_rect( - ViewContext *vc, const int mval[2], int size, - unsigned int min, unsigned int max, float *r_dist) -{ - struct ImBuf *buf; - const unsigned int *bufmin, *bufmax, *tbuf; - int minx, miny; - int a, b, rc, nr, amount, dirvec[4][2]; - unsigned int index = 0; - - amount = (size - 1) / 2; - - minx = mval[0] - (amount + 1); - miny = mval[1] - (amount + 1); - buf = ED_view3d_backbuf_read(vc, minx, miny, minx + size - 1, miny + size - 1); - if (!buf) return 0; - - rc = 0; - - dirvec[0][0] = 1; dirvec[0][1] = 0; - dirvec[1][0] = 0; dirvec[1][1] = -size; - dirvec[2][0] = -1; dirvec[2][1] = 0; - dirvec[3][0] = 0; dirvec[3][1] = size; - - bufmin = buf->rect; - tbuf = buf->rect; - bufmax = buf->rect + size * size; - tbuf += amount * size + amount; - - for (nr = 1; nr <= size; nr++) { - - for (a = 0; a < 2; a++) { - for (b = 0; b < nr; b++) { - if (*tbuf && *tbuf >= min && *tbuf < max) { - /* we got a hit */ - - /* get x,y pixel coords from the offset - * (manhatten distance in keeping with other screen-based selection) */ - *r_dist = (float)( - abs(((int)(tbuf - buf->rect) % size) - (size / 2)) + - abs(((int)(tbuf - buf->rect) / size) - (size / 2))); - - /* indices start at 1 here */ - index = (*tbuf - min) + 1; - goto exit; - } - - tbuf += (dirvec[rc][0] + dirvec[rc][1]); - - if (tbuf < bufmin || tbuf >= bufmax) { - goto exit; - } - } - rc++; - rc &= 3; - } + view3d_draw_background_none(); } - -exit: - IMB_freeImBuf(buf); - return index; } +/* ******************** solid plates ***************** */ -/* ************************************************************* */ - -static void view3d_stereo_bgpic_setup(Scene *scene, View3D *v3d, Image *ima, ImageUser *iuser) +/** + * Clear the buffer and draw the proper shader + */ +static void view3d_draw_background(const bContext *C) { - if (BKE_image_is_stereo(ima)) { - iuser->flag |= IMA_SHOW_STEREO; + Scene *scene = CTX_data_scene(C); + View3D *v3d = CTX_wm_view3d(C); + RegionView3D *rv3d = CTX_wm_region_view3d(C); - if ((scene->r.scemode & R_MULTIVIEW) == 0) { - iuser->multiview_eye = STEREO_LEFT_ID; - } - else if (v3d->stereo3d_camera != STEREO_3D_ID) { - /* show only left or right camera */ - iuser->multiview_eye = v3d->stereo3d_camera; - } + glDisable(GL_DEPTH_TEST); + glDepthMask(GL_TRUE); + /* Background functions do not read or write depth, but they do clear or completely + * overwrite color buffer. It's more efficient to clear color & depth in once call, so + * background functions do this even though they don't use depth. + */ - BKE_image_multiview_index(ima, iuser); - } - else { - iuser->flag &= ~IMA_SHOW_STEREO; + switch (v3d->debug.background) { + case V3D_DEBUG_BACKGROUND_WORLD: + view3d_draw_background_world(scene, v3d, rv3d); + break; + case V3D_DEBUG_BACKGROUND_GRADIENT: + view3d_draw_background_gradient(); + break; + case V3D_DEBUG_BACKGROUND_NONE: + default: + view3d_draw_background_none(); + break; } } -static void view3d_draw_bgpic(Scene *scene, ARegion *ar, View3D *v3d, - const bool do_foreground, const bool do_camera_frame) +/** + * + */ +static void view3d_draw_render_solid_surfaces(const bContext *C, ARegion *ar, const bool UNUSED(run_screen_shaders)) { - RegionView3D *rv3d = ar->regiondata; - BGpic *bgpic; - int fg_flag = do_foreground ? V3D_BGPIC_FOREGROUND : 0; - - for (bgpic = v3d->bgpicbase.first; bgpic; bgpic = bgpic->next) { - bgpic->iuser.scene = scene; /* Needed for render results. */ - - if ((bgpic->flag & V3D_BGPIC_FOREGROUND) != fg_flag) - continue; - - if ((bgpic->view == 0) || /* zero for any */ - (bgpic->view & (1 << rv3d->view)) || /* check agaist flags */ - (rv3d->persp == RV3D_CAMOB && bgpic->view == (1 << RV3D_VIEW_CAMERA))) - { - float image_aspect[2]; - float fac, asp, zoomx, zoomy; - float x1, y1, x2, y2, centx, centy; - - ImBuf *ibuf = NULL, *freeibuf, *releaseibuf; - void *lock; - rctf clip_rect; - - Image *ima = NULL; - MovieClip *clip = NULL; - - /* disable individual images */ - if ((bgpic->flag & V3D_BGPIC_DISABLED)) - continue; - - freeibuf = NULL; - releaseibuf = NULL; - if (bgpic->source == V3D_BGPIC_IMAGE) { - ima = bgpic->ima; - if (ima == NULL) - continue; - BKE_image_user_frame_calc(&bgpic->iuser, CFRA, 0); - if (ima->source == IMA_SRC_SEQUENCE && !(bgpic->iuser.flag & IMA_USER_FRAME_IN_RANGE)) { - ibuf = NULL; /* frame is out of range, dont show */ - } - else { - view3d_stereo_bgpic_setup(scene, v3d, ima, &bgpic->iuser); - ibuf = BKE_image_acquire_ibuf(ima, &bgpic->iuser, &lock); - releaseibuf = ibuf; - } - - image_aspect[0] = ima->aspx; - image_aspect[1] = ima->aspy; - } - else if (bgpic->source == V3D_BGPIC_MOVIE) { - /* TODO: skip drawing when out of frame range (as image sequences do above) */ - - if (bgpic->flag & V3D_BGPIC_CAMERACLIP) { - if (scene->camera) - clip = BKE_object_movieclip_get(scene, scene->camera, true); - } - else { - clip = bgpic->clip; - } + /* TODO viewport */ + draw_all_objects(C, ar, false, use_depth(C)); +} - if (clip == NULL) - continue; +/** + * + */ +static void view3d_draw_render_transparent_surfaces(const bContext *UNUSED(C)) +{ + /* TODO viewport */ +} - BKE_movieclip_user_set_frame(&bgpic->cuser, CFRA); - ibuf = BKE_movieclip_get_ibuf(clip, &bgpic->cuser); +/** + * + */ +static void view3d_draw_post_draw(const bContext *UNUSED(C)) +{ + /* TODO viewport */ +} - image_aspect[0] = clip->aspx; - image_aspect[1] = clip->aspy; +/* ******************** geometry overlay ***************** */ - /* working with ibuf from image and clip has got different workflow now. - * ibuf acquired from clip is referenced by cache system and should - * be dereferenced after usage. */ - freeibuf = ibuf; - } - else { - /* perhaps when loading future files... */ - BLI_assert(0); - copy_v2_fl(image_aspect, 1.0f); - } +/** + * Front/back wire frames + */ +static void view3d_draw_wire_plates(const bContext *UNUSED(C)) +{ + /* TODO viewport */ +} - if (ibuf == NULL) - continue; +/** + * Special treatment for selected objects + */ +static void view3d_draw_outline_plates(const bContext *UNUSED(C)) +{ + /* TODO viewport */ +} - if ((ibuf->rect == NULL && ibuf->rect_float == NULL) || ibuf->channels != 4) { /* invalid image format */ - if (freeibuf) - IMB_freeImBuf(freeibuf); - if (releaseibuf) - BKE_image_release_ibuf(ima, releaseibuf, lock); +/* ******************** other elements ***************** */ - continue; - } - if (ibuf->rect == NULL) - IMB_rect_from_float(ibuf); +#define DEBUG_GRID 0 - if (rv3d->persp == RV3D_CAMOB) { +static void gridline_range(double x0, double dx, double max, int *r_first, int *r_count) +{ + /* determine range of gridlines that appear in this Area -- similar calc but separate ranges for x & y + * x0 is gridline 0, the axis in screen space + * Area covers [0 .. max) pixels */ - if (do_camera_frame) { - rctf vb; - ED_view3d_calc_camera_border(scene, ar, v3d, rv3d, &vb, false); - x1 = vb.xmin; - y1 = vb.ymin; - x2 = vb.xmax; - y2 = vb.ymax; - } - else { - x1 = ar->winrct.xmin; - y1 = ar->winrct.ymin; - x2 = ar->winrct.xmax; - y2 = ar->winrct.ymax; - } + int first = (int)ceil(-x0 / dx); + int last = (int)floor((max - x0) / dx); - /* apply offset last - camera offset is different to offset in blender units */ - /* so this has some sane way of working - this matches camera's shift _exactly_ */ - { - const float max_dim = max_ff(x2 - x1, y2 - y1); - const float xof_scale = bgpic->xof * max_dim; - const float yof_scale = bgpic->yof * max_dim; - - x1 += xof_scale; - y1 += yof_scale; - x2 += xof_scale; - y2 += yof_scale; - } + if (first <= last) { + *r_first = first; + *r_count = last - first + 1; + } + else { + *r_first = 0; + *r_count = 0; + } - centx = (x1 + x2) / 2.0f; - centy = (y1 + y2) / 2.0f; +#if DEBUG_GRID + printf(" first %d * dx = %f\n", first, x0 + first * dx); + printf(" last %d * dx = %f\n", last, x0 + last * dx); + printf(" count = %d\n", *count_out); +#endif +} - /* aspect correction */ - if (bgpic->flag & V3D_BGPIC_CAMERA_ASPECT) { - /* apply aspect from clip */ - const float w_src = ibuf->x * image_aspect[0]; - const float h_src = ibuf->y * image_aspect[1]; +static int gridline_count(ARegion *ar, double x0, double y0, double dx) +{ + /* x0 & y0 establish the "phase" of the grid within this 2D region + * dx is the frequency, shared by x & y directions + * pass in dx of smallest (highest precision) grid we want to draw */ - /* destination aspect is already applied from the camera frame */ - const float w_dst = x1 - x2; - const float h_dst = y1 - y2; +#if DEBUG_GRID + printf(" %s(%f, %f, dx:%f)\n", __FUNCTION__, x0, y0, dx); +#endif - const float asp_src = w_src / h_src; - const float asp_dst = w_dst / h_dst; + int first, x_ct, y_ct; - if (fabsf(asp_src - asp_dst) >= FLT_EPSILON) { - if ((asp_src > asp_dst) == ((bgpic->flag & V3D_BGPIC_CAMERA_CROP) != 0)) { - /* fit X */ - const float div = asp_src / asp_dst; - x1 = ((x1 - centx) * div) + centx; - x2 = ((x2 - centx) * div) + centx; - } - else { - /* fit Y */ - const float div = asp_dst / asp_src; - y1 = ((y1 - centy) * div) + centy; - y2 = ((y2 - centy) * div) + centy; - } - } - } - } - else { - float tvec[3]; - float sco[2]; - const float mval_f[2] = {1.0f, 0.0f}; - const float co_zero[3] = {0}; - float zfac; - - /* calc window coord */ - zfac = ED_view3d_calc_zfac(rv3d, co_zero, NULL); - ED_view3d_win_to_delta(ar, mval_f, tvec, zfac); - fac = max_ff(fabsf(tvec[0]), max_ff(fabsf(tvec[1]), fabsf(tvec[2]))); /* largest abs axis */ - fac = 1.0f / fac; - - asp = (float)ibuf->y / (float)ibuf->x; - - zero_v3(tvec); - ED_view3d_project_float_v2_m4(ar, tvec, sco, rv3d->persmat); - - x1 = sco[0] + fac * (bgpic->xof - bgpic->size); - y1 = sco[1] + asp * fac * (bgpic->yof - bgpic->size); - x2 = sco[0] + fac * (bgpic->xof + bgpic->size); - y2 = sco[1] + asp * fac * (bgpic->yof + bgpic->size); - - centx = (x1 + x2) / 2.0f; - centy = (y1 + y2) / 2.0f; - } + gridline_range(x0, dx, ar->winx, &first, &x_ct); + gridline_range(y0, dx, ar->winy, &first, &y_ct); - /* complete clip? */ - BLI_rctf_init(&clip_rect, x1, x2, y1, y2); - if (bgpic->rotation) { - BLI_rctf_rotate_expand(&clip_rect, &clip_rect, bgpic->rotation); - } + int total_ct = x_ct + y_ct; - if (clip_rect.xmax < 0 || clip_rect.ymax < 0 || clip_rect.xmin > ar->winx || clip_rect.ymin > ar->winy) { - if (freeibuf) - IMB_freeImBuf(freeibuf); - if (releaseibuf) - BKE_image_release_ibuf(ima, releaseibuf, lock); +#if DEBUG_GRID + printf(" %d + %d = %d gridlines\n", x_ct, y_ct, total_ct); +#endif - continue; - } + return total_ct; +} - zoomx = (x2 - x1) / ibuf->x; - zoomy = (y2 - y1) / ibuf->y; +static bool drawgrid_draw(ARegion *ar, double x0, double y0, double dx, int skip_mod, unsigned pos, unsigned col, GLubyte col_value[3]) +{ + /* skip every skip_mod lines relative to each axis; they will be overlaid by another drawgrid_draw + * always skip exact x0 & y0 axes; they will be drawn later in color + * + * set grid color once, just before the first line is drawn + * it's harmless to set same color for every line, or every vertex + * but if no lines are drawn, color must not be set! */ - /* for some reason; zoomlevels down refuses to use GL_ALPHA_SCALE */ - if (zoomx < 1.0f || zoomy < 1.0f) { - float tzoom = min_ff(zoomx, zoomy); - int mip = 0; +#if DEBUG_GRID + printf(" %s(%f, %f, dx:%f, skip_mod:%d)\n", __FUNCTION__, x0, y0, dx, skip_mod); +#endif - if ((ibuf->userflags & IB_MIPMAP_INVALID) != 0) { - IMB_remakemipmap(ibuf, 0); - ibuf->userflags &= ~IB_MIPMAP_INVALID; - } - else if (ibuf->mipmap[0] == NULL) - IMB_makemipmap(ibuf, 0); - - while (tzoom < 1.0f && mip < 8 && ibuf->mipmap[mip]) { - tzoom *= 2.0f; - zoomx *= 2.0f; - zoomy *= 2.0f; - mip++; - } - if (mip > 0) - ibuf = ibuf->mipmap[mip - 1]; - } + const float x_max = (float)ar->winx; + const float y_max = (float)ar->winy; - if (v3d->zbuf) glDisable(GL_DEPTH_TEST); - glDepthMask(0); + int first, ct; + int x_ct = 0, y_ct = 0; /* count of lines actually drawn */ + int lines_skipped_for_next_unit = 0; - glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + /* draw vertical lines */ + gridline_range(x0, dx, x_max, &first, &ct); - glMatrixMode(GL_PROJECTION); - glPushMatrix(); - glMatrixMode(GL_MODELVIEW); - glPushMatrix(); - ED_region_pixelspace(ar); + for (int i = first; i < first + ct; ++i) { + if (i == 0) + continue; + else if (skip_mod && (i % skip_mod) == 0) { + ++lines_skipped_for_next_unit; + continue; + } - glTranslatef(centx, centy, 0.0); - glRotatef(RAD2DEGF(-bgpic->rotation), 0.0f, 0.0f, 1.0f); + if (x_ct == 0) + immAttrib3ub(col, col_value[0], col_value[1], col_value[2]); - if (bgpic->flag & V3D_BGPIC_FLIP_X) { - zoomx *= -1.0f; - x1 = x2; - } - if (bgpic->flag & V3D_BGPIC_FLIP_Y) { - zoomy *= -1.0f; - y1 = y2; - } - glPixelZoom(zoomx, zoomy); - glColor4f(1.0f, 1.0f, 1.0f, 1.0f - bgpic->blend); + float x = (float)(x0 + i * dx); + immVertex2f(pos, x, 0.0f); + immVertex2f(pos, x, y_max); + ++x_ct; + } - /* could not use glaDrawPixelsAuto because it could fallback to - * glaDrawPixelsSafe in some cases, which will end up in missing - * alpha transparency for the background image (sergey) - */ - glaDrawPixelsTex(x1 - centx, y1 - centy, ibuf->x, ibuf->y, GL_RGBA, GL_UNSIGNED_BYTE, GL_LINEAR, ibuf->rect); + /* draw horizontal lines */ + gridline_range(y0, dx, y_max, &first, &ct); - glPixelZoom(1.0, 1.0); - glPixelTransferf(GL_ALPHA_SCALE, 1.0f); + for (int i = first; i < first + ct; ++i) { + if (i == 0) + continue; + else if (skip_mod && (i % skip_mod) == 0) { + ++lines_skipped_for_next_unit; + continue; + } - glMatrixMode(GL_PROJECTION); - glPopMatrix(); - glMatrixMode(GL_MODELVIEW); - glPopMatrix(); + if (x_ct + y_ct == 0) + immAttrib3ub(col, col_value[0], col_value[1], col_value[2]); - glDisable(GL_BLEND); + float y = (float)(y0 + i * dx); + immVertex2f(pos, 0.0f, y); + immVertex2f(pos, x_max, y); + ++y_ct; + } - glDepthMask(1); - if (v3d->zbuf) glEnable(GL_DEPTH_TEST); +#if DEBUG_GRID + int total_ct = x_ct + y_ct; + printf(" %d + %d = %d gridlines drawn, %d skipped for next unit\n", x_ct, y_ct, total_ct, lines_skipped_for_next_unit); +#endif - if (freeibuf) - IMB_freeImBuf(freeibuf); - if (releaseibuf) - BKE_image_release_ibuf(ima, releaseibuf, lock); - } - } + return lines_skipped_for_next_unit > 0; } -static void view3d_draw_bgpic_test(Scene *scene, ARegion *ar, View3D *v3d, - const bool do_foreground, const bool do_camera_frame) +#define GRID_MIN_PX_D 6.0 +#define GRID_MIN_PX_F 6.0f + +static void drawgrid(UnitSettings *unit, ARegion *ar, View3D *v3d, const char **grid_unit) { RegionView3D *rv3d = ar->regiondata; - if ((v3d->flag & V3D_DISPBGPICS) == 0) - return; - - /* disabled - mango request, since footage /w only render is quite useful - * and this option is easy to disable all background images at once */ -#if 0 - if (v3d->flag2 & V3D_RENDER_OVERRIDE) - return; +#if DEBUG_GRID + printf("%s width %d, height %d\n", __FUNCTION__, ar->winx, ar->winy); #endif - if ((rv3d->view == RV3D_VIEW_USER) || (rv3d->persp != RV3D_ORTHO)) { - if (rv3d->persp == RV3D_CAMOB) { - view3d_draw_bgpic(scene, ar, v3d, do_foreground, do_camera_frame); - } - } - else { - view3d_draw_bgpic(scene, ar, v3d, do_foreground, do_camera_frame); - } -} - -/* ****************** View3d afterdraw *************** */ + double fx = rv3d->persmat[3][0]; + double fy = rv3d->persmat[3][1]; + double fw = rv3d->persmat[3][3]; -typedef struct View3DAfter { - struct View3DAfter *next, *prev; - struct Base *base; - short dflag; -} View3DAfter; + const double wx = 0.5 * ar->winx; /* use double precision to avoid rounding errors */ + const double wy = 0.5 * ar->winy; -/* temp storage of Objects that need to be drawn as last */ -void ED_view3d_after_add(ListBase *lb, Base *base, const short dflag) -{ - View3DAfter *v3da = MEM_callocN(sizeof(View3DAfter), "View 3d after"); - BLI_assert((base->flag & OB_FROMDUPLI) == 0); - BLI_addtail(lb, v3da); - v3da->base = base; - v3da->dflag = dflag; -} + double x = wx * fx / fw; + double y = wy * fy / fw; -/* disables write in zbuffer and draws it over */ -static void view3d_draw_transp(Scene *scene, ARegion *ar, View3D *v3d) -{ - View3DAfter *v3da; - - glDepthMask(GL_FALSE); - v3d->transp = true; - - while ((v3da = BLI_pophead(&v3d->afterdraw_transp))) { - draw_object(scene, ar, v3d, v3da->base, v3da->dflag); - MEM_freeN(v3da); - } - v3d->transp = false; - - glDepthMask(GL_TRUE); - -} - -/* clears zbuffer and draws it over */ -static void view3d_draw_xray(Scene *scene, ARegion *ar, View3D *v3d, bool *clear) -{ - View3DAfter *v3da; + double vec4[4] = { v3d->grid, v3d->grid, 0.0, 1.0 }; + mul_m4_v4d(rv3d->persmat, vec4); + fx = vec4[0]; + fy = vec4[1]; + fw = vec4[3]; - if (*clear && v3d->zbuf) { - glClear(GL_DEPTH_BUFFER_BIT); - *clear = false; - } + double dx = fabs(x - wx * fx / fw); + if (dx == 0) dx = fabs(y - wy * fy / fw); - v3d->xray = true; - while ((v3da = BLI_pophead(&v3d->afterdraw_xray))) { - draw_object(scene, ar, v3d, v3da->base, v3da->dflag); - MEM_freeN(v3da); - } - v3d->xray = false; -} + x += wx; + y += wy; + /* now x, y, and dx have their final values + * (x,y) is the world origin (0,0,0) mapped to Area-relative screen space + * dx is the distance in pixels between grid lines -- same for horiz or vert grid lines */ -/* clears zbuffer and draws it over */ -static void view3d_draw_xraytransp(Scene *scene, ARegion *ar, View3D *v3d, const bool clear) -{ - View3DAfter *v3da; + glLineWidth(1.0f); - if (clear && v3d->zbuf) - glClear(GL_DEPTH_BUFFER_BIT); +#if 0 /* TODO: write to UI/widget depth buffer, not scene depth */ + glDepthMask(GL_FALSE); /* disable write in zbuffer */ +#endif - v3d->xray = true; - v3d->transp = true; - - glDepthMask(GL_FALSE); + VertexFormat *format = immVertexFormat(); + unsigned int pos = add_attrib(format, "pos", COMP_F32, 2, KEEP_FLOAT); + unsigned int color = add_attrib(format, "color", COMP_U8, 3, NORMALIZE_INT_TO_FLOAT); - while ((v3da = BLI_pophead(&v3d->afterdraw_xraytransp))) { - draw_object(scene, ar, v3d, v3da->base, v3da->dflag); - MEM_freeN(v3da); - } + immBindBuiltinProgram(GPU_SHADER_2D_FLAT_COLOR); - v3d->transp = false; - v3d->xray = false; + unsigned char col[3], col2[3]; + UI_GetThemeColor3ubv(TH_GRID, col); - glDepthMask(GL_TRUE); -} + if (unit->system) { + const void *usys; + int len; -/* *********************** */ + bUnit_GetSystem(unit->system, B_UNIT_LENGTH, &usys, &len); -/* - * In most cases call draw_dupli_objects, - * draw_dupli_objects_color was added because when drawing set dupli's - * we need to force the color - */ + bool first = true; -#if 0 -int dupli_ob_sort(void *arg1, void *arg2) -{ - void *p1 = ((DupliObject *)arg1)->ob; - void *p2 = ((DupliObject *)arg2)->ob; - int val = 0; - if (p1 < p2) val = -1; - else if (p1 > p2) val = 1; - return val; -} -#endif + if (usys) { + int i = len; + while (i--) { + double scalar = bUnit_GetScaler(usys, i); + double dx_scalar = dx * scalar / (double)unit->scale_length; + if (dx_scalar < (GRID_MIN_PX_D * 2.0)) { + /* very very small grid items are less useful when dealing with units */ + continue; + } -static DupliObject *dupli_step(DupliObject *dob) -{ - while (dob && dob->no_draw) - dob = dob->next; - return dob; -} + if (first) { + first = false; -static void draw_dupli_objects_color( - Scene *scene, ARegion *ar, View3D *v3d, Base *base, - const short dflag, const int color) -{ - RegionView3D *rv3d = ar->regiondata; - ListBase *lb; - LodLevel *savedlod; - DupliObject *dob_prev = NULL, *dob, *dob_next = NULL; - Base tbase = {NULL}; - BoundBox bb, *bb_tmp; /* use a copy because draw_object, calls clear_mesh_caches */ - GLuint displist = 0; - unsigned char color_rgb[3]; - const short dflag_dupli = dflag | DRAW_CONSTCOLOR; - short transflag; - bool use_displist = false; /* -1 is initialize */ - char dt; - short dtx; - DupliApplyData *apply_data; - - if (base->object->restrictflag & OB_RESTRICT_VIEW) return; - if ((base->object->restrictflag & OB_RESTRICT_RENDER) && (v3d->flag2 & V3D_RENDER_OVERRIDE)) return; - - if (dflag & DRAW_CONSTCOLOR) { - BLI_assert(color == TH_UNDEFINED); - } - else { - UI_GetThemeColorBlend3ubv(color, TH_BACK, 0.5f, color_rgb); - } + /* Store the smallest drawn grid size units name so users know how big each grid cell is */ + *grid_unit = bUnit_GetNameDisplay(usys, i); + rv3d->gridview = (float)((scalar * (double)v3d->grid) / (double)unit->scale_length); - tbase.flag = OB_FROMDUPLI | base->flag; - lb = object_duplilist(G.main->eval_ctx, scene, base->object); - // BLI_listbase_sort(lb, dupli_ob_sort); /* might be nice to have if we have a dupli list with mixed objects. */ + int gridline_ct = gridline_count(ar, x, y, dx_scalar); + if (gridline_ct == 0) + goto drawgrid_cleanup; /* nothing to draw */ - apply_data = duplilist_apply(base->object, scene, lb); + immBegin(GL_LINES, gridline_ct * 2); + } - dob = dupli_step(lb->first); - if (dob) dob_next = dupli_step(dob->next); + float blend_fac = 1.0f - ((GRID_MIN_PX_F * 2.0f) / (float)dx_scalar); + /* tweak to have the fade a bit nicer */ + blend_fac = (blend_fac * blend_fac) * 2.0f; + CLAMP(blend_fac, 0.3f, 1.0f); - for (; dob; dob_prev = dob, dob = dob_next, dob_next = dob_next ? dupli_step(dob_next->next) : NULL) { - bool testbb = false; + UI_GetThemeColorBlend3ubv(TH_HIGH_GRAD, TH_GRID, blend_fac, col2); - tbase.object = dob->ob; + const int skip_mod = (i == 0) ? 0 : (int)round(bUnit_GetScaler(usys, i - 1) / scalar); +#if DEBUG_GRID + printf("%s %f, ", bUnit_GetNameDisplay(usys, i), scalar); + if (i > 0) + printf("next unit is %d times larger\n", skip_mod); + else + printf("largest unit\n"); +#endif + if (!drawgrid_draw(ar, x, y, dx_scalar, skip_mod, pos, color, col2)) + break; + } + } + } + else { + const double sublines = v3d->gridsubdiv; + const float sublines_fl = v3d->gridsubdiv; - /* Make sure lod is updated from dupli's position */ - savedlod = dob->ob->currentlod; + int grids_to_draw = 2; /* first the faint fine grid, then the bold coarse grid */ -#ifdef WITH_GAMEENGINE - if (rv3d->rflag & RV3D_IS_GAME_ENGINE) { - BKE_object_lod_update(dob->ob, rv3d->viewinv[3]); + if (dx < GRID_MIN_PX_D) { + rv3d->gridview *= sublines_fl; + dx *= sublines; + if (dx < GRID_MIN_PX_D) { + rv3d->gridview *= sublines_fl; + dx *= sublines; + if (dx < GRID_MIN_PX_D) { + rv3d->gridview *= sublines_fl; + dx *= sublines; + grids_to_draw = (dx < GRID_MIN_PX_D) ? 0 : 1; + } + } + } + else { + if (dx > (GRID_MIN_PX_D * 10.0)) { /* start blending in */ + rv3d->gridview /= sublines_fl; + dx /= sublines; + if (dx > (GRID_MIN_PX_D * 10.0)) { /* start blending in */ + rv3d->gridview /= sublines_fl; + dx /= sublines; + if (dx > (GRID_MIN_PX_D * 10.0)) { + grids_to_draw = 1; + } + } + } } -#endif - - /* extra service: draw the duplicator in drawtype of parent, minimum taken - * to allow e.g. boundbox box objects in groups for LOD */ - dt = tbase.object->dt; - tbase.object->dt = MIN2(tbase.object->dt, base->object->dt); - /* inherit draw extra, but not if a boundbox under the assumption that this - * is intended to speed up drawing, and drawing extra (especially wire) can - * slow it down too much */ - dtx = tbase.object->dtx; - if (tbase.object->dt != OB_BOUNDBOX) - tbase.object->dtx = base->object->dtx; + int gridline_ct = gridline_count(ar, x, y, dx); + if (gridline_ct == 0) + goto drawgrid_cleanup; /* nothing to draw */ - /* negative scale flag has to propagate */ - transflag = tbase.object->transflag; + immBegin(GL_LINES, gridline_ct * 2); - if (is_negative_m4(dob->mat)) - tbase.object->transflag |= OB_NEG_SCALE; - else - tbase.object->transflag &= ~OB_NEG_SCALE; - - /* should move outside the loop but possible color is set in draw_object still */ - if ((dflag & DRAW_CONSTCOLOR) == 0) { - glColor3ubv(color_rgb); - } - - /* generate displist, test for new object */ - if (dob_prev && dob_prev->ob != dob->ob) { - if (use_displist == true) - glDeleteLists(displist, 1); - - use_displist = false; + if (grids_to_draw == 2) { + UI_GetThemeColorBlend3ubv(TH_HIGH_GRAD, TH_GRID, dx / (GRID_MIN_PX_D * 6.0), col2); + if (drawgrid_draw(ar, x, y, dx, v3d->gridsubdiv, pos, color, col2)) + drawgrid_draw(ar, x, y, dx * sublines, 0, pos, color, col); } - - if ((bb_tmp = BKE_object_boundbox_get(dob->ob))) { - bb = *bb_tmp; /* must make a copy */ - testbb = true; + else if (grids_to_draw == 1) { + drawgrid_draw(ar, x, y, dx, 0, pos, color, col); } + } - if (!testbb || ED_view3d_boundbox_clip_ex(rv3d, &bb, dob->mat)) { - /* generate displist */ - if (use_displist == false) { - - /* note, since this was added, its checked (dob->type == OB_DUPLIGROUP) - * however this is very slow, it was probably needed for the NLA - * offset feature (used in group-duplicate.blend but no longer works in 2.5) - * so for now it should be ok to - campbell */ - - if ( /* if this is the last no need to make a displist */ - (dob_next == NULL || dob_next->ob != dob->ob) || - /* lamp drawing messes with matrices, could be handled smarter... but this works */ - (dob->ob->type == OB_LAMP) || - (dob->type == OB_DUPLIGROUP && dob->animated) || - !bb_tmp || - draw_glsl_material(scene, dob->ob, v3d, dt) || - check_object_draw_texture(scene, v3d, dt) || - (v3d->flag2 & V3D_SOLID_MATCAP) != 0) - { - // printf("draw_dupli_objects_color: skipping displist for %s\n", dob->ob->id.name + 2); - use_displist = false; - } - else { - // printf("draw_dupli_objects_color: using displist for %s\n", dob->ob->id.name + 2); - - /* disable boundbox check for list creation */ - BKE_object_boundbox_flag(dob->ob, BOUNDBOX_DISABLED, 1); - /* need this for next part of code */ - unit_m4(dob->ob->obmat); /* obmat gets restored */ - - displist = glGenLists(1); - glNewList(displist, GL_COMPILE); - draw_object(scene, ar, v3d, &tbase, dflag_dupli); - glEndList(); - - use_displist = true; - BKE_object_boundbox_flag(dob->ob, BOUNDBOX_DISABLED, 0); - } - } - - if (use_displist) { - glPushMatrix(); - glMultMatrixf(dob->mat); - glCallList(displist); - glPopMatrix(); - } - else { - copy_m4_m4(dob->ob->obmat, dob->mat); - GPU_begin_dupli_object(dob); - draw_object(scene, ar, v3d, &tbase, dflag_dupli); - GPU_end_dupli_object(); - } - } - - tbase.object->dt = dt; - tbase.object->dtx = dtx; - tbase.object->transflag = transflag; - tbase.object->currentlod = savedlod; + /* draw visible axes */ + /* horizontal line */ + if (0 <= y && y < ar->winy) { + UI_make_axis_color(col, col2, ELEM(rv3d->view, RV3D_VIEW_RIGHT, RV3D_VIEW_LEFT) ? 'Y' : 'X'); + immAttrib3ub(color, col2[0], col2[1], col2[2]); + immVertex2f(pos, 0.0f, y); + immVertex2f(pos, (float)ar->winx, y); } - if (apply_data) { - duplilist_restore(lb, apply_data); - duplilist_free_apply_data(apply_data); + /* vertical line */ + if (0 <= x && x < ar->winx) { + UI_make_axis_color(col, col2, ELEM(rv3d->view, RV3D_VIEW_TOP, RV3D_VIEW_BOTTOM) ? 'Y' : 'Z'); + immAttrib3ub(color, col2[0], col2[1], col2[2]); + immVertex2f(pos, x, 0.0f); + immVertex2f(pos, x, (float)ar->winy); } - free_object_duplilist(lb); - - if (use_displist) - glDeleteLists(displist, 1); -} + immEnd(); -static void draw_dupli_objects(Scene *scene, ARegion *ar, View3D *v3d, Base *base) -{ - /* define the color here so draw_dupli_objects_color can be called - * from the set loop */ - - int color = (base->flag & SELECT) ? TH_SELECT : TH_WIRE; - /* debug */ - if (base->object->dup_group && base->object->dup_group->id.us < 1) - color = TH_REDALERT; - - draw_dupli_objects_color(scene, ar, v3d, base, 0, color); +drawgrid_cleanup: + immUnbindProgram(); + +#if 0 /* depth write is left enabled above */ + glDepthMask(GL_TRUE); /* enable write in zbuffer */ +#endif } -/* XXX warning, not using gpu offscreen here */ -void view3d_update_depths_rect(ARegion *ar, ViewDepths *d, rcti *rect) +#undef DEBUG_GRID +#undef GRID_MIN_PX_D +#undef GRID_MIN_PX_F + +static void drawfloor(Scene *scene, View3D *v3d, const char **grid_unit, bool write_depth) { - int x, y, w, h; - rcti r; - /* clamp rect by region */ + /* draw only if there is something to draw */ + if (v3d->gridflag & (V3D_SHOW_FLOOR | V3D_SHOW_X | V3D_SHOW_Y | V3D_SHOW_Z)) { + /* draw how many lines? + * trunc(v3d->gridlines / 2) * 4 + * + 2 for xy axes (possibly with special colors) + * + 1 for z axis (the only line not in xy plane) + * even v3d->gridlines are honored, odd rounded down */ + const int gridlines = v3d->gridlines / 2; + const float grid_scale = ED_view3d_grid_scale(scene, v3d, grid_unit); + const float grid = gridlines * grid_scale; - r.xmin = 0; - r.xmax = ar->winx - 1; - r.ymin = 0; - r.ymax = ar->winy - 1; + const bool show_floor = (v3d->gridflag & V3D_SHOW_FLOOR) && gridlines >= 1; - /* Constrain rect to depth bounds */ - BLI_rcti_isect(&r, rect, rect); + bool show_axis_x = v3d->gridflag & V3D_SHOW_X; + bool show_axis_y = v3d->gridflag & V3D_SHOW_Y; + bool show_axis_z = v3d->gridflag & V3D_SHOW_Z; - /* assign values to compare with the ViewDepths */ - x = rect->xmin; - y = rect->ymin; + unsigned char col_grid[3], col_axis[3]; - w = BLI_rcti_size_x(rect); - h = BLI_rcti_size_y(rect); + glLineWidth(1.0f); - if (w <= 0 || h <= 0) { - if (d->depths) - MEM_freeN(d->depths); - d->depths = NULL; + UI_GetThemeColor3ubv(TH_GRID, col_grid); - d->damaged = false; - } - else if (d->w != w || - d->h != h || - d->x != x || - d->y != y || - d->depths == NULL - ) - { - d->x = x; - d->y = y; - d->w = w; - d->h = h; + if (!write_depth) + glDepthMask(GL_FALSE); - if (d->depths) - MEM_freeN(d->depths); + if (show_floor) { + const unsigned vertex_ct = 2 * (gridlines * 4 + 2); + const int sublines = v3d->gridsubdiv; - d->depths = MEM_mallocN(sizeof(float) * d->w * d->h, "View depths Subset"); - - d->damaged = true; - } + unsigned char col_bg[3], col_grid_emphasise[3], col_grid_light[3]; - if (d->damaged) { - /* XXX using special function here, it doesn't use the gpu offscreen system */ - view3d_opengl_read_Z_pixels(ar, d->x, d->y, d->w, d->h, GL_DEPTH_COMPONENT, GL_FLOAT, d->depths); - glGetDoublev(GL_DEPTH_RANGE, d->depth_range); - d->damaged = false; - } -} + VertexFormat *format = immVertexFormat(); + unsigned int pos = add_attrib(format, "pos", COMP_F32, 2, KEEP_FLOAT); + unsigned int color = add_attrib(format, "color", COMP_U8, 3, NORMALIZE_INT_TO_FLOAT); -/* note, with nouveau drivers the glReadPixels() is very slow. [#24339] */ -void ED_view3d_depth_update(ARegion *ar) -{ - RegionView3D *rv3d = ar->regiondata; - - /* Create storage for, and, if necessary, copy depth buffer */ - if (!rv3d->depths) rv3d->depths = MEM_callocN(sizeof(ViewDepths), "ViewDepths"); - if (rv3d->depths) { - ViewDepths *d = rv3d->depths; - if (d->w != ar->winx || - d->h != ar->winy || - !d->depths) - { - d->w = ar->winx; - d->h = ar->winy; - if (d->depths) - MEM_freeN(d->depths); - d->depths = MEM_mallocN(sizeof(float) * d->w * d->h, "View depths"); - d->damaged = true; - } - - if (d->damaged) { - view3d_opengl_read_pixels(ar, 0, 0, d->w, d->h, GL_DEPTH_COMPONENT, GL_FLOAT, d->depths); - glGetDoublev(GL_DEPTH_RANGE, d->depth_range); - - d->damaged = false; - } - } -} + immBindBuiltinProgram(GPU_SHADER_3D_FLAT_COLOR); -/* utility function to find the closest Z value, use for autodepth */ -float view3d_depth_near(ViewDepths *d) -{ - /* convert to float for comparisons */ - const float near = (float)d->depth_range[0]; - const float far_real = (float)d->depth_range[1]; - float far = far_real; - - const float *depths = d->depths; - float depth = FLT_MAX; - int i = (int)d->w * (int)d->h; /* cast to avoid short overflow */ + immBegin(GL_LINES, vertex_ct); - /* far is both the starting 'far' value - * and the closest value found. */ - while (i--) { - depth = *depths++; - if ((depth < far) && (depth > near)) { - far = depth; - } - } + /* draw normal grid lines */ + UI_GetColorPtrShade3ubv(col_grid, col_grid_light, 10); - return far == far_real ? FLT_MAX : far; -} - -void ED_view3d_draw_depth_gpencil(Scene *scene, ARegion *ar, View3D *v3d) -{ - short zbuf = v3d->zbuf; - RegionView3D *rv3d = ar->regiondata; + for (int a = 1; a <= gridlines; a++) { + /* skip emphasised divider lines */ + if (a % sublines != 0) { + const float line = a * grid_scale; - view3d_winmatrix_set(ar, v3d, NULL); - view3d_viewmatrix_set(scene, v3d, rv3d); /* note: calls BKE_object_where_is_calc for camera... */ + immAttrib3ubv(color, col_grid_light); - mul_m4_m4m4(rv3d->persmat, rv3d->winmat, rv3d->viewmat); - invert_m4_m4(rv3d->persinv, rv3d->persmat); - invert_m4_m4(rv3d->viewinv, rv3d->viewmat); + immVertex2f(pos, -grid, -line); + immVertex2f(pos, +grid, -line); + immVertex2f(pos, -grid, +line); + immVertex2f(pos, +grid, +line); - glClear(GL_DEPTH_BUFFER_BIT); + immVertex2f(pos, -line, -grid); + immVertex2f(pos, -line, +grid); + immVertex2f(pos, +line, -grid); + immVertex2f(pos, +line, +grid); + } + } - glLoadMatrixf(rv3d->viewmat); + /* draw emphasised grid lines */ + UI_GetThemeColor3ubv(TH_BACK, col_bg); + /* emphasise division lines lighter instead of darker, if background is darker than grid */ + UI_GetColorPtrShade3ubv(col_grid, col_grid_emphasise, + (col_grid[0] + col_grid[1] + col_grid[2] + 30 > + col_bg[0] + col_bg[1] + col_bg[2]) ? 20 : -10); - v3d->zbuf = true; - glEnable(GL_DEPTH_TEST); + if (sublines <= gridlines) { + immAttrib3ubv(color, col_grid_emphasise); - if (v3d->flag2 & V3D_SHOW_GPENCIL) { - ED_gpencil_draw_view3d(NULL, scene, v3d, ar, true); - } - - v3d->zbuf = zbuf; + for (int a = sublines; a <= gridlines; a += sublines) { + const float line = a * grid_scale; -} + immVertex2f(pos, -grid, -line); + immVertex2f(pos, +grid, -line); + immVertex2f(pos, -grid, +line); + immVertex2f(pos, +grid, +line); -void ED_view3d_draw_depth(Scene *scene, ARegion *ar, View3D *v3d, bool alphaoverride) -{ - RegionView3D *rv3d = ar->regiondata; - Base *base; - short zbuf = v3d->zbuf; - short flag = v3d->flag; - float glalphaclip = U.glalphaclip; - int obcenter_dia = U.obcenter_dia; - /* no need for color when drawing depth buffer */ - const short dflag_depth = DRAW_CONSTCOLOR; - /* temp set drawtype to solid */ - - /* Setting these temporarily is not nice */ - v3d->flag &= ~V3D_SELECT_OUTLINE; - U.glalphaclip = alphaoverride ? 0.5f : glalphaclip; /* not that nice but means we wont zoom into billboards */ - U.obcenter_dia = 0; - - view3d_winmatrix_set(ar, v3d, NULL); - view3d_viewmatrix_set(scene, v3d, rv3d); /* note: calls BKE_object_where_is_calc for camera... */ - - mul_m4_m4m4(rv3d->persmat, rv3d->winmat, rv3d->viewmat); - invert_m4_m4(rv3d->persinv, rv3d->persmat); - invert_m4_m4(rv3d->viewinv, rv3d->viewmat); - - glClear(GL_DEPTH_BUFFER_BIT); - - glLoadMatrixf(rv3d->viewmat); - - if (rv3d->rflag & RV3D_CLIPPING) { - ED_view3d_clipping_set(rv3d); - } - /* get surface depth without bias */ - rv3d->rflag |= RV3D_ZOFFSET_DISABLED; - - v3d->zbuf = true; - glEnable(GL_DEPTH_TEST); - - /* draw set first */ - if (scene->set) { - Scene *sce_iter; - for (SETLOOPER(scene->set, sce_iter, base)) { - if (v3d->lay & base->lay) { - draw_object(scene, ar, v3d, base, 0); - if (base->object->transflag & OB_DUPLI) { - draw_dupli_objects_color(scene, ar, v3d, base, dflag_depth, TH_UNDEFINED); + immVertex2f(pos, -line, -grid); + immVertex2f(pos, -line, +grid); + immVertex2f(pos, +line, -grid); + immVertex2f(pos, +line, +grid); } } - } - } - - for (base = scene->base.first; base; base = base->next) { - if (v3d->lay & base->lay) { - /* dupli drawing */ - if (base->object->transflag & OB_DUPLI) { - draw_dupli_objects_color(scene, ar, v3d, base, dflag_depth, TH_UNDEFINED); - } - draw_object(scene, ar, v3d, base, dflag_depth); - } - } - - /* this isn't that nice, draw xray objects as if they are normal */ - if (v3d->afterdraw_transp.first || - v3d->afterdraw_xray.first || - v3d->afterdraw_xraytransp.first) - { - View3DAfter *v3da; - int mask_orig; - v3d->xray = true; - - /* transp materials can change the depth mask, see #21388 */ - glGetIntegerv(GL_DEPTH_WRITEMASK, &mask_orig); + /* draw X axis */ + if (show_axis_x) { + show_axis_x = false; /* drawing now, won't need to draw later */ + UI_make_axis_color(col_grid, col_axis, 'X'); + immAttrib3ubv(color, col_axis); + } + else + immAttrib3ubv(color, col_grid_emphasise); + immVertex2f(pos, -grid, 0.0f); + immVertex2f(pos, +grid, 0.0f); - if (v3d->afterdraw_xray.first || v3d->afterdraw_xraytransp.first) { - glDepthFunc(GL_ALWAYS); /* always write into the depth bufer, overwriting front z values */ - for (v3da = v3d->afterdraw_xray.first; v3da; v3da = v3da->next) { - draw_object(scene, ar, v3d, v3da->base, dflag_depth); + /* draw Y axis */ + if (show_axis_y) { + show_axis_y = false; /* drawing now, won't need to draw later */ + UI_make_axis_color(col_grid, col_axis, 'Y'); + immAttrib3ubv(color, col_axis); } - glDepthFunc(GL_LEQUAL); /* Now write the depth buffer normally */ - } + else + immAttrib3ubv(color, col_grid_emphasise); - /* draw 3 passes, transp/xray/xraytransp */ - v3d->xray = false; - v3d->transp = true; - while ((v3da = BLI_pophead(&v3d->afterdraw_transp))) { - draw_object(scene, ar, v3d, v3da->base, dflag_depth); - MEM_freeN(v3da); - } + immVertex2f(pos, 0.0f, -grid); + immVertex2f(pos, 0.0f, +grid); - v3d->xray = true; - v3d->transp = false; - while ((v3da = BLI_pophead(&v3d->afterdraw_xray))) { - draw_object(scene, ar, v3d, v3da->base, dflag_depth); - MEM_freeN(v3da); - } + immEnd(); + immUnbindProgram(); - v3d->xray = true; - v3d->transp = true; - while ((v3da = BLI_pophead(&v3d->afterdraw_xraytransp))) { - draw_object(scene, ar, v3d, v3da->base, dflag_depth); - MEM_freeN(v3da); + /* done with XY plane */ } - - v3d->xray = false; - v3d->transp = false; - - glDepthMask(mask_orig); - } - - if (rv3d->rflag & RV3D_CLIPPING) { - ED_view3d_clipping_disable(); - } - rv3d->rflag &= ~RV3D_ZOFFSET_DISABLED; - - v3d->zbuf = zbuf; - if (!v3d->zbuf) glDisable(GL_DEPTH_TEST); - - U.glalphaclip = glalphaclip; - v3d->flag = flag; - U.obcenter_dia = obcenter_dia; -} - -typedef struct View3DShadow { - struct View3DShadow *next, *prev; - GPULamp *lamp; -} View3DShadow; - -static void gpu_render_lamp_update(Scene *scene, View3D *v3d, - Object *ob, Object *par, - float obmat[4][4], unsigned int lay, - ListBase *shadows, SceneRenderLayer *srl) -{ - GPULamp *lamp; - Lamp *la = (Lamp *)ob->data; - View3DShadow *shadow; - unsigned int layers; - - lamp = GPU_lamp_from_blender(scene, ob, par); - - if (lamp) { - GPU_lamp_update(lamp, lay, (ob->restrictflag & OB_RESTRICT_RENDER), obmat); - GPU_lamp_update_colors(lamp, la->r, la->g, la->b, la->energy); - - layers = lay & v3d->lay; - if (srl) - layers &= srl->lay; - - if (layers && - GPU_lamp_has_shadow_buffer(lamp) && - /* keep last, may do string lookup */ - GPU_lamp_override_visible(lamp, srl, NULL)) - { - shadow = MEM_callocN(sizeof(View3DShadow), "View3DShadow"); - shadow->lamp = lamp; - BLI_addtail(shadows, shadow); - } - } -} + if (show_axis_x || show_axis_y || show_axis_z) { + /* draw axis lines -- sometimes grid floor is off, other times we still need to draw the Z axis */ -static void gpu_update_lamps_shadows_world(Scene *scene, View3D *v3d) -{ - ListBase shadows; - View3DShadow *shadow; - Scene *sce_iter; - Base *base; - Object *ob; - World *world = scene->world; - SceneRenderLayer *srl = v3d->scenelock ? BLI_findlink(&scene->r.layers, scene->r.actlay) : NULL; - - BLI_listbase_clear(&shadows); - - /* update lamp transform and gather shadow lamps */ - for (SETLOOPER(scene, sce_iter, base)) { - ob = base->object; - - if (ob->type == OB_LAMP) - gpu_render_lamp_update(scene, v3d, ob, NULL, ob->obmat, ob->lay, &shadows, srl); - - if (ob->transflag & OB_DUPLI) { - DupliObject *dob; - ListBase *lb = object_duplilist(G.main->eval_ctx, scene, ob); - - for (dob = lb->first; dob; dob = dob->next) - if (dob->ob->type == OB_LAMP) - gpu_render_lamp_update(scene, v3d, dob->ob, ob, dob->mat, ob->lay, &shadows, srl); - - free_object_duplilist(lb); - } - } - - /* render shadows after updating all lamps, nested object_duplilist - * don't work correct since it's replacing object matrices */ - for (shadow = shadows.first; shadow; shadow = shadow->next) { - /* this needs to be done better .. */ - float viewmat[4][4], winmat[4][4]; - int drawtype, lay, winsize, flag2 = v3d->flag2; - ARegion ar = {NULL}; - RegionView3D rv3d = {{{0}}}; - - drawtype = v3d->drawtype; - lay = v3d->lay; - - v3d->drawtype = OB_SOLID; - v3d->lay &= GPU_lamp_shadow_layer(shadow->lamp); - v3d->flag2 &= ~(V3D_SOLID_TEX | V3D_SHOW_SOLID_MATCAP); - v3d->flag2 |= V3D_RENDER_OVERRIDE | V3D_RENDER_SHADOW; - - GPU_lamp_shadow_buffer_bind(shadow->lamp, viewmat, &winsize, winmat); - - ar.regiondata = &rv3d; - ar.regiontype = RGN_TYPE_WINDOW; - rv3d.persp = RV3D_CAMOB; - copy_m4_m4(rv3d.winmat, winmat); - copy_m4_m4(rv3d.viewmat, viewmat); - invert_m4_m4(rv3d.viewinv, rv3d.viewmat); - mul_m4_m4m4(rv3d.persmat, rv3d.winmat, rv3d.viewmat); - invert_m4_m4(rv3d.persinv, rv3d.viewinv); - - /* no need to call ED_view3d_draw_offscreen_init since shadow buffers were already updated */ - ED_view3d_draw_offscreen( - scene, v3d, &ar, winsize, winsize, viewmat, winmat, - false, false, true, - NULL, NULL, NULL, NULL); - GPU_lamp_shadow_buffer_unbind(shadow->lamp); - - v3d->drawtype = drawtype; - v3d->lay = lay; - v3d->flag2 = flag2; - } - - BLI_freelistN(&shadows); - - /* update world values */ - if (world) { - GPU_mist_update_enable(world->mode & WO_MIST); - GPU_mist_update_values(world->mistype, world->miststa, world->mistdist, world->misi, &world->horr); - GPU_horizon_update_color(&world->horr); - GPU_ambient_update_color(&world->ambr); - GPU_zenith_update_color(&world->zenr); - } -} + VertexFormat *format = immVertexFormat(); + unsigned int pos = add_attrib(format, "pos", COMP_F32, 3, KEEP_FLOAT); + unsigned int color = add_attrib(format, "color", COMP_U8, 3, NORMALIZE_INT_TO_FLOAT); -/* *********************** customdata **************** */ + immBindBuiltinProgram(GPU_SHADER_3D_FLAT_COLOR); + immBegin(GL_LINES, (show_axis_x + show_axis_y + show_axis_z) * 2); -CustomDataMask ED_view3d_datamask(const Scene *scene, const View3D *v3d) -{ - CustomDataMask mask = 0; - const int drawtype = view3d_effective_drawtype(v3d); + if (show_axis_x) { + UI_make_axis_color(col_grid, col_axis, 'X'); + immAttrib3ubv(color, col_axis); + immVertex3f(pos, -grid, 0.0f, 0.0f); + immVertex3f(pos, +grid, 0.0f, 0.0f); + } - if (ELEM(drawtype, OB_TEXTURE, OB_MATERIAL) || - ((drawtype == OB_SOLID) && (v3d->flag2 & V3D_SOLID_TEX))) - { - mask |= CD_MASK_MTEXPOLY | CD_MASK_MLOOPUV | CD_MASK_MLOOPCOL; + if (show_axis_y) { + UI_make_axis_color(col_grid, col_axis, 'Y'); + immAttrib3ubv(color, col_axis); + immVertex3f(pos, 0.0f, -grid, 0.0f); + immVertex3f(pos, 0.0f, +grid, 0.0f); + } - if (BKE_scene_use_new_shading_nodes(scene)) { - if (drawtype == OB_MATERIAL) - mask |= CD_MASK_ORCO; - } - else { - if ((scene->gm.matmode == GAME_MAT_GLSL && drawtype == OB_TEXTURE) || - (drawtype == OB_MATERIAL)) - { - mask |= CD_MASK_ORCO; + if (show_axis_z) { + UI_make_axis_color(col_grid, col_axis, 'Z'); + immAttrib3ubv(color, col_axis); + immVertex3f(pos, 0.0f, 0.0f, -grid); + immVertex3f(pos, 0.0f, 0.0f, +grid); } + + immEnd(); + immUnbindProgram(); } - } - return mask; + if (!write_depth) + glDepthMask(GL_TRUE); + } } -/* goes over all modes and view3d settings */ -CustomDataMask ED_view3d_screen_datamask(const bScreen *screen) +/** could move this elsewhere, but tied into #ED_view3d_grid_scale */ +float ED_scene_grid_scale(Scene *scene, const char **grid_unit) { - const Scene *scene = screen->scene; - CustomDataMask mask = CD_MASK_BAREMESH; - const ScrArea *sa; - - /* check if we need tfaces & mcols due to view mode */ - for (sa = screen->areabase.first; sa; sa = sa->next) { - if (sa->spacetype == SPACE_VIEW3D) { - mask |= ED_view3d_datamask(scene, sa->spacedata.first); + /* apply units */ + if (scene->unit.system) { + const void *usys; + int len; + + bUnit_GetSystem(scene->unit.system, B_UNIT_LENGTH, &usys, &len); + + if (usys) { + int i = bUnit_GetBaseUnit(usys); + if (grid_unit) + *grid_unit = bUnit_GetNameDisplay(usys, i); + return (float)bUnit_GetScaler(usys, i) / scene->unit.scale_length; } } - return mask; + return 1.0f; } -/** - * \note keep this synced with #ED_view3d_mats_rv3d_backup/#ED_view3d_mats_rv3d_restore - */ -void ED_view3d_update_viewmat(Scene *scene, View3D *v3d, ARegion *ar, float viewmat[4][4], float winmat[4][4]) +float ED_view3d_grid_scale(Scene *scene, View3D *v3d, const char **grid_unit) { - RegionView3D *rv3d = ar->regiondata; - - /* setup window matrices */ - if (winmat) - copy_m4_m4(rv3d->winmat, winmat); - else - view3d_winmatrix_set(ar, v3d, NULL); - - /* setup view matrix */ - if (viewmat) - copy_m4_m4(rv3d->viewmat, viewmat); - else - view3d_viewmatrix_set(scene, v3d, rv3d); /* note: calls BKE_object_where_is_calc for camera... */ - - /* update utility matrices */ - mul_m4_m4m4(rv3d->persmat, rv3d->winmat, rv3d->viewmat); - invert_m4_m4(rv3d->persinv, rv3d->persmat); - invert_m4_m4(rv3d->viewinv, rv3d->viewmat); - - /* calculate GLSL view dependent values */ + return v3d->grid * ED_scene_grid_scale(scene, grid_unit); +} - /* store window coordinates scaling/offset */ - if (rv3d->persp == RV3D_CAMOB && v3d->camera) { - rctf cameraborder; - ED_view3d_calc_camera_border(scene, ar, v3d, rv3d, &cameraborder, false); - rv3d->viewcamtexcofac[0] = (float)ar->winx / BLI_rctf_size_x(&cameraborder); - rv3d->viewcamtexcofac[1] = (float)ar->winy / BLI_rctf_size_y(&cameraborder); - - rv3d->viewcamtexcofac[2] = -rv3d->viewcamtexcofac[0] * cameraborder.xmin / (float)ar->winx; - rv3d->viewcamtexcofac[3] = -rv3d->viewcamtexcofac[1] * cameraborder.ymin / (float)ar->winy; - } - else { - rv3d->viewcamtexcofac[0] = rv3d->viewcamtexcofac[1] = 1.0f; - rv3d->viewcamtexcofac[2] = rv3d->viewcamtexcofac[3] = 0.0f; - } +static void view3d_draw_grid(const bContext *C, ARegion *ar) +{ + /* TODO viewport + * Missing is the flags to check whether to draw it + * for now now we are using the flags in v3d itself. + * + * Also for now always assume depth is there, so we + * draw on top of it. + */ /** * Calculate pixel-size factor once, is used for lamps and object centers. * Used by #ED_view3d_pixel_size and typically not accessed directly. @@ -2703,1359 +1472,995 @@ void ED_view3d_update_viewmat(Scene *scene, View3D *v3d, ARegion *ar, float view * * 'RegionView3D.pixsize' is used for viewport drawing, not rendering. */ - { - /* note: '1.0f / len_v3(v1)' replaced 'len_v3(rv3d->viewmat[0])' - * because of float point precision problems at large values [#23908] */ - float v1[3], v2[3]; - float len_px, len_sc; - - v1[0] = rv3d->persmat[0][0]; - v1[1] = rv3d->persmat[1][0]; - v1[2] = rv3d->persmat[2][0]; - - v2[0] = rv3d->persmat[0][1]; - v2[1] = rv3d->persmat[1][1]; - v2[2] = rv3d->persmat[2][1]; - - len_px = 2.0f / sqrtf(min_ff(len_squared_v3(v1), len_squared_v3(v2))); - len_sc = (float)MAX2(ar->winx, ar->winy); - - rv3d->pixsize = len_px / len_sc; - } -} - -/** - * Shared by #ED_view3d_draw_offscreen and #view3d_main_region_draw_objects - * - * \note \a C and \a grid_unit will be NULL when \a draw_offscreen is set. - * \note Drawing lamps and opengl render uses this, so dont do grease pencil or view widgets here. - */ -static void view3d_draw_objects( - const bContext *C, - Scene *scene, View3D *v3d, ARegion *ar, - const char **grid_unit, - const bool do_bgpic, const bool draw_offscreen, GPUFX *fx) -{ + Scene *scene = CTX_data_scene(C); + View3D *v3d = CTX_wm_view3d(C); RegionView3D *rv3d = ar->regiondata; - Base *base; - const bool do_camera_frame = !draw_offscreen; - const bool draw_grids = !draw_offscreen && (v3d->flag2 & V3D_RENDER_OVERRIDE) == 0; + const bool draw_floor = (rv3d->view == RV3D_VIEW_USER) || (rv3d->persp != RV3D_ORTHO); - /* only draw grids after in solid modes, else it hovers over mesh wires */ - const bool draw_grids_after = draw_grids && draw_floor && (v3d->drawtype > OB_WIRE) && fx; - bool do_composite_xray = false; - bool xrayclear = true; + const char *grid_unit = NULL; - if (!draw_offscreen) { - ED_region_draw_cb_draw(C, ar, REGION_DRAW_PRE_VIEW); - } + /* ortho grid goes first, does not write to depth buffer and doesn't need depth test so it will override + * objects if done last + * needs to be done always, gridview is adjusted in drawgrid() now, but only for ortho views. + */ + rv3d->gridview = ED_view3d_grid_scale(scene, v3d, &grid_unit); - if (rv3d->rflag & RV3D_CLIPPING) - view3d_draw_clipping(rv3d); + glEnable(GL_DEPTH_TEST); + glDepthMask(GL_FALSE); /* read & test depth, but don't alter it. TODO: separate UI depth buffer */ - /* set zbuffer after we draw clipping region */ - if (v3d->drawtype > OB_WIRE) { - v3d->zbuf = true; + if (!draw_floor) { + ED_region_pixelspace(ar); + *(&grid_unit) = NULL; /* drawgrid need this to detect/affect smallest valid unit... */ + drawgrid(&scene->unit, ar, v3d, &grid_unit); + + glMatrixMode(GL_PROJECTION); + glLoadMatrixf(rv3d->winmat); + glMatrixMode(GL_MODELVIEW); + glLoadMatrixf(rv3d->viewmat); } else { - v3d->zbuf = false; + drawfloor(scene, v3d, &grid_unit, false); } - /* special case (depth for wire color) */ - if (v3d->drawtype <= OB_WIRE) { - if (scene->obedit && scene->obedit->type == OB_MESH) { - Mesh *me = scene->obedit->data; - if (me->drawflag & ME_DRAWEIGHT) { - v3d->zbuf = true; - } - } - } + glDisable(GL_DEPTH_TEST); +} - if (v3d->zbuf) { - glEnable(GL_DEPTH_TEST); - } +static bool is_cursor_visible(Scene *scene) +{ + Object *ob = OBACT; - /* ortho grid goes first, does not write to depth buffer and doesn't need depth test so it will override - * objects if done last */ - if (draw_grids) { - /* needs to be done always, gridview is adjusted in drawgrid() now, but only for ortho views. */ - rv3d->gridview = ED_view3d_grid_scale(scene, v3d, grid_unit); - - if (!draw_floor) { - ED_region_pixelspace(ar); - *grid_unit = NULL; /* drawgrid need this to detect/affect smallest valid unit... */ - drawgrid(&scene->unit, ar, v3d, grid_unit); - /* XXX make function? replaces persp(1) */ - glMatrixMode(GL_PROJECTION); - glLoadMatrixf(rv3d->winmat); - glMatrixMode(GL_MODELVIEW); - glLoadMatrixf(rv3d->viewmat); - } - else if (!draw_grids_after) { - drawfloor(scene, v3d, grid_unit, true); + /* don't draw cursor in paint modes, but with a few exceptions */ + if (ob && ob->mode & OB_MODE_ALL_PAINT) { + /* exception: object is in weight paint and has deforming armature in pose mode */ + if (ob->mode & OB_MODE_WEIGHT_PAINT) { + if (BKE_object_pose_armature_get(ob) != NULL) { + return true; + } } - } - - /* important to do before clipping */ - if (do_bgpic) { - view3d_draw_bgpic_test(scene, ar, v3d, false, do_camera_frame); - } - - if (rv3d->rflag & RV3D_CLIPPING) { - ED_view3d_clipping_set(rv3d); - } - - /* draw set first */ - if (scene->set) { - const short dflag = DRAW_CONSTCOLOR | DRAW_SCENESET; - Scene *sce_iter; - for (SETLOOPER(scene->set, sce_iter, base)) { - if (v3d->lay & base->lay) { - UI_ThemeColorBlend(TH_WIRE, TH_BACK, 0.6f); - draw_object(scene, ar, v3d, base, dflag); + /* exception: object in texture paint mode, clone brush, use_clone_layer disabled */ + else if (ob->mode & OB_MODE_TEXTURE_PAINT) { + const Paint *p = BKE_paint_get_active(scene); - if (base->object->transflag & OB_DUPLI) { - draw_dupli_objects_color(scene, ar, v3d, base, dflag, TH_UNDEFINED); + if (p && p->brush && p->brush->imagepaint_tool == PAINT_TOOL_CLONE) { + if ((scene->toolsettings->imapaint.flag & IMAGEPAINT_PROJECT_LAYER_CLONE) == 0) { + return true; } } } - /* Transp and X-ray afterdraw stuff for sets is done later */ - } - - - if (draw_offscreen) { - for (base = scene->base.first; base; base = base->next) { - if (v3d->lay & base->lay) { - /* dupli drawing */ - if (base->object->transflag & OB_DUPLI) - draw_dupli_objects(scene, ar, v3d, base); - - draw_object(scene, ar, v3d, base, 0); - } - } + /* no exception met? then don't draw cursor! */ + return false; } - else { - unsigned int lay_used = 0; - /* then draw not selected and the duplis, but skip editmode object */ - for (base = scene->base.first; base; base = base->next) { - lay_used |= base->lay; - - if (v3d->lay & base->lay) { + return true; +} - /* dupli drawing */ - if (base->object->transflag & OB_DUPLI) { - draw_dupli_objects(scene, ar, v3d, base); - } - if ((base->flag & SELECT) == 0) { - if (base->object != scene->obedit) - draw_object(scene, ar, v3d, base, 0); - } - } - } +static void drawcursor(Scene *scene, ARegion *ar, View3D *v3d) +{ + int co[2]; - /* mask out localview */ - v3d->lay_used = lay_used & ((1 << 20) - 1); + /* we don't want the clipping for cursor */ + if (ED_view3d_project_int_global(ar, ED_view3d_cursor3d_get(scene, v3d), co, V3D_PROJ_TEST_NOP) == V3D_PROJ_RET_OK) { + const float f5 = 0.25f * U.widget_unit; + const float f10 = 0.5f * U.widget_unit; + const float f20 = U.widget_unit; + + glLineWidth(1.0f); - /* draw selected and editmode */ - for (base = scene->base.first; base; base = base->next) { - if (v3d->lay & base->lay) { - if (base->object == scene->obedit || (base->flag & SELECT)) { - draw_object(scene, ar, v3d, base, 0); - } - } - } - } + VertexFormat *format = immVertexFormat(); + unsigned int pos = add_attrib(format, "pos", COMP_F32, 2, KEEP_FLOAT); + unsigned int color = add_attrib(format, "color", COMP_U8, 3, NORMALIZE_INT_TO_FLOAT); - /* perspective floor goes last to use scene depth and avoid writing to depth buffer */ - if (draw_grids_after) { - drawfloor(scene, v3d, grid_unit, false); - } + immBindBuiltinProgram(GPU_SHADER_2D_FLAT_COLOR); - /* must be before xray draw which clears the depth buffer */ - if (v3d->flag2 & V3D_SHOW_GPENCIL) { - wmWindowManager *wm = (C != NULL) ? CTX_wm_manager(C) : NULL; - - /* must be before xray draw which clears the depth buffer */ - if (v3d->zbuf) glDisable(GL_DEPTH_TEST); - ED_gpencil_draw_view3d(wm, scene, v3d, ar, true); - if (v3d->zbuf) glEnable(GL_DEPTH_TEST); - } + const int segments = 16; - /* transp and X-ray afterdraw stuff */ - if (v3d->afterdraw_transp.first) view3d_draw_transp(scene, ar, v3d); + immBegin(GL_LINE_LOOP, segments); - /* always do that here to cleanup depth buffers if none needed */ - if (fx) { - do_composite_xray = v3d->zbuf && (v3d->afterdraw_xray.first || v3d->afterdraw_xraytransp.first); - GPU_fx_compositor_setup_XRay_pass(fx, do_composite_xray); - } + for (int i = 0; i < segments; ++i) { + float angle = 2 * M_PI * ((float)i / (float)segments); + float x = co[0] + f10 * cosf(angle); + float y = co[1] + f10 * sinf(angle); - if (v3d->afterdraw_xray.first) view3d_draw_xray(scene, ar, v3d, &xrayclear); - if (v3d->afterdraw_xraytransp.first) view3d_draw_xraytransp(scene, ar, v3d, xrayclear); + if (i % 2 == 0) + immAttrib3ub(color, 255, 0, 0); + else + immAttrib3ub(color, 255, 255, 255); - if (fx && do_composite_xray) { - GPU_fx_compositor_XRay_resolve(fx); - } + immVertex2f(pos, x, y); + } + immEnd(); - if (!draw_offscreen) { - ED_region_draw_cb_draw(C, ar, REGION_DRAW_POST_VIEW); - } + immUnbindProgram(); - if (rv3d->rflag & RV3D_CLIPPING) - ED_view3d_clipping_disable(); + VertexFormat_clear(format); + pos = add_attrib(format, "pos", COMP_F32, 2, KEEP_FLOAT); - /* important to do after clipping */ - if (do_bgpic) { - view3d_draw_bgpic_test(scene, ar, v3d, true, do_camera_frame); - } + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); - if (!draw_offscreen) { - BIF_draw_manipulator(C); - } + unsigned char crosshair_color[3]; + UI_GetThemeColor3ubv(TH_VIEW_OVERLAY, crosshair_color); + immUniformColor3ubv(crosshair_color); - /* cleanup */ - if (v3d->zbuf) { - v3d->zbuf = false; - glDisable(GL_DEPTH_TEST); - } + immBegin(GL_LINES, 8); + immVertex2f(pos, co[0] - f20, co[1]); + immVertex2f(pos, co[0] - f5, co[1]); + immVertex2f(pos, co[0] + f5, co[1]); + immVertex2f(pos, co[0] + f20, co[1]); + immVertex2f(pos, co[0], co[1] - f20); + immVertex2f(pos, co[0], co[1] - f5); + immVertex2f(pos, co[0], co[1] + f5); + immVertex2f(pos, co[0], co[1] + f20); + immEnd(); - if ((v3d->flag2 & V3D_RENDER_SHADOW) == 0) { - GPU_free_images_old(); + immUnbindProgram(); } } -static void view3d_main_region_setup_view(Scene *scene, View3D *v3d, ARegion *ar, float viewmat[4][4], float winmat[4][4]) +static void draw_view_axis(RegionView3D *rv3d, rcti *rect) { - RegionView3D *rv3d = ar->regiondata; + const float k = U.rvisize * U.pixelsize; /* axis size */ + const int bright = - 20 * (10 - U.rvibright); /* axis alpha offset (rvibright has range 0-10) */ - ED_view3d_update_viewmat(scene, v3d, ar, viewmat, winmat); + const float startx = rect->xmin + k + 1.0f; /* axis center in screen coordinates, x=y */ + const float starty = rect->ymin + k + 1.0f; - /* set for opengl */ - glMatrixMode(GL_PROJECTION); - glLoadMatrixf(rv3d->winmat); - glMatrixMode(GL_MODELVIEW); - glLoadMatrixf(rv3d->viewmat); -} + float axis_pos[3][2]; + unsigned char axis_col[3][4]; -/** - * Store values from #RegionView3D, set when drawing. - * This is needed when we draw with to a viewport using a different matrix (offscreen drawing for example). - * - * Values set by #ED_view3d_update_viewmat should be handled here. - */ -struct RV3DMatrixStore { - float winmat[4][4]; - float viewmat[4][4]; - float viewinv[4][4]; - float persmat[4][4]; - float persinv[4][4]; - float viewcamtexcofac[4]; - float pixsize; -}; + int axis_order[3] = {0, 1, 2}; + axis_sort_v3(rv3d->viewinv[2], axis_order); -void *ED_view3d_mats_rv3d_backup(struct RegionView3D *rv3d) -{ - struct RV3DMatrixStore *rv3dmat = MEM_mallocN(sizeof(*rv3dmat), __func__); - copy_m4_m4(rv3dmat->winmat, rv3d->winmat); - copy_m4_m4(rv3dmat->viewmat, rv3d->viewmat); - copy_m4_m4(rv3dmat->persmat, rv3d->persmat); - copy_m4_m4(rv3dmat->persinv, rv3d->persinv); - copy_m4_m4(rv3dmat->viewinv, rv3d->viewinv); - copy_v4_v4(rv3dmat->viewcamtexcofac, rv3d->viewcamtexcofac); - rv3dmat->pixsize = rv3d->pixsize; - return (void *)rv3dmat; -} + for (int axis_i = 0; axis_i < 3; axis_i++) { + int i = axis_order[axis_i]; -void ED_view3d_mats_rv3d_restore(struct RegionView3D *rv3d, void *rv3dmat_pt) -{ - struct RV3DMatrixStore *rv3dmat = rv3dmat_pt; - copy_m4_m4(rv3d->winmat, rv3dmat->winmat); - copy_m4_m4(rv3d->viewmat, rv3dmat->viewmat); - copy_m4_m4(rv3d->persmat, rv3dmat->persmat); - copy_m4_m4(rv3d->persinv, rv3dmat->persinv); - copy_m4_m4(rv3d->viewinv, rv3dmat->viewinv); - copy_v4_v4(rv3d->viewcamtexcofac, rv3dmat->viewcamtexcofac); - rv3d->pixsize = rv3dmat->pixsize; -} + /* get position of each axis tip on screen */ + float vec[3] = { 0.0f }; + vec[i] = 1.0f; + mul_qt_v3(rv3d->viewquat, vec); + axis_pos[i][0] = startx + vec[0] * k; + axis_pos[i][1] = starty + vec[1] * k; -void ED_view3d_draw_offscreen_init(Scene *scene, View3D *v3d) -{ - /* shadow buffers, before we setup matrices */ - if (draw_glsl_material(scene, NULL, v3d, v3d->drawtype)) - gpu_update_lamps_shadows_world(scene, v3d); -} + /* get color of each axis */ + UI_GetThemeColorShade3ubv(TH_AXIS_X + i, bright, axis_col[i]); /* rgb */ + axis_col[i][3] = 255 * hypotf(vec[0], vec[1]); /* alpha */ + } -/* - * Function to clear the view - */ -static void view3d_main_region_clear(Scene *scene, View3D *v3d, ARegion *ar) -{ - if (scene->world && (v3d->flag3 & V3D_SHOW_WORLD)) { - RegionView3D *rv3d = ar->regiondata; - GPUMaterial *gpumat = GPU_material_world(scene, scene->world); + /* draw axis lines */ + glLineWidth(2.0f); + glEnable(GL_LINE_SMOOTH); + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - /* calculate full shader for background */ - GPU_material_bind(gpumat, 1, 1, 1.0, false, rv3d->viewmat, rv3d->viewinv, rv3d->viewcamtexcofac, (v3d->scenelock != 0)); - - bool material_not_bound = !GPU_material_bound(gpumat); - - if (material_not_bound) { - glMatrixMode(GL_PROJECTION); - glPushMatrix(); - glLoadIdentity(); - glMatrixMode(GL_MODELVIEW); - glPushMatrix(); - glLoadIdentity(); - glColor4f(0.0f, 0.0f, 0.0f, 1.0f); - } + VertexFormat *format = immVertexFormat(); + unsigned pos = add_attrib(format, "pos", COMP_F32, 2, KEEP_FLOAT); + unsigned col = add_attrib(format, "color", COMP_U8, 4, NORMALIZE_INT_TO_FLOAT); - /* Draw world */ - glEnable(GL_DEPTH_TEST); - glDepthFunc(GL_ALWAYS); - glBegin(GL_TRIANGLE_STRIP); - glVertex3f(-1.0, -1.0, 1.0); - glVertex3f(1.0, -1.0, 1.0); - glVertex3f(-1.0, 1.0, 1.0); - glVertex3f(1.0, 1.0, 1.0); - glEnd(); - - if (material_not_bound) { - glMatrixMode(GL_PROJECTION); - glPopMatrix(); - glMatrixMode(GL_MODELVIEW); - glPopMatrix(); - } + immBindBuiltinProgram(GPU_SHADER_2D_FLAT_COLOR); + immBegin(GL_LINES, 6); - GPU_material_unbind(gpumat); - - glDepthFunc(GL_LEQUAL); - glDisable(GL_DEPTH_TEST); + for (int axis_i = 0; axis_i < 3; axis_i++) { + int i = axis_order[axis_i]; + + immAttrib4ubv(col, axis_col[i]); + immVertex2f(pos, startx, starty); + immVertex2fv(pos, axis_pos[i]); } - else { - if (UI_GetThemeValue(TH_SHOW_BACK_GRAD)) { - glMatrixMode(GL_PROJECTION); - glPushMatrix(); - glLoadIdentity(); - glMatrixMode(GL_MODELVIEW); - glPushMatrix(); - glLoadIdentity(); - - glEnable(GL_DEPTH_TEST); - glDepthFunc(GL_ALWAYS); - glBegin(GL_QUADS); - UI_ThemeColor(TH_LOW_GRAD); - glVertex3f(-1.0, -1.0, 1.0); - glVertex3f(1.0, -1.0, 1.0); - UI_ThemeColor(TH_HIGH_GRAD); - glVertex3f(1.0, 1.0, 1.0); - glVertex3f(-1.0, 1.0, 1.0); - glEnd(); - glDepthFunc(GL_LEQUAL); - glDisable(GL_DEPTH_TEST); - glMatrixMode(GL_PROJECTION); - glPopMatrix(); + immEnd(); + immUnbindProgram(); + glDisable(GL_LINE_SMOOTH); - glMatrixMode(GL_MODELVIEW); - glPopMatrix(); - } - else { - UI_ThemeClearColorAlpha(TH_HIGH_GRAD, 1.0f); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - } + /* draw axis names */ + for (int axis_i = 0; axis_i < 3; axis_i++) { + int i = axis_order[axis_i]; + + const char axis_text[2] = {'x' + i, '\0'}; + BLF_color4ubv(BLF_default(), axis_col[i]); + BLF_draw_default_ascii(axis_pos[i][0] + 2, axis_pos[i][1] + 2, 0.0f, axis_text, 1); } + + /* BLF_draw disabled blending for us */ } -/* ED_view3d_draw_offscreen_init should be called before this to initialize - * stuff like shadow buffers - */ -void ED_view3d_draw_offscreen( - Scene *scene, View3D *v3d, ARegion *ar, int winx, int winy, - float viewmat[4][4], float winmat[4][4], - bool do_bgpic, bool do_sky, bool is_persp, const char *viewname, - GPUFX *fx, GPUFXSettings *fx_settings, - GPUOffScreen *ofs) -{ - struct bThemeState theme_state; - int bwinx, bwiny; - rcti brect; - bool do_compositing = false; - RegionView3D *rv3d = ar->regiondata; +#ifdef WITH_INPUT_NDOF +/* draw center and axis of rotation for ongoing 3D mouse navigation */ +static void draw_rotation_guide(RegionView3D *rv3d) +{ + float o[3]; /* center of rotation */ + float end[3]; /* endpoints for drawing */ - glPushMatrix(); + GLubyte color[4] = {0, 108, 255, 255}; /* bright blue so it matches device LEDs */ - /* set temporary new size */ - bwinx = ar->winx; - bwiny = ar->winy; - brect = ar->winrct; + negate_v3_v3(o, rv3d->ofs); - ar->winx = winx; - ar->winy = winy; - ar->winrct.xmin = 0; - ar->winrct.ymin = 0; - ar->winrct.xmax = winx; - ar->winrct.ymax = winy; + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glPointSize(5.0f); + glEnable(GL_POINT_SMOOTH); + glDepthMask(GL_FALSE); /* don't overwrite zbuf */ - UI_Theme_Store(&theme_state); - UI_SetTheme(SPACE_VIEW3D, RGN_TYPE_WINDOW); + VertexFormat *format = immVertexFormat(); + unsigned pos = add_attrib(format, "pos", COMP_F32, 3, KEEP_FLOAT); + unsigned col = add_attrib(format, "color", COMP_U8, 4, NORMALIZE_INT_TO_FLOAT); - /* set flags */ - G.f |= G_RENDER_OGL; + immBindBuiltinProgram(GPU_SHADER_3D_SMOOTH_COLOR); - if ((v3d->flag2 & V3D_RENDER_SHADOW) == 0) { - /* free images which can have changed on frame-change - * warning! can be slow so only free animated images - campbell */ - GPU_free_images_anim(); - } + if (rv3d->rot_angle != 0.0f) { + /* -- draw rotation axis -- */ + float scaled_axis[3]; + const float scale = rv3d->dist; + mul_v3_v3fl(scaled_axis, rv3d->rot_axis, scale); - /* setup view matrices before fx or unbinding the offscreen buffers will cause issues */ - if ((viewname != NULL && viewname[0] != '\0') && (viewmat == NULL) && rv3d->persp == RV3D_CAMOB && v3d->camera) - view3d_stereo3d_setup_offscreen(scene, v3d, ar, winmat, viewname); - else - view3d_main_region_setup_view(scene, v3d, ar, viewmat, winmat); - /* framebuffer fx needed, we need to draw offscreen first */ - if (v3d->fx_settings.fx_flag && fx) { - GPUSSAOSettings *ssao = NULL; + immBegin(GL_LINE_STRIP, 3); + color[3] = 0; /* more transparent toward the ends */ + immAttrib4ubv(col, color); + add_v3_v3v3(end, o, scaled_axis); + immVertex3fv(pos, end); - if (v3d->drawtype < OB_SOLID) { - ssao = v3d->fx_settings.ssao; - v3d->fx_settings.ssao = NULL; - } +#if 0 + color[3] = 0.2f + fabsf(rv3d->rot_angle); /* modulate opacity with angle */ + /* ^^ neat idea, but angle is frame-rate dependent, so it's usually close to 0.2 */ +#endif - do_compositing = GPU_fx_compositor_initialize_passes(fx, &ar->winrct, NULL, fx_settings); + color[3] = 127; /* more opaque toward the center */ + immAttrib4ubv(col, color); + immVertex3fv(pos, o); - if (ssao) - v3d->fx_settings.ssao = ssao; - } + color[3] = 0; + immAttrib4ubv(col, color); + sub_v3_v3v3(end, o, scaled_axis); + immVertex3fv(pos, end); + immEnd(); + + /* -- draw ring around rotation center -- */ + { +#define ROT_AXIS_DETAIL 13 - /* clear opengl buffers */ - if (do_sky) { - view3d_main_region_clear(scene, v3d, ar); - } - else { - glClearColor(0.0f, 0.0f, 0.0f, 0.0f); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - } + const float s = 0.05f * scale; + const float step = 2.0f * (float)(M_PI / ROT_AXIS_DETAIL); - /* main drawing call */ - view3d_draw_objects(NULL, scene, v3d, ar, NULL, do_bgpic, true, do_compositing ? fx : NULL); + float q[4]; /* rotate ring so it's perpendicular to axis */ + const int upright = fabsf(rv3d->rot_axis[2]) >= 0.95f; + if (!upright) { + const float up[3] = {0.0f, 0.0f, 1.0f}; + float vis_angle, vis_axis[3]; - /* post process */ - if (do_compositing) { - if (!winmat) - is_persp = rv3d->is_persp; - GPU_fx_do_composite_pass(fx, winmat, is_persp, scene, ofs); - } + cross_v3_v3v3(vis_axis, up, rv3d->rot_axis); + vis_angle = acosf(dot_v3v3(up, rv3d->rot_axis)); + axis_angle_to_quat(q, vis_axis, vis_angle); + } - if ((v3d->flag2 & V3D_RENDER_SHADOW) == 0) { - /* draw grease-pencil stuff */ - ED_region_pixelspace(ar); + immBegin(GL_LINE_LOOP, ROT_AXIS_DETAIL); + color[3] = 63; /* somewhat faint */ + immAttrib4ubv(col, color); + float angle = 0.0f; + for (int i = 0; i < ROT_AXIS_DETAIL; ++i, angle += step) { + float p[3] = {s * cosf(angle), s * sinf(angle), 0.0f}; + + if (!upright) { + mul_qt_v3(q, p); + } + add_v3_v3(p, o); + immVertex3fv(pos, p); + } + immEnd(); - if (v3d->flag2 & V3D_SHOW_GPENCIL) { - /* draw grease-pencil stuff - needed to get paint-buffer shown too (since it's 2D) */ - ED_gpencil_draw_view3d(NULL, scene, v3d, ar, false); +#undef ROT_AXIS_DETAIL } - /* freeing the images again here could be done after the operator runs, leaving for now */ - GPU_free_images_anim(); + color[3] = 255; /* solid dot */ } + else + color[3] = 127; /* see-through dot */ - /* restore size */ - ar->winx = bwinx; - ar->winy = bwiny; - ar->winrct = brect; - - glPopMatrix(); + /* -- draw rotation center -- */ + immBegin(GL_POINTS, 1); + immAttrib4ubv(col, color); + immVertex3fv(pos, o); + immEnd(); + immUnbindProgram(); - UI_Theme_Restore(&theme_state); +#if 0 + /* find screen coordinates for rotation center, then draw pretty icon */ + mul_m4_v3(rv3d->persinv, rot_center); + UI_icon_draw(rot_center[0], rot_center[1], ICON_NDOF_TURN); + /* ^^ just playing around, does not work */ +#endif - G.f &= ~G_RENDER_OGL; + glDisable(GL_BLEND); + glDisable(GL_POINT_SMOOTH); + glDepthMask(GL_TRUE); } +#endif /* WITH_INPUT_NDOF */ -/** - * Utility func for ED_view3d_draw_offscreen - * - * \param ofs: Optional off-screen buffer, can be NULL. - * (avoids re-creating when doing multiple GL renders). - */ -ImBuf *ED_view3d_draw_offscreen_imbuf( - Scene *scene, View3D *v3d, ARegion *ar, int sizex, int sizey, - unsigned int flag, bool draw_background, - int alpha_mode, int samples, bool full_samples, const char *viewname, - /* output vars */ - GPUFX *fx, GPUOffScreen *ofs, char err_out[256]) -{ - RegionView3D *rv3d = ar->regiondata; - ImBuf *ibuf; - const bool draw_sky = (alpha_mode == R_ADDSKY); +/* ******************** non-meshes ***************** */ - /* view state */ - GPUFXSettings fx_settings = v3d->fx_settings; - bool is_ortho = false; - float winmat[4][4]; +static void view3d_draw_non_mesh( +Scene *scene, SceneLayer *sl, Object *ob, Base *base, View3D *v3d, +RegionView3D *rv3d, const bool is_boundingbox, const unsigned char color[4]) +{ + glMatrixMode(GL_PROJECTION); + glPushMatrix(); + glMatrixMode(GL_MODELVIEW); + glPushMatrix(); - if (ofs && ((GPU_offscreen_width(ofs) != sizex) || (GPU_offscreen_height(ofs) != sizey))) { - /* sizes differ, can't reuse */ - ofs = NULL; + /* multiply view with object matrix. + * local viewmat and persmat, to calculate projections */ + ED_view3d_init_mats_rv3d_gl(ob, rv3d); + + switch (ob->type) { + case OB_MESH: + case OB_FONT: + case OB_CURVE: + case OB_SURF: + case OB_MBALL: + if (is_boundingbox) { + draw_bounding_volume(ob, ob->boundtype); + } + break; + case OB_EMPTY: + drawaxes(rv3d->viewmatob, ob->empty_drawsize, ob->empty_drawtype, color); + break; + case OB_LAMP: + drawlamp(v3d, rv3d, base, OB_SOLID, DRAW_CONSTCOLOR, color, ob == OBACT_NEW); + break; + case OB_CAMERA: + drawcamera(scene, v3d, rv3d, base, DRAW_CONSTCOLOR, color); + break; + case OB_SPEAKER: + drawspeaker(color); + break; + case OB_LATTICE: + /* TODO */ + break; + case OB_ARMATURE: + /* TODO */ + break; + default: + /* TODO Viewport: handle the other cases*/ + break; } - const bool own_ofs = (ofs == NULL); - - if (own_ofs) { - /* bind */ - ofs = GPU_offscreen_create(sizex, sizey, full_samples ? 0 : samples, err_out); - if (ofs == NULL) { - return NULL; - } + if (ob->rigidbody_object) { + draw_rigidbody_shape(ob); } - ED_view3d_draw_offscreen_init(scene, v3d); - - GPU_offscreen_bind(ofs, true); + ED_view3d_clear_mats_rv3d(rv3d); - /* read in pixels & stamp */ - ibuf = IMB_allocImBuf(sizex, sizey, 32, flag); - - /* render 3d view */ - if (rv3d->persp == RV3D_CAMOB && v3d->camera) { - CameraParams params; - Object *camera = BKE_camera_multiview_render(scene, v3d->camera, viewname); + glMatrixMode(GL_PROJECTION); + glPopMatrix(); + glMatrixMode(GL_MODELVIEW); + glPopMatrix(); +} - BKE_camera_params_init(¶ms); - /* fallback for non camera objects */ - params.clipsta = v3d->near; - params.clipend = v3d->far; - BKE_camera_params_from_object(¶ms, camera); - BKE_camera_multiview_params(&scene->r, ¶ms, camera, viewname); - BKE_camera_params_compute_viewplane(¶ms, sizex, sizey, scene->r.xasp, scene->r.yasp); - BKE_camera_params_compute_matrix(¶ms); +/* ******************** info ***************** */ - BKE_camera_to_gpu_dof(camera, &fx_settings); +/** +* Render and camera border +*/ +static void view3d_draw_border(const bContext *C, ARegion *ar) +{ + Scene *scene = CTX_data_scene(C); + RegionView3D *rv3d = ar->regiondata; + View3D *v3d = CTX_wm_view3d(C); - is_ortho = params.is_ortho; - copy_m4_m4(winmat, params.winmat); + if (rv3d->persp == RV3D_CAMOB) { + drawviewborder(scene, ar, v3d); } - else { - rctf viewplane; - float clipsta, clipend; - - is_ortho = ED_view3d_viewplane_get(v3d, rv3d, sizex, sizey, &viewplane, &clipsta, &clipend, NULL); - if (is_ortho) { - orthographic_m4(winmat, viewplane.xmin, viewplane.xmax, viewplane.ymin, viewplane.ymax, -clipend, clipend); - } - else { - perspective_m4(winmat, viewplane.xmin, viewplane.xmax, viewplane.ymin, viewplane.ymax, clipsta, clipend); - } + else if (v3d->flag2 & V3D_RENDER_BORDER) { + drawrenderborder(ar, v3d); } +} - if ((samples && full_samples) == 0) { - /* Single-pass render, common case */ - ED_view3d_draw_offscreen( - scene, v3d, ar, sizex, sizey, NULL, winmat, - draw_background, draw_sky, !is_ortho, viewname, - fx, &fx_settings, ofs); +/** +* Grease Pencil +*/ +static void view3d_draw_grease_pencil(const bContext *UNUSED(C)) +{ + /* TODO viewport */ +} - if (ibuf->rect_float) { - GPU_offscreen_read_pixels(ofs, GL_FLOAT, ibuf->rect_float); - } - else if (ibuf->rect) { - GPU_offscreen_read_pixels(ofs, GL_UNSIGNED_BYTE, ibuf->rect); - } - } - else { - /* Multi-pass render, use accumulation buffer & jitter for 'full' oversampling. - * Use because OpenGL may use a lower quality MSAA, and only over-sample edges. */ - static float jit_ofs[32][2]; - float winmat_jitter[4][4]; - /* use imbuf as temp storage, before writing into it from accumulation buffer */ - unsigned char *rect_temp = ibuf->rect ? (void *)ibuf->rect : (void *)ibuf->rect_float; - unsigned int *accum_buffer = MEM_mallocN(sizex * sizey * sizeof(int[4]), "accum1"); - unsigned int i; - int j; - - BLI_jitter_init(jit_ofs, samples); - - /* first sample buffer, also initializes 'rv3d->persmat' */ - ED_view3d_draw_offscreen( - scene, v3d, ar, sizex, sizey, NULL, winmat, - draw_background, draw_sky, !is_ortho, viewname, - fx, &fx_settings, ofs); - GPU_offscreen_read_pixels(ofs, GL_UNSIGNED_BYTE, rect_temp); - - i = sizex * sizey * 4; - while (i--) { - accum_buffer[i] = rect_temp[i]; - } - /* skip the first sample */ - for (j = 1; j < samples; j++) { - copy_m4_m4(winmat_jitter, winmat); - window_translate_m4( - winmat_jitter, rv3d->persmat, - (jit_ofs[j][0] * 2.0f) / sizex, - (jit_ofs[j][1] * 2.0f) / sizey); - - ED_view3d_draw_offscreen( - scene, v3d, ar, sizex, sizey, NULL, winmat_jitter, - draw_background, draw_sky, !is_ortho, viewname, - fx, &fx_settings, ofs); - GPU_offscreen_read_pixels(ofs, GL_UNSIGNED_BYTE, rect_temp); - - i = sizex * sizey * 4; - while (i--) { - accum_buffer[i] += rect_temp[i]; - } - } +/** +* Viewport Name +*/ +static const char *view3d_get_name(View3D *v3d, RegionView3D *rv3d) +{ + const char *name = NULL; - if (ibuf->rect_float) { - float *rect_float = ibuf->rect_float; - i = sizex * sizey * 4; - while (i--) { - rect_float[i] = (float)(accum_buffer[i] / samples) * (1.0f / 255.0f); + switch (rv3d->view) { + case RV3D_VIEW_FRONT: + if (rv3d->persp == RV3D_ORTHO) name = IFACE_("Front Ortho"); + else name = IFACE_("Front Persp"); + break; + case RV3D_VIEW_BACK: + if (rv3d->persp == RV3D_ORTHO) name = IFACE_("Back Ortho"); + else name = IFACE_("Back Persp"); + break; + case RV3D_VIEW_TOP: + if (rv3d->persp == RV3D_ORTHO) name = IFACE_("Top Ortho"); + else name = IFACE_("Top Persp"); + break; + case RV3D_VIEW_BOTTOM: + if (rv3d->persp == RV3D_ORTHO) name = IFACE_("Bottom Ortho"); + else name = IFACE_("Bottom Persp"); + break; + case RV3D_VIEW_RIGHT: + if (rv3d->persp == RV3D_ORTHO) name = IFACE_("Right Ortho"); + else name = IFACE_("Right Persp"); + break; + case RV3D_VIEW_LEFT: + if (rv3d->persp == RV3D_ORTHO) name = IFACE_("Left Ortho"); + else name = IFACE_("Left Persp"); + break; + + default: + if (rv3d->persp == RV3D_CAMOB) { + if ((v3d->camera) && (v3d->camera->type == OB_CAMERA)) { + Camera *cam; + cam = v3d->camera->data; + if (cam->type == CAM_PERSP) { + name = IFACE_("Camera Persp"); + } + else if (cam->type == CAM_ORTHO) { + name = IFACE_("Camera Ortho"); + } + else { + BLI_assert(cam->type == CAM_PANO); + name = IFACE_("Camera Pano"); + } + } + else { + name = IFACE_("Object as Camera"); + } } - } - else { - unsigned char *rect_ub = (unsigned char *)ibuf->rect; - i = sizex * sizey * 4; - while (i--) { - rect_ub[i] = accum_buffer[i] / samples; + else { + name = (rv3d->persp == RV3D_ORTHO) ? IFACE_("User Ortho") : IFACE_("User Persp"); } - } - - MEM_freeN(accum_buffer); } - /* unbind */ - GPU_offscreen_unbind(ofs, true); + return name; +} + +static void draw_viewport_name(ARegion *ar, View3D *v3d, rcti *rect) +{ + RegionView3D *rv3d = ar->regiondata; + const char *name = view3d_get_name(v3d, rv3d); + /* increase size for unicode languages (Chinese in utf-8...) */ +#ifdef WITH_INTERNATIONAL + char tmpstr[96]; +#else + char tmpstr[32]; +#endif - if (own_ofs) { - GPU_offscreen_free(ofs); + if (v3d->localvd) { + BLI_snprintf(tmpstr, sizeof(tmpstr), IFACE_("%s (Local)"), name); + name = tmpstr; } - if (ibuf->rect_float && ibuf->rect) - IMB_rect_from_float(ibuf); - - return ibuf; + UI_FontThemeColor(BLF_default(), TH_TEXT_HI); +#ifdef WITH_INTERNATIONAL + BLF_draw_default(U.widget_unit + rect->xmin, rect->ymax - U.widget_unit, 0.0f, name, sizeof(tmpstr)); +#else + BLF_draw_default_ascii(U.widget_unit + rect->xmin, rect->ymax - U.widget_unit, 0.0f, name, sizeof(tmpstr)); +#endif } /** - * Creates own fake 3d views (wrapping #ED_view3d_draw_offscreen_imbuf) - * - * \param ofs: Optional off-screen buffer can be NULL. - * (avoids re-creating when doing multiple GL renders). - * - * \note used by the sequencer + * draw info beside axes in bottom left-corner: + * framenum, object name, bone name (if available), marker name (if available) */ -ImBuf *ED_view3d_draw_offscreen_imbuf_simple( - Scene *scene, Object *camera, int width, int height, - unsigned int flag, int drawtype, bool use_solid_tex, bool use_gpencil, bool draw_background, - int alpha_mode, int samples, bool full_samples, const char *viewname, - GPUFX *fx, GPUOffScreen *ofs, char err_out[256]) -{ - View3D v3d = {NULL}; - ARegion ar = {NULL}; - RegionView3D rv3d = {{{0}}}; - - /* connect data */ - v3d.regionbase.first = v3d.regionbase.last = &ar; - ar.regiondata = &rv3d; - ar.regiontype = RGN_TYPE_WINDOW; - - v3d.camera = camera; - v3d.lay = scene->lay; - v3d.drawtype = drawtype; - v3d.flag2 = V3D_RENDER_OVERRIDE; - - if (use_gpencil) - v3d.flag2 |= V3D_SHOW_GPENCIL; - - if (use_solid_tex) - v3d.flag2 |= V3D_SOLID_TEX; - - if (draw_background) - v3d.flag3 |= V3D_SHOW_WORLD; - rv3d.persp = RV3D_CAMOB; +static void draw_selected_name(Scene *scene, Object *ob, rcti *rect) +{ + const int cfra = CFRA; + const char *msg_pin = " (Pinned)"; + const char *msg_sep = " : "; - copy_m4_m4(rv3d.viewinv, v3d.camera->obmat); - normalize_m4(rv3d.viewinv); - invert_m4_m4(rv3d.viewmat, rv3d.viewinv); + const int font_id = BLF_default(); - { - CameraParams params; - Object *view_camera = BKE_camera_multiview_render(scene, v3d.camera, viewname); + char info[300]; + char *s = info; + short offset = 1.5f * UI_UNIT_X + rect->xmin; - BKE_camera_params_init(¶ms); - BKE_camera_params_from_object(¶ms, view_camera); - BKE_camera_multiview_params(&scene->r, ¶ms, view_camera, viewname); - BKE_camera_params_compute_viewplane(¶ms, width, height, scene->r.xasp, scene->r.yasp); - BKE_camera_params_compute_matrix(¶ms); + s += sprintf(s, "(%d)", cfra); - copy_m4_m4(rv3d.winmat, params.winmat); - v3d.near = params.clipsta; - v3d.far = params.clipend; - v3d.lens = params.lens; - } + /* + * info can contain: + * - a frame (7 + 2) + * - 3 object names (MAX_NAME) + * - 2 BREAD_CRUMB_SEPARATORs (6) + * - a SHAPE_KEY_PINNED marker and a trailing '\0' (9+1) - translated, so give some room! + * - a marker name (MAX_NAME + 3) + */ - mul_m4_m4m4(rv3d.persmat, rv3d.winmat, rv3d.viewmat); - invert_m4_m4(rv3d.persinv, rv3d.viewinv); + /* get name of marker on current frame (if available) */ + const char *markern = BKE_scene_find_marker_name(scene, cfra); - return ED_view3d_draw_offscreen_imbuf( - scene, &v3d, &ar, width, height, flag, - draw_background, alpha_mode, samples, full_samples, viewname, - fx, ofs, err_out); -} + /* check if there is an object */ + if (ob) { + *s++ = ' '; + s += BLI_strcpy_rlen(s, ob->id.name + 2); + /* name(s) to display depends on type of object */ + if (ob->type == OB_ARMATURE) { + bArmature *arm = ob->data; -/** - * \note The info that this uses is updated in #ED_refresh_viewport_fps, - * which currently gets called during #SCREEN_OT_animation_step. - */ -void ED_scene_draw_fps(Scene *scene, const rcti *rect) -{ - ScreenFrameRateInfo *fpsi = scene->fps_info; - float fps; - char printable[16]; - int i, tot; - - if (!fpsi || !fpsi->lredrawtime || !fpsi->redrawtime) - return; - - printable[0] = '\0'; - -#if 0 - /* this is too simple, better do an average */ - fps = (float)(1.0 / (fpsi->lredrawtime - fpsi->redrawtime)) -#else - fpsi->redrawtimes_fps[fpsi->redrawtime_index] = (float)(1.0 / (fpsi->lredrawtime - fpsi->redrawtime)); - - for (i = 0, tot = 0, fps = 0.0f; i < REDRAW_FRAME_AVERAGE; i++) { - if (fpsi->redrawtimes_fps[i]) { - fps += fpsi->redrawtimes_fps[i]; - tot++; + /* show name of active bone too (if possible) */ + if (arm->edbo) { + if (arm->act_edbone) { + s += BLI_strcpy_rlen(s, msg_sep); + s += BLI_strcpy_rlen(s, arm->act_edbone->name); + } + } + else if (ob->mode & OB_MODE_POSE) { + if (arm->act_bone) { + + if (arm->act_bone->layer & arm->layer) { + s += BLI_strcpy_rlen(s, msg_sep); + s += BLI_strcpy_rlen(s, arm->act_bone->name); + } + } + } + } + else if (ELEM(ob->type, OB_MESH, OB_LATTICE, OB_CURVE)) { + /* try to display active bone and active shapekey too (if they exist) */ + + if (ob->type == OB_MESH && ob->mode & OB_MODE_WEIGHT_PAINT) { + Object *armobj = BKE_object_pose_armature_get(ob); + if (armobj && armobj->mode & OB_MODE_POSE) { + bArmature *arm = armobj->data; + if (arm->act_bone) { + if (arm->act_bone->layer & arm->layer) { + s += BLI_strcpy_rlen(s, msg_sep); + s += BLI_strcpy_rlen(s, arm->act_bone->name); + } + } + } + } + + Key *key = BKE_key_from_object(ob); + if (key) { + KeyBlock *kb = BLI_findlink(&key->block, ob->shapenr - 1); + if (kb) { + s += BLI_strcpy_rlen(s, msg_sep); + s += BLI_strcpy_rlen(s, kb->name); + if (ob->shapeflag & OB_SHAPE_LOCK) { + s += BLI_strcpy_rlen(s, IFACE_(msg_pin)); + } + } + } } - } - if (tot) { - fpsi->redrawtime_index = (fpsi->redrawtime_index + 1) % REDRAW_FRAME_AVERAGE; - - //fpsi->redrawtime_index++; - //if (fpsi->redrawtime >= REDRAW_FRAME_AVERAGE) - // fpsi->redrawtime = 0; - - fps = fps / tot; - } -#endif - /* is this more than half a frame behind? */ - if (fps + 0.5f < (float)(FPS)) { - UI_ThemeColor(TH_REDALERT); - BLI_snprintf(printable, sizeof(printable), IFACE_("fps: %.2f"), fps); + /* color depends on whether there is a keyframe */ + if (id_frame_has_keyframe((ID *)ob, /* BKE_scene_frame_get(scene) */ (float)cfra, ANIMFILTER_KEYS_LOCAL)) + UI_FontThemeColor(font_id, TH_TIME_KEYFRAME); + else if (ED_gpencil_has_keyframe_v3d(scene, ob, cfra)) + UI_FontThemeColor(font_id, TH_TIME_GP_KEYFRAME); + else + UI_FontThemeColor(font_id, TH_TEXT_HI); } else { - UI_ThemeColor(TH_TEXT_HI); - BLI_snprintf(printable, sizeof(printable), IFACE_("fps: %i"), (int)(fps + 0.5f)); + /* no object */ + if (ED_gpencil_has_keyframe_v3d(scene, NULL, cfra)) + UI_FontThemeColor(font_id, TH_TIME_GP_KEYFRAME); + else + UI_FontThemeColor(font_id, TH_TEXT_HI); } -#ifdef WITH_INTERNATIONAL - BLF_draw_default(rect->xmin + U.widget_unit, rect->ymax - U.widget_unit, 0.0f, printable, sizeof(printable)); -#else - BLF_draw_default_ascii(rect->xmin + U.widget_unit, rect->ymax - U.widget_unit, 0.0f, printable, sizeof(printable)); -#endif -} + if (markern) { + s += sprintf(s, " <%s>", markern); + } -static bool view3d_main_region_do_render_draw(Scene *scene) -{ - RenderEngineType *type = RE_engines_find(scene->r.engine); + if (U.uiflag & USER_SHOW_ROTVIEWICON) + offset = U.widget_unit + (U.rvisize * 2) + rect->xmin; - return (type && type->view_update && type->view_draw); + BLF_draw_default(offset, 0.5f * U.widget_unit, 0.0f, info, sizeof(info)); } -bool ED_view3d_calc_render_border(Scene *scene, View3D *v3d, ARegion *ar, rcti *rect) +/* ******************** view loop ***************** */ + +/** + * Set the correct matrices + */ +static void view3d_draw_setup_view(const bContext *C, ARegion *ar) { + Scene *scene = CTX_data_scene(C); + View3D *v3d = CTX_wm_view3d(C); RegionView3D *rv3d = ar->regiondata; - rctf viewborder; - bool use_border; - /* test if there is a 3d view rendering */ - if (v3d->drawtype != OB_RENDER || !view3d_main_region_do_render_draw(scene)) - return false; - - /* test if there is a border render */ - if (rv3d->persp == RV3D_CAMOB) - use_border = (scene->r.mode & R_BORDER) != 0; + /* setup the view matrix */ + if (view3d_stereo3d_active(C, scene, v3d, rv3d)) + view3d_stereo3d_setup(scene, v3d, ar); else - use_border = (v3d->flag2 & V3D_RENDER_BORDER) != 0; - - if (!use_border) - return false; - - /* compute border */ - if (rv3d->persp == RV3D_CAMOB) { - ED_view3d_calc_camera_border(scene, ar, v3d, rv3d, &viewborder, false); - - rect->xmin = viewborder.xmin + scene->r.border.xmin * BLI_rctf_size_x(&viewborder); - rect->ymin = viewborder.ymin + scene->r.border.ymin * BLI_rctf_size_y(&viewborder); - rect->xmax = viewborder.xmin + scene->r.border.xmax * BLI_rctf_size_x(&viewborder); - rect->ymax = viewborder.ymin + scene->r.border.ymax * BLI_rctf_size_y(&viewborder); - } - else { - rect->xmin = v3d->render_border.xmin * ar->winx; - rect->xmax = v3d->render_border.xmax * ar->winx; - rect->ymin = v3d->render_border.ymin * ar->winy; - rect->ymax = v3d->render_border.ymax * ar->winy; - } - - BLI_rcti_translate(rect, ar->winrct.xmin, ar->winrct.ymin); - BLI_rcti_isect(&ar->winrct, rect, rect); - - return true; + view3d_main_region_setup_view(scene, v3d, ar, NULL, NULL); } -static bool view3d_main_region_draw_engine(const bContext *C, Scene *scene, - ARegion *ar, View3D *v3d, - bool clip_border, const rcti *border_rect) +static void draw_all_objects(const bContext *C, ARegion *ar, const bool only_depth, const bool use_depth) { - RegionView3D *rv3d = ar->regiondata; - RenderEngineType *type; - GLint scissor[4]; - - /* create render engine */ - if (!rv3d->render_engine) { - RenderEngine *engine; - - type = RE_engines_find(scene->r.engine); - - if (!(type->view_update && type->view_draw)) - return false; - - engine = RE_engine_create_ex(type, true); - - engine->tile_x = scene->r.tilex; - engine->tile_y = scene->r.tiley; + Scene *scene = CTX_data_scene(C); + SceneLayer *sl = CTX_data_scene_layer(C); + View3D *v3d = CTX_wm_view3d(C); - type->view_update(engine, C); + if (only_depth) + glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); - rv3d->render_engine = engine; + if (only_depth || use_depth) { + glEnable(GL_DEPTH_TEST); + glDepthFunc(GL_LESS); + glDepthMask(GL_TRUE); + v3d->zbuf = true; } - /* setup view matrices */ - view3d_main_region_setup_view(scene, v3d, ar, NULL, NULL); - - /* background draw */ - ED_region_pixelspace(ar); + for (Base *base = sl->object_bases.first; base; base = base->next) { + if ((base->flag & BASE_VISIBLED) != 0) { + /* dupli drawing */ + if (base->object->transflag & OB_DUPLI) + draw_dupli_objects(scene, sl, ar, v3d, base); - if (clip_border) { - /* for border draw, we only need to clear a subset of the 3d view */ - if (border_rect->xmax > border_rect->xmin && border_rect->ymax > border_rect->ymin) { - glGetIntegerv(GL_SCISSOR_BOX, scissor); - glScissor(border_rect->xmin, border_rect->ymin, - BLI_rcti_size_x(border_rect), BLI_rcti_size_y(border_rect)); - } - else { - return false; + draw_object(scene, sl, ar, v3d, base, 0); } } - glClearColor(0.0f, 0.0f, 0.0f, 0.0f); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - - if (v3d->flag & V3D_DISPBGPICS) - view3d_draw_bgpic_test(scene, ar, v3d, false, true); - else - fdrawcheckerboard(0, 0, ar->winx, ar->winy); - - /* render result draw */ - type = rv3d->render_engine->type; - type->view_draw(rv3d->render_engine, C); - - if (v3d->flag & V3D_DISPBGPICS) - view3d_draw_bgpic_test(scene, ar, v3d, true, true); + if (only_depth) + glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); - if (clip_border) { - /* restore scissor as it was before */ - glScissor(scissor[0], scissor[1], scissor[2], scissor[3]); + if (only_depth || use_depth) { + glDisable(GL_DEPTH_TEST); + v3d->zbuf = false; } - - return true; } -static void view3d_main_region_draw_engine_info(View3D *v3d, RegionView3D *rv3d, ARegion *ar, bool render_border) +/** + * Draw only the scene depth buffer + */ +static void draw_depth_buffer(const bContext *C, ARegion *ar) { - float fill_color[4] = {0.0f, 0.0f, 0.0f, 0.25f}; + draw_all_objects(C, ar, true, true); +} - if (!rv3d->render_engine || !rv3d->render_engine->text[0]) - return; - - if (render_border) { - /* draw darkened background color. no alpha because border render does - * partial redraw and will not redraw the region behind this info bar */ - float alpha = 1.0f - fill_color[3]; - Camera *camera = ED_view3d_camera_data_get(v3d, rv3d); - - if (camera) { - if (camera->flag & CAM_SHOWPASSEPARTOUT) { - alpha *= (1.0f - camera->passepartalpha); - } - } +/** + * Required if the shaders need it or external engines + * (e.g., Cycles requires depth buffer handled separately). + */ +static void view3d_draw_prerender_buffers(const bContext *C, ARegion *ar, DrawData *draw_data) +{ + View3D *v3d = CTX_wm_view3d(C); - UI_GetThemeColor3fv(TH_HIGH_GRAD, fill_color); - mul_v3_fl(fill_color, alpha); - fill_color[3] = 1.0f; + /* TODO viewport */ + if (draw_data->is_render && ((!draw_data->clip_border) || (v3d->drawtype <= OB_WIRE))) { + draw_depth_buffer(C, ar); } - - ED_region_info_draw(ar, rv3d->render_engine->text, fill_color, true); } -static bool view3d_stereo3d_active(const bContext *C, Scene *scene, View3D *v3d, RegionView3D *rv3d) +/** + * Draw all the plates that will fill the RGBD buffer + */ +static void view3d_draw_solid_plates(const bContext *C, ARegion *ar, DrawData *draw_data) { - wmWindow *win = CTX_wm_window(C); - - if ((scene->r.scemode & R_MULTIVIEW) == 0) - return false; - - if (WM_stereo3d_enabled(win, true) == false) - return false; - - if ((v3d->camera == NULL) || (v3d->camera->type != OB_CAMERA) || rv3d->persp != RV3D_CAMOB) - return false; + /* realtime plates */ + if ((!draw_data->is_render) || draw_data->clip_border) { + view3d_draw_background(C); + view3d_draw_render_solid_surfaces(C, ar, true); + view3d_draw_render_transparent_surfaces(C); + view3d_draw_post_draw(C); + } - if (scene->r.views_format & SCE_VIEWS_FORMAT_MULTIVIEW) { - if (v3d->stereo3d_camera == STEREO_MONO_ID) - return false; + /* offline plates*/ + if (draw_data->is_render) { + Scene *scene = CTX_data_scene(C); + View3D *v3d = CTX_wm_view3d(C); - return BKE_scene_multiview_is_stereo3d(&scene->r); + view3d_draw_render_draw(C, scene, ar, v3d, draw_data->clip_border, &draw_data->border_rect); } - return true; +#if VIEW3D_DRAW_DEBUG + view3d_draw_debug_post_solid(C, ar, draw_data); +#endif } -/* setup the view and win matrices for the multiview cameras - * - * unlike view3d_stereo3d_setup_offscreen, when view3d_stereo3d_setup is called - * we have no winmatrix (i.e., projection matrix) defined at that time. - * Since the camera and the camera shift are needed for the winmat calculation - * we do a small hack to replace it temporarily so we don't need to change the - * view3d)main_region_setup_view() code to account for that. +/** + * Wires, outline, ... */ -static void view3d_stereo3d_setup(Scene *scene, View3D *v3d, ARegion *ar) +static void view3d_draw_geometry_overlay(const bContext *C) { - bool is_left; - const char *names[2] = {STEREO_LEFT_NAME, STEREO_RIGHT_NAME}; - const char *viewname; - - /* show only left or right camera */ - if (v3d->stereo3d_camera != STEREO_3D_ID) - v3d->multiview_eye = v3d->stereo3d_camera; - - is_left = v3d->multiview_eye == STEREO_LEFT_ID; - viewname = names[is_left ? STEREO_LEFT_ID : STEREO_RIGHT_ID]; + view3d_draw_wire_plates(C); + view3d_draw_outline_plates(C); +} - /* update the viewport matrices with the new camera */ - if (scene->r.views_format == SCE_VIEWS_FORMAT_STEREO_3D) { - Camera *data; - float viewmat[4][4]; - float shiftx; +/* drawing cameras, lamps, ... */ +static void view3d_draw_non_meshes(const bContext *C, ARegion *ar) +{ + /* TODO viewport + * for now we draw them all, in the near future + * we filter them based on the plates/layers + */ + Scene *scene = CTX_data_scene(C); + SceneLayer *sl = CTX_data_scene_layer(C); + View3D *v3d = CTX_wm_view3d(C); + RegionView3D *rv3d = ar->regiondata; - data = (Camera *)v3d->camera->data; - shiftx = data->shiftx; + bool is_boundingbox = ((v3d->drawtype == OB_BOUNDBOX) || + ((v3d->drawtype == OB_RENDER) && (v3d->prev_drawtype == OB_BOUNDBOX))); - BLI_lock_thread(LOCK_VIEW3D); - data->shiftx = BKE_camera_multiview_shift_x(&scene->r, v3d->camera, viewname); + glEnable(GL_DEPTH_TEST); + glDepthMask(GL_TRUE); + /* TODO Viewport + * we are already temporarily writing to zbuffer in draw_object() + * for now let's avoid writing again to zbuffer to prevent glitches + */ - BKE_camera_multiview_view_matrix(&scene->r, v3d->camera, is_left, viewmat); - view3d_main_region_setup_view(scene, v3d, ar, viewmat, NULL); + for (Base *base = sl->object_bases.first; base; base = base->next) { + if ((base->flag & BASE_VISIBLED) != 0) { + Object *ob = base->object; - data->shiftx = shiftx; - BLI_unlock_thread(LOCK_VIEW3D); + unsigned char ob_wire_col[4]; + draw_object_wire_color(scene, sl, base, ob_wire_col); + view3d_draw_non_mesh(scene, sl, ob, base, v3d, rv3d, is_boundingbox, ob_wire_col); + } } - else { /* SCE_VIEWS_FORMAT_MULTIVIEW */ - float viewmat[4][4]; - Object *view_ob = v3d->camera; - Object *camera = BKE_camera_multiview_render(scene, v3d->camera, viewname); - - BLI_lock_thread(LOCK_VIEW3D); - v3d->camera = camera; - BKE_camera_multiview_view_matrix(&scene->r, camera, false, viewmat); - view3d_main_region_setup_view(scene, v3d, ar, viewmat, NULL); - - v3d->camera = view_ob; - BLI_unlock_thread(LOCK_VIEW3D); - } + glDepthMask(GL_FALSE); + glDisable(GL_DEPTH_TEST); } -static void view3d_stereo3d_setup_offscreen(Scene *scene, View3D *v3d, ARegion *ar, - float winmat[4][4], const char *viewname) +/** +* Parent lines, grid, ... +*/ +static void view3d_draw_other_elements(const bContext *C, ARegion *ar) { - /* update the viewport matrices with the new camera */ - if (scene->r.views_format == SCE_VIEWS_FORMAT_STEREO_3D) { - float viewmat[4][4]; - const bool is_left = STREQ(viewname, STEREO_LEFT_NAME); + view3d_draw_grid(C, ar); - BKE_camera_multiview_view_matrix(&scene->r, v3d->camera, is_left, viewmat); - view3d_main_region_setup_view(scene, v3d, ar, viewmat, winmat); - } - else { /* SCE_VIEWS_FORMAT_MULTIVIEW */ - float viewmat[4][4]; - Object *camera = BKE_camera_multiview_render(scene, v3d->camera, viewname); +#ifdef WITH_INPUT_NDOF + RegionView3D *rv3d = ar->regiondata; - BKE_camera_multiview_view_matrix(&scene->r, camera, false, viewmat); - view3d_main_region_setup_view(scene, v3d, ar, viewmat, winmat); - } + if ((U.ndof_flag & NDOF_SHOW_GUIDE) && ((rv3d->viewlock & RV3D_LOCKED) == 0) && (rv3d->persp != RV3D_CAMOB)) + /* TODO: draw something else (but not this) during fly mode */ + draw_rotation_guide(rv3d); +#endif } -#ifdef WITH_GAMEENGINE -static void update_lods(Scene *scene, float camera_pos[3]) +/** + * Paint brushes, armatures, ... + */ +static void view3d_draw_tool_ui(const bContext *UNUSED(C)) { - Scene *sce_iter; - Base *base; - Object *ob; - - for (SETLOOPER(scene, sce_iter, base)) { - ob = base->object; - BKE_object_lod_update(ob, camera_pos); - } + /* TODO viewport */ } -#endif -static void view3d_main_region_draw_objects(const bContext *C, Scene *scene, View3D *v3d, - ARegion *ar, const char **grid_unit) +/** + * Blueprint images + */ +static void view3d_draw_reference_images(const bContext *UNUSED(C)) { - wmWindow *win = CTX_wm_window(C); - RegionView3D *rv3d = ar->regiondata; - unsigned int lay_used = v3d->lay_used; - - /* post processing */ - bool do_compositing = false; - - /* shadow buffers, before we setup matrices */ - if (draw_glsl_material(scene, NULL, v3d, v3d->drawtype)) - gpu_update_lamps_shadows_world(scene, v3d); + /* TODO viewport */ +} - /* reset default OpenGL lights if needed (i.e. after preferences have been altered) */ - if (rv3d->rflag & RV3D_GPULIGHT_UPDATE) { - rv3d->rflag &= ~RV3D_GPULIGHT_UPDATE; - GPU_default_lights(); - } +/** +* 3D manipulators +*/ +static void view3d_draw_manipulator(const bContext *C) +{ + View3D *v3d = CTX_wm_view3d(C); + v3d->zbuf = false; + BIF_draw_manipulator(C); +} - /* setup the view matrix */ - if (view3d_stereo3d_active(C, scene, v3d, rv3d)) - view3d_stereo3d_setup(scene, v3d, ar); - else - view3d_main_region_setup_view(scene, v3d, ar, NULL, NULL); +/** +* Information drawn on top of the solid plates and composed data +*/ +void view3d_draw_region_info(const bContext *C, ARegion *ar) +{ + RegionView3D *rv3d = ar->regiondata; + View3D *v3d = CTX_wm_view3d(C); + Scene *scene = CTX_data_scene(C); + wmWindowManager *wm = CTX_wm_manager(C); - rv3d->rflag &= ~RV3D_IS_GAME_ENGINE; -#ifdef WITH_GAMEENGINE - if (STREQ(scene->r.engine, RE_engine_id_BLENDER_GAME)) { - rv3d->rflag |= RV3D_IS_GAME_ENGINE; + /* correct projection matrix */ + ED_region_pixelspace(ar); - /* Make sure LoDs are up to date */ - update_lods(scene, rv3d->viewinv[3]); - } -#endif + /* local coordinate visible rect inside region, to accomodate overlapping ui */ + rcti rect; + ED_region_visible_rect(ar, &rect); - /* framebuffer fx needed, we need to draw offscreen first */ - if (v3d->fx_settings.fx_flag && v3d->drawtype >= OB_SOLID) { - GPUFXSettings fx_settings; - BKE_screen_gpu_fx_validate(&v3d->fx_settings); - fx_settings = v3d->fx_settings; - if (!rv3d->compositor) - rv3d->compositor = GPU_fx_compositor_create(); - - if (rv3d->persp == RV3D_CAMOB && v3d->camera) - BKE_camera_to_gpu_dof(v3d->camera, &fx_settings); - else { - fx_settings.dof = NULL; - } + view3d_draw_border(C, ar); + view3d_draw_grease_pencil(C); - do_compositing = GPU_fx_compositor_initialize_passes(rv3d->compositor, &ar->winrct, &ar->drawrct, &fx_settings); + if (U.uiflag & USER_SHOW_ROTVIEWICON) { + draw_view_axis(rv3d, &rect); } - - /* clear the background */ - view3d_main_region_clear(scene, v3d, ar); - /* enables anti-aliasing for 3D view drawing */ - if (win->multisamples != USER_MULTISAMPLE_NONE) { - glEnable(GL_MULTISAMPLE); + if ((U.uiflag & USER_SHOW_FPS) && ED_screen_animation_no_scrub(wm)) { + ED_scene_draw_fps(scene, &rect); } - - /* main drawing call */ - view3d_draw_objects(C, scene, v3d, ar, grid_unit, true, false, do_compositing ? rv3d->compositor : NULL); - - /* post process */ - if (do_compositing) { - GPU_fx_do_composite_pass(rv3d->compositor, rv3d->winmat, rv3d->is_persp, scene, NULL); + else if (U.uiflag & USER_SHOW_VIEWPORTNAME) { + draw_viewport_name(ar, v3d, &rect); } - /* Disable back anti-aliasing */ - if (win->multisamples != USER_MULTISAMPLE_NONE) { - glDisable(GL_MULTISAMPLE); + if (U.uiflag & USER_DRAWVIEWINFO) { + SceneLayer *sl = CTX_data_scene_layer(C); + Object *ob = OBACT_NEW; + draw_selected_name(scene, ob, &rect); } +#if 0 /* TODO */ + if (grid_unit) { /* draw below the viewport name */ + char numstr[32] = ""; - if (v3d->lay_used != lay_used) { /* happens when loading old files or loading with UI load */ - /* find header and force tag redraw */ - ScrArea *sa = CTX_wm_area(C); - ARegion *ar_header = BKE_area_find_region_type(sa, RGN_TYPE_HEADER); - ED_region_tag_redraw(ar_header); /* can be NULL */ - } + UI_FontThemeColor(BLF_default(), TH_TEXT_HI); + if (v3d->grid != 1.0f) { + BLI_snprintf(numstr, sizeof(numstr), "%s x %.4g", grid_unit, v3d->grid); + } - if ((v3d->flag2 & V3D_RENDER_OVERRIDE) == 0) { - BDR_drawSketch(C); + BLF_draw_default_ascii(rect.xmin + U.widget_unit, + rect.ymax - (USER_SHOW_VIEWPORTNAME ? 2 * U.widget_unit : U.widget_unit), 0.0f, + numstr[0] ? numstr : grid_unit, sizeof(numstr)); } +#endif +} -#ifdef WITH_INPUT_NDOF - if ((U.ndof_flag & NDOF_SHOW_GUIDE) && ((rv3d->viewlock & RV3D_LOCKED) == 0) && (rv3d->persp != RV3D_CAMOB)) - /* TODO: draw something else (but not this) during fly mode */ - draw_rotation_guide(rv3d); +/** + * This could run once per view, or even in parallel + * for each of them. What is a "view"? + * - a viewport with the camera elsewhere + * - left/right stereo + * - panorama / fisheye individual cubemap faces + */ +static void view3d_draw_view(const bContext *C, ARegion *ar, DrawData *draw_data) +{ + /* TODO - Technically this should be drawn to a few FBO, so we can handle + * compositing better, but for now this will get the ball rolling (dfelinto) */ + + view3d_draw_setup_view(C, ar); + view3d_draw_prerender_buffers(C, ar, draw_data); + view3d_draw_solid_plates(C, ar, draw_data); + view3d_draw_geometry_overlay(C); + view3d_draw_non_meshes(C, ar); + view3d_draw_other_elements(C, ar); + view3d_draw_tool_ui(C); + view3d_draw_reference_images(C); + view3d_draw_manipulator(C); + view3d_draw_region_info(C, ar); + +#if VIEW3D_DRAW_DEBUG + view3d_draw_debug(C, ar, draw_data); #endif } -static bool is_cursor_visible(Scene *scene) +static void view3d_render_pass(const bContext *C, ARegion *UNUSED(ar)) { - Object *ob = OBACT; + Scene *scene = CTX_data_scene(C); + RenderEngineType *type = RE_engines_find(scene->r.engine); /* In the future we should get that from Layers */ - /* don't draw cursor in paint modes, but with a few exceptions */ - if (ob && ob->mode & OB_MODE_ALL_PAINT) { - /* exception: object is in weight paint and has deforming armature in pose mode */ - if (ob->mode & OB_MODE_WEIGHT_PAINT) { - if (BKE_object_pose_armature_get(ob) != NULL) { - return true; - } - } - /* exception: object in texture paint mode, clone brush, use_clone_layer disabled */ - else if (ob->mode & OB_MODE_TEXTURE_PAINT) { - const Paint *p = BKE_paint_get_active(scene); + if (type->flag & RE_USE_OGL_PIPELINE) { + type->view_draw(NULL, C); + } + else { + // Offline Render engine + } +} - if (p && p->brush && p->brush->imagepaint_tool == PAINT_TOOL_CLONE) { - if ((scene->toolsettings->imapaint.flag & IMAGEPAINT_PROJECT_LAYER_CLONE) == 0) { - return true; - } - } - } +static void view3d_draw_view_new(const bContext *C, ARegion *ar, DrawData *UNUSED(draw_data)) +{ - /* no exception met? then don't draw cursor! */ - return false; - } + view3d_draw_setup_view(C, ar); - return true; + /* Only 100% compliant on new spec goes bellow */ + view3d_render_pass(C, ar); } -static void view3d_main_region_draw_info(const bContext *C, Scene *scene, - ARegion *ar, View3D *v3d, - const char *grid_unit, bool render_border) + +void view3d_main_region_draw(const bContext *C, ARegion *ar) { - wmWindowManager *wm = CTX_wm_manager(C); + Scene *scene = CTX_data_scene(C); + View3D *v3d = CTX_wm_view3d(C); + int mode = CTX_data_mode_enum(C); RegionView3D *rv3d = ar->regiondata; - rcti rect; - - /* local coordinate visible rect inside region, to accomodate overlapping ui */ - ED_region_visible_rect(ar, &rect); + /* TODO layers - In the future we should get RE from Layers */ + RenderEngineType *type = RE_engines_find(scene->r.engine); - if (rv3d->persp == RV3D_CAMOB) { - drawviewborder(scene, ar, v3d); + if (IS_VIEWPORT_LEGACY(v3d) && ((type->flag & RE_USE_OGL_PIPELINE) == 0)) { + view3d_main_region_draw_legacy(C, ar); + return; } - else if (v3d->flag2 & V3D_RENDER_BORDER) { - glLineWidth(1.0f); - setlinestyle(3); - cpack(0x4040FF); - sdrawbox(v3d->render_border.xmin * ar->winx, v3d->render_border.ymin * ar->winy, - v3d->render_border.xmax * ar->winx, v3d->render_border.ymax * ar->winy); + if (!rv3d->viewport) + rv3d->viewport = GPU_viewport_create(); - setlinestyle(0); - } + GPU_viewport_bind(rv3d->viewport, &ar->winrct, scene->r.engine, mode); - if (v3d->flag2 & V3D_SHOW_GPENCIL) { - /* draw grease-pencil stuff - needed to get paint-buffer shown too (since it's 2D) */ - ED_gpencil_draw_view3d(wm, scene, v3d, ar, false); - } + /* 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); - if ((v3d->flag2 & V3D_RENDER_OVERRIDE) == 0) { - Object *ob; + if (type->flag & RE_USE_OGL_PIPELINE) + view3d_draw_view_new(C, ar, &draw_data); + else + view3d_draw_view(C, ar, &draw_data); - /* 3d cursor */ - if (is_cursor_visible(scene)) { - drawcursor(scene, ar, v3d); - } + GPU_viewport_unbind(rv3d->viewport); - if (U.uiflag & USER_SHOW_ROTVIEWICON) - draw_view_axis(rv3d, &rect); - else - draw_view_icon(rv3d, &rect); + v3d->flag |= V3D_INVALID_BACKBUF; +} - ob = OBACT; - if (U.uiflag & USER_DRAWVIEWINFO) - draw_selected_name(scene, ob, &rect); - } +/* ******************** legacy interface ***************** */ +/** + * This will be removed once the viewport gets replaced + * meanwhile it should keep the old viewport working. + */ - if (rv3d->render_engine) { - view3d_main_region_draw_engine_info(v3d, rv3d, ar, render_border); - return; +void VP_legacy_drawcursor(Scene *scene, ARegion *ar, View3D *v3d) +{ + if (is_cursor_visible(scene)) { + drawcursor(scene, ar, v3d); } +} - if ((v3d->flag2 & V3D_RENDER_OVERRIDE) == 0) { - if ((U.uiflag & USER_SHOW_FPS) && ED_screen_animation_no_scrub(wm)) { - ED_scene_draw_fps(scene, &rect); - } - else if (U.uiflag & USER_SHOW_VIEWPORTNAME) { - draw_viewport_name(ar, v3d, &rect); - } - - if (grid_unit) { /* draw below the viewport name */ - char numstr[32] = ""; - - UI_ThemeColor(TH_TEXT_HI); - if (v3d->grid != 1.0f) { - BLI_snprintf(numstr, sizeof(numstr), "%s x %.4g", grid_unit, v3d->grid); - } +void VP_legacy_draw_view_axis(RegionView3D *rv3d, rcti *rect) +{ + draw_view_axis(rv3d, rect); +} - BLF_draw_default_ascii(rect.xmin + U.widget_unit, - rect.ymax - (USER_SHOW_VIEWPORTNAME ? 2 * U.widget_unit : U.widget_unit), 0.0f, - numstr[0] ? numstr : grid_unit, sizeof(numstr)); - } - } +void VP_legacy_draw_viewport_name(ARegion *ar, View3D *v3d, rcti *rect) +{ + draw_viewport_name(ar, v3d, rect); } -void view3d_main_region_draw(const bContext *C, ARegion *ar) +void VP_legacy_draw_selected_name(Scene *scene, Object *ob, rcti *rect) { - Scene *scene = CTX_data_scene(C); - View3D *v3d = CTX_wm_view3d(C); - const char *grid_unit = NULL; - rcti border_rect; - bool render_border, clip_border; + draw_selected_name(scene, ob, rect); +} - /* if we only redraw render border area, skip opengl draw and also - * don't do scissor because it's already set */ - render_border = ED_view3d_calc_render_border(scene, v3d, ar, &border_rect); - clip_border = (render_border && !BLI_rcti_compare(&ar->drawrct, &border_rect)); +void VP_legacy_drawgrid(UnitSettings *unit, ARegion *ar, View3D *v3d, const char **grid_unit) +{ + drawgrid(unit, ar, v3d, grid_unit); +} - /* draw viewport using opengl */ - if (v3d->drawtype != OB_RENDER || !view3d_main_region_do_render_draw(scene) || clip_border) { - view3d_main_region_draw_objects(C, scene, v3d, ar, &grid_unit); - -#ifdef DEBUG_DRAW - bl_debug_draw(); -#endif - if (G.debug & G_DEBUG_SIMDATA) - draw_sim_debug_data(scene, v3d, ar); - - ED_region_pixelspace(ar); - } +void VP_legacy_drawfloor(Scene *scene, View3D *v3d, const char **grid_unit, bool write_depth) +{ + drawfloor(scene, v3d, grid_unit, write_depth); +} - /* draw viewport using external renderer */ - if (v3d->drawtype == OB_RENDER) - view3d_main_region_draw_engine(C, scene, ar, v3d, clip_border, &border_rect); - - view3d_main_region_draw_info(C, scene, ar, v3d, grid_unit, render_border); +void VP_legacy_view3d_main_region_setup_view(Scene *scene, View3D *v3d, ARegion *ar, float viewmat[4][4], float winmat[4][4]) +{ + view3d_main_region_setup_view(scene, v3d, ar, viewmat, winmat); +} - v3d->flag |= V3D_INVALID_BACKBUF; +bool VP_legacy_view3d_stereo3d_active(const bContext *C, Scene *scene, View3D *v3d, RegionView3D *rv3d) +{ + return view3d_stereo3d_active(C, scene, v3d, rv3d); +} - BLI_assert(BLI_listbase_is_empty(&v3d->afterdraw_transp)); - BLI_assert(BLI_listbase_is_empty(&v3d->afterdraw_xray)); - BLI_assert(BLI_listbase_is_empty(&v3d->afterdraw_xraytransp)); +void VP_legacy_view3d_stereo3d_setup(Scene *scene, View3D *v3d, ARegion *ar) +{ + view3d_stereo3d_setup(scene, v3d, ar); } -#ifdef DEBUG_DRAW -/* debug drawing */ -#define _DEBUG_DRAW_QUAD_TOT 1024 -#define _DEBUG_DRAW_EDGE_TOT 1024 -static float _bl_debug_draw_quads[_DEBUG_DRAW_QUAD_TOT][4][3]; -static int _bl_debug_draw_quads_tot = 0; -static float _bl_debug_draw_edges[_DEBUG_DRAW_QUAD_TOT][2][3]; -static int _bl_debug_draw_edges_tot = 0; -static unsigned int _bl_debug_draw_quads_color[_DEBUG_DRAW_QUAD_TOT]; -static unsigned int _bl_debug_draw_edges_color[_DEBUG_DRAW_EDGE_TOT]; -static unsigned int _bl_debug_draw_color; +bool VP_legacy_use_depth(Scene *scene, View3D *v3d) +{ + return use_depth_doit(scene, v3d); +} -void bl_debug_draw_quad_clear(void) +void VP_drawviewborder(Scene *scene, ARegion *ar, View3D *v3d) { - _bl_debug_draw_quads_tot = 0; - _bl_debug_draw_edges_tot = 0; - _bl_debug_draw_color = 0x00FF0000; + drawviewborder(scene, ar, v3d); } -void bl_debug_color_set(const unsigned int color) + +void VP_drawrenderborder(ARegion *ar, View3D *v3d) { - _bl_debug_draw_color = color; + drawrenderborder(ar, v3d); } -void bl_debug_draw_quad_add(const float v0[3], const float v1[3], const float v2[3], const float v3[3]) + +void VP_view3d_draw_background_none(void) { - if (_bl_debug_draw_quads_tot >= _DEBUG_DRAW_QUAD_TOT) { - printf("%s: max quad count hit %d!", __func__, _bl_debug_draw_quads_tot); - } - else { - float *pt = &_bl_debug_draw_quads[_bl_debug_draw_quads_tot][0][0]; - copy_v3_v3(pt, v0); pt += 3; - copy_v3_v3(pt, v1); pt += 3; - copy_v3_v3(pt, v2); pt += 3; - copy_v3_v3(pt, v3); pt += 3; - _bl_debug_draw_quads_color[_bl_debug_draw_quads_tot] = _bl_debug_draw_color; - _bl_debug_draw_quads_tot++; - } + view3d_draw_background_none(); } -void bl_debug_draw_edge_add(const float v0[3], const float v1[3]) + +void VP_view3d_draw_background_world(Scene *scene, View3D *v3d, RegionView3D *rv3d) { - if (_bl_debug_draw_quads_tot >= _DEBUG_DRAW_EDGE_TOT) { - printf("%s: max edge count hit %d!", __func__, _bl_debug_draw_edges_tot); - } - else { - float *pt = &_bl_debug_draw_edges[_bl_debug_draw_edges_tot][0][0]; - copy_v3_v3(pt, v0); pt += 3; - copy_v3_v3(pt, v1); pt += 3; - _bl_debug_draw_edges_color[_bl_debug_draw_edges_tot] = _bl_debug_draw_color; - _bl_debug_draw_edges_tot++; - } -} -static void bl_debug_draw(void) -{ - unsigned int color; - if (_bl_debug_draw_quads_tot) { - int i; - color = _bl_debug_draw_quads_color[0]; - cpack(color); - for (i = 0; i < _bl_debug_draw_quads_tot; i ++) { - if (_bl_debug_draw_quads_color[i] != color) { - color = _bl_debug_draw_quads_color[i]; - cpack(color); - } - glBegin(GL_LINE_LOOP); - glVertex3fv(_bl_debug_draw_quads[i][0]); - glVertex3fv(_bl_debug_draw_quads[i][1]); - glVertex3fv(_bl_debug_draw_quads[i][2]); - glVertex3fv(_bl_debug_draw_quads[i][3]); - glEnd(); - } - } - if (_bl_debug_draw_edges_tot) { - int i; - color = _bl_debug_draw_edges_color[0]; - cpack(color); - glBegin(GL_LINES); - for (i = 0; i < _bl_debug_draw_edges_tot; i ++) { - if (_bl_debug_draw_edges_color[i] != color) { - color = _bl_debug_draw_edges_color[i]; - cpack(color); - } - glVertex3fv(_bl_debug_draw_edges[i][0]); - glVertex3fv(_bl_debug_draw_edges[i][1]); - } - glEnd(); - color = _bl_debug_draw_edges_color[0]; - cpack(color); - glPointSize(4.0); - glBegin(GL_POINTS); - for (i = 0; i < _bl_debug_draw_edges_tot; i ++) { - if (_bl_debug_draw_edges_color[i] != color) { - color = _bl_debug_draw_edges_color[i]; - cpack(color); - } - glVertex3fv(_bl_debug_draw_edges[i][0]); - glVertex3fv(_bl_debug_draw_edges[i][1]); - } - glEnd(); - } + view3d_draw_background_world(scene, v3d, rv3d); } -#endif diff --git a/source/blender/editors/space_view3d/view3d_draw_legacy.c b/source/blender/editors/space_view3d/view3d_draw_legacy.c new file mode 100644 index 00000000000..84f0e296a1f --- /dev/null +++ b/source/blender/editors/space_view3d/view3d_draw_legacy.c @@ -0,0 +1,2546 @@ +/* + * ***** 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) 2008 Blender Foundation. + * All rights reserved. + * + * + * Contributor(s): Blender Foundation + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/editors/space_view3d/view3d_draw_legacy.c + * \ingroup spview3d + */ + +#include <string.h> +#include <stdio.h> +#include <math.h> + +#include "DNA_armature_types.h" +#include "DNA_camera_types.h" +#include "DNA_customdata_types.h" +#include "DNA_object_types.h" +#include "DNA_group_types.h" +#include "DNA_mesh_types.h" +#include "DNA_key_types.h" +#include "DNA_lamp_types.h" +#include "DNA_scene_types.h" +#include "DNA_world_types.h" +#include "DNA_brush_types.h" + +#include "MEM_guardedalloc.h" + +#include "BLI_blenlib.h" +#include "BLI_math.h" +#include "BLI_jitter.h" +#include "BLI_utildefines.h" +#include "BLI_endian_switch.h" +#include "BLI_threads.h" + +#include "BKE_anim.h" +#include "BKE_camera.h" +#include "BKE_context.h" +#include "BKE_customdata.h" +#include "BKE_DerivedMesh.h" +#include "BKE_image.h" +#include "BKE_key.h" +#include "BKE_layer.h" +#include "BKE_main.h" +#include "BKE_object.h" +#include "BKE_global.h" +#include "BKE_paint.h" +#include "BKE_scene.h" +#include "BKE_screen.h" +#include "BKE_unit.h" +#include "BKE_movieclip.h" + +#include "RE_engine.h" + +#include "IMB_imbuf_types.h" +#include "IMB_imbuf.h" +#include "IMB_colormanagement.h" + +#include "BIF_gl.h" +#include "BIF_glutil.h" + +#include "WM_api.h" + +#include "BLF_api.h" +#include "BLT_translation.h" + +#include "ED_armature.h" +#include "ED_keyframing.h" +#include "ED_gpencil.h" +#include "ED_screen.h" +#include "ED_space_api.h" +#include "ED_screen_types.h" +#include "ED_transform.h" + +#include "UI_interface.h" +#include "UI_interface_icons.h" +#include "UI_resources.h" + +#include "GPU_draw.h" +#include "GPU_framebuffer.h" +#include "GPU_material.h" +#include "GPU_compositing.h" +#include "GPU_extensions.h" +#include "GPU_immediate.h" + +#include "view3d_intern.h" /* own include */ + +/* prototypes */ +static void view3d_stereo3d_setup_offscreen(Scene *scene, View3D *v3d, ARegion *ar, + float winmat[4][4], const char *viewname); + +void circ(float x, float y, float rad) +{ + glBegin(GL_LINE_LOOP); + const int segments = 32; + for (int i = 0; i < segments; ++i) { + float angle = 2 * M_PI * ((float)i / (float)segments); + glVertex2f(x + rad * cosf(angle), + y + rad * sinf(angle)); + } + glEnd(); +} + + +/* ********* custom clipping *********** */ + +static void view3d_draw_clipping(RegionView3D *rv3d) +{ + BoundBox *bb = rv3d->clipbb; + + if (bb) { + const unsigned int clipping_index[6][4] = { + {0, 1, 2, 3}, + {0, 4, 5, 1}, + {4, 7, 6, 5}, + {7, 3, 2, 6}, + {1, 5, 6, 2}, + {7, 4, 0, 3} + }; + + /* fill in zero alpha for rendering & re-projection [#31530] */ + unsigned char col[4]; + UI_GetThemeColor4ubv(TH_V3D_CLIPPING_BORDER, col); + glColor4ubv(col); + + glEnable(GL_BLEND); + glEnableClientState(GL_VERTEX_ARRAY); + glVertexPointer(3, GL_FLOAT, 0, bb->vec); + glDrawElements(GL_QUADS, sizeof(clipping_index) / sizeof(unsigned int), GL_UNSIGNED_INT, clipping_index); + glDisableClientState(GL_VERTEX_ARRAY); + glDisable(GL_BLEND); + } +} + +void ED_view3d_clipping_set(RegionView3D *rv3d) +{ + double plane[4]; + const unsigned int tot = (rv3d->viewlock & RV3D_BOXCLIP) ? 4 : 6; + + for (unsigned a = 0; a < tot; a++) { + copy_v4db_v4fl(plane, rv3d->clip[a]); + glClipPlane(GL_CLIP_PLANE0 + a, plane); + glEnable(GL_CLIP_PLANE0 + a); + } +} + +/* use these to temp disable/enable clipping when 'rv3d->rflag & RV3D_CLIPPING' is set */ +void ED_view3d_clipping_disable(void) +{ + for (unsigned a = 0; a < 6; a++) { + glDisable(GL_CLIP_PLANE0 + a); + } +} +void ED_view3d_clipping_enable(void) +{ + for (unsigned a = 0; a < 6; a++) { + glEnable(GL_CLIP_PLANE0 + a); + } +} + +static bool view3d_clipping_test(const float co[3], const float clip[6][4]) +{ + if (plane_point_side_v3(clip[0], co) > 0.0f) + if (plane_point_side_v3(clip[1], co) > 0.0f) + if (plane_point_side_v3(clip[2], co) > 0.0f) + if (plane_point_side_v3(clip[3], co) > 0.0f) + return false; + + return true; +} + +/* for 'local' ED_view3d_clipping_local must run first + * then all comparisons can be done in localspace */ +bool ED_view3d_clipping_test(const RegionView3D *rv3d, const float co[3], const bool is_local) +{ + return view3d_clipping_test(co, is_local ? rv3d->clip_local : rv3d->clip); +} + +/* ********* end custom clipping *********** */ + +static void draw_view_icon(RegionView3D *rv3d, rcti *rect) +{ + BIFIconID icon; + + if (ELEM(rv3d->view, RV3D_VIEW_TOP, RV3D_VIEW_BOTTOM)) + icon = ICON_AXIS_TOP; + else if (ELEM(rv3d->view, RV3D_VIEW_FRONT, RV3D_VIEW_BACK)) + icon = ICON_AXIS_FRONT; + else if (ELEM(rv3d->view, RV3D_VIEW_RIGHT, RV3D_VIEW_LEFT)) + icon = ICON_AXIS_SIDE; + else return; + + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + + UI_icon_draw(5.0 + rect->xmin, 5.0 + rect->ymin, icon); + + glDisable(GL_BLEND); +} + +/* *********************** backdraw for selection *************** */ + +static void backdrawview3d(Scene *scene, SceneLayer *sl, wmWindow *win, ARegion *ar, View3D *v3d) +{ + RegionView3D *rv3d = ar->regiondata; + struct Base *base = sl->basact; + int multisample_enabled; + + BLI_assert(ar->regiontype == RGN_TYPE_WINDOW); + + if (base && (base->object->mode & (OB_MODE_VERTEX_PAINT | OB_MODE_WEIGHT_PAINT) || + BKE_paint_select_face_test(base->object))) + { + /* do nothing */ + } + /* texture paint mode sampling */ + else if (base && (base->object->mode & OB_MODE_TEXTURE_PAINT) && + (v3d->drawtype > OB_WIRE)) + { + /* do nothing */ + } + else if ((base && (base->object->mode & OB_MODE_PARTICLE_EDIT)) && + V3D_IS_ZBUF(v3d)) + { + /* do nothing */ + } + else if (scene->obedit && + V3D_IS_ZBUF(v3d)) + { + /* do nothing */ + } + else { + v3d->flag &= ~V3D_INVALID_BACKBUF; + return; + } + + if (!(v3d->flag & V3D_INVALID_BACKBUF)) + return; + +#if 0 + if (test) { + if (qtest()) { + addafterqueue(ar->win, BACKBUFDRAW, 1); + return; + } + } +#endif + + if (v3d->drawtype > OB_WIRE) v3d->zbuf = true; + + /* dithering and AA break color coding, so disable */ + glDisable(GL_DITHER); + + multisample_enabled = glIsEnabled(GL_MULTISAMPLE); + if (multisample_enabled) + glDisable(GL_MULTISAMPLE); + + if (win->multisamples != USER_MULTISAMPLE_NONE) { + /* for multisample we use an offscreen FBO. multisample drawing can fail + * with color coded selection drawing, and reading back depths from such + * a buffer can also cause a few seconds freeze on OS X / NVidia. */ + int w = BLI_rcti_size_x(&ar->winrct); + int h = BLI_rcti_size_y(&ar->winrct); + char error[256]; + + if (rv3d->gpuoffscreen) { + if (GPU_offscreen_width(rv3d->gpuoffscreen) != w || + GPU_offscreen_height(rv3d->gpuoffscreen) != h) + { + GPU_offscreen_free(rv3d->gpuoffscreen); + rv3d->gpuoffscreen = NULL; + } + } + + if (!rv3d->gpuoffscreen) { + rv3d->gpuoffscreen = GPU_offscreen_create(w, h, 0, error); + + if (!rv3d->gpuoffscreen) + fprintf(stderr, "Failed to create offscreen selection buffer for multisample: %s\n", error); + } + } + + if (rv3d->gpuoffscreen) + GPU_offscreen_bind(rv3d->gpuoffscreen, true); + else + glScissor(ar->winrct.xmin, ar->winrct.ymin, BLI_rcti_size_x(&ar->winrct), BLI_rcti_size_y(&ar->winrct)); + + glClearColor(0.0, 0.0, 0.0, 0.0); + if (v3d->zbuf) { + glEnable(GL_DEPTH_TEST); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + } + else { + glClear(GL_COLOR_BUFFER_BIT); + glDisable(GL_DEPTH_TEST); + } + + if (rv3d->rflag & RV3D_CLIPPING) + ED_view3d_clipping_set(rv3d); + + G.f |= G_BACKBUFSEL; + + if (base && ((base->flag & BASE_VISIBLED) != 0)) + draw_object_backbufsel(scene, v3d, rv3d, base->object); + + if (rv3d->gpuoffscreen) + GPU_offscreen_unbind(rv3d->gpuoffscreen, true); + else + ar->swap = 0; /* mark invalid backbuf for wm draw */ + + v3d->flag &= ~V3D_INVALID_BACKBUF; + + G.f &= ~G_BACKBUFSEL; + v3d->zbuf = false; + glDisable(GL_DEPTH_TEST); + glEnable(GL_DITHER); + if (multisample_enabled) + glEnable(GL_MULTISAMPLE); + + if (rv3d->rflag & RV3D_CLIPPING) + ED_view3d_clipping_disable(); +} + +void view3d_opengl_read_pixels(ARegion *ar, int x, int y, int w, int h, int format, int type, void *data) +{ + RegionView3D *rv3d = ar->regiondata; + + if (rv3d->gpuoffscreen) { + GPU_offscreen_bind(rv3d->gpuoffscreen, true); + glReadBuffer(GL_COLOR_ATTACHMENT0); + glReadPixels(x, y, w, h, format, type, data); + GPU_offscreen_unbind(rv3d->gpuoffscreen, true); + } + else { + glReadPixels(ar->winrct.xmin + x, ar->winrct.ymin + y, w, h, format, type, data); + } +} + +/* XXX depth reading exception, for code not using gpu offscreen */ +static void view3d_opengl_read_Z_pixels(ARegion *ar, int x, int y, int w, int h, int format, int type, void *data) +{ + glReadPixels(ar->winrct.xmin + x, ar->winrct.ymin + y, w, h, format, type, data); +} + +void ED_view3d_backbuf_validate(ViewContext *vc) +{ + if (vc->v3d->flag & V3D_INVALID_BACKBUF) + backdrawview3d(vc->scene, vc->sl, vc->win, vc->ar, vc->v3d); +} + +/** + * allow for small values [0.5 - 2.5], + * and large values, FLT_MAX by clamping by the area size + */ +int ED_view3d_backbuf_sample_size_clamp(ARegion *ar, const float dist) +{ + return (int)min_ff(ceilf(dist), (float)max_ii(ar->winx, ar->winx)); +} + +/* samples a single pixel (copied from vpaint) */ +unsigned int ED_view3d_backbuf_sample(ViewContext *vc, int x, int y) +{ + if (x >= vc->ar->winx || y >= vc->ar->winy) { + return 0; + } + + ED_view3d_backbuf_validate(vc); + + unsigned int col; + view3d_opengl_read_pixels(vc->ar, x, y, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, &col); + glReadBuffer(GL_BACK); + + if (ENDIAN_ORDER == B_ENDIAN) { + BLI_endian_switch_uint32(&col); + } + + return GPU_select_to_index(col); +} + +/* reads full rect, converts indices */ +ImBuf *ED_view3d_backbuf_read(ViewContext *vc, int xmin, int ymin, int xmax, int ymax) +{ + /* clip */ + const rcti clip = { + max_ii(xmin, 0), min_ii(xmax, vc->ar->winx - 1), + max_ii(ymin, 0), min_ii(ymax, vc->ar->winy - 1)}; + const int size_clip[2] = { + BLI_rcti_size_x(&clip) + 1, + BLI_rcti_size_y(&clip) + 1}; + + if (UNLIKELY((clip.xmin > clip.xmax) || + (clip.ymin > clip.ymax))) + { + return NULL; + } + + ImBuf *ibuf_clip = IMB_allocImBuf(size_clip[0], size_clip[1], 32, IB_rect); + + ED_view3d_backbuf_validate(vc); + + view3d_opengl_read_pixels(vc->ar, clip.xmin, clip.ymin, size_clip[0], size_clip[1], GL_RGBA, GL_UNSIGNED_BYTE, ibuf_clip->rect); + + glReadBuffer(GL_BACK); + + if (ENDIAN_ORDER == B_ENDIAN) { + IMB_convert_rgba_to_abgr(ibuf_clip); + } + + GPU_select_to_index_array(ibuf_clip->rect, size_clip[0] * size_clip[1]); + + if ((clip.xmin == xmin) && + (clip.xmax == xmax) && + (clip.ymin == ymin) && + (clip.ymax == ymax)) + { + return ibuf_clip; + } + else { + /* put clipped result into a non-clipped buffer */ + const int size[2] = { + (xmax - xmin + 1), + (ymax - ymin + 1)}; + + ImBuf *ibuf_full = IMB_allocImBuf(size[0], size[1], 32, IB_rect); + + IMB_rectcpy( + ibuf_full, ibuf_clip, + clip.xmin - xmin, clip.ymin - ymin, + 0, 0, + size_clip[0], size_clip[1]); + IMB_freeImBuf(ibuf_clip); + return ibuf_full; + } +} + +/* smart function to sample a rect spiralling outside, nice for backbuf selection */ +unsigned int ED_view3d_backbuf_sample_rect( + ViewContext *vc, const int mval[2], int size, + unsigned int min, unsigned int max, float *r_dist) +{ + int dirvec[4][2]; + + const int amount = (size - 1) / 2; + + const int minx = mval[0] - (amount + 1); + const int miny = mval[1] - (amount + 1); + ImBuf *buf = ED_view3d_backbuf_read(vc, minx, miny, minx + size - 1, miny + size - 1); + if (!buf) return 0; + + unsigned index = 0; + int rc = 0; + + dirvec[0][0] = 1; dirvec[0][1] = 0; + dirvec[1][0] = 0; dirvec[1][1] = -size; + dirvec[2][0] = -1; dirvec[2][1] = 0; + dirvec[3][0] = 0; dirvec[3][1] = size; + + const unsigned *bufmin = buf->rect; + const unsigned *tbuf = buf->rect; + const unsigned *bufmax = buf->rect + size * size; + tbuf += amount * size + amount; + + for (int nr = 1; nr <= size; nr++) { + for (int a = 0; a < 2; a++) { + for (int b = 0; b < nr; b++) { + if (*tbuf && *tbuf >= min && *tbuf < max) { + /* we got a hit */ + + /* get x,y pixel coords from the offset + * (manhatten distance in keeping with other screen-based selection) */ + *r_dist = (float)( + abs(((int)(tbuf - buf->rect) % size) - (size / 2)) + + abs(((int)(tbuf - buf->rect) / size) - (size / 2))); + + /* indices start at 1 here */ + index = (*tbuf - min) + 1; + goto exit; + } + + tbuf += (dirvec[rc][0] + dirvec[rc][1]); + + if (tbuf < bufmin || tbuf >= bufmax) { + goto exit; + } + } + rc++; + rc &= 3; + } + } + +exit: + IMB_freeImBuf(buf); + return index; +} + + +/* ************************************************************* */ + +static void view3d_stereo_bgpic_setup(Scene *scene, View3D *v3d, Image *ima, ImageUser *iuser) +{ + if (BKE_image_is_stereo(ima)) { + iuser->flag |= IMA_SHOW_STEREO; + + if ((scene->r.scemode & R_MULTIVIEW) == 0) { + iuser->multiview_eye = STEREO_LEFT_ID; + } + else if (v3d->stereo3d_camera != STEREO_3D_ID) { + /* show only left or right camera */ + iuser->multiview_eye = v3d->stereo3d_camera; + } + + BKE_image_multiview_index(ima, iuser); + } + else { + iuser->flag &= ~IMA_SHOW_STEREO; + } +} + +static void view3d_draw_bgpic(Scene *scene, ARegion *ar, View3D *v3d, + const bool do_foreground, const bool do_camera_frame) +{ + RegionView3D *rv3d = ar->regiondata; + int fg_flag = do_foreground ? V3D_BGPIC_FOREGROUND : 0; + + for (BGpic *bgpic = v3d->bgpicbase.first; bgpic; bgpic = bgpic->next) { + bgpic->iuser.scene = scene; /* Needed for render results. */ + + if ((bgpic->flag & V3D_BGPIC_FOREGROUND) != fg_flag) + continue; + + if ((bgpic->view == 0) || /* zero for any */ + (bgpic->view & (1 << rv3d->view)) || /* check agaist flags */ + (rv3d->persp == RV3D_CAMOB && bgpic->view == (1 << RV3D_VIEW_CAMERA))) + { + float image_aspect[2]; + float x1, y1, x2, y2, centx, centy; + + void *lock; + + Image *ima = NULL; + + /* disable individual images */ + if ((bgpic->flag & V3D_BGPIC_DISABLED)) + continue; + + ImBuf *ibuf = NULL; + ImBuf *freeibuf = NULL; + ImBuf *releaseibuf = NULL; + if (bgpic->source == V3D_BGPIC_IMAGE) { + ima = bgpic->ima; + if (ima == NULL) + continue; + BKE_image_user_frame_calc(&bgpic->iuser, CFRA, 0); + if (ima->source == IMA_SRC_SEQUENCE && !(bgpic->iuser.flag & IMA_USER_FRAME_IN_RANGE)) { + ibuf = NULL; /* frame is out of range, dont show */ + } + else { + view3d_stereo_bgpic_setup(scene, v3d, ima, &bgpic->iuser); + ibuf = BKE_image_acquire_ibuf(ima, &bgpic->iuser, &lock); + releaseibuf = ibuf; + } + + image_aspect[0] = ima->aspx; + image_aspect[1] = ima->aspy; + } + else if (bgpic->source == V3D_BGPIC_MOVIE) { + /* TODO: skip drawing when out of frame range (as image sequences do above) */ + MovieClip *clip = NULL; + + if (bgpic->flag & V3D_BGPIC_CAMERACLIP) { + if (scene->camera) + clip = BKE_object_movieclip_get(scene, scene->camera, true); + } + else { + clip = bgpic->clip; + } + + if (clip == NULL) + continue; + + BKE_movieclip_user_set_frame(&bgpic->cuser, CFRA); + ibuf = BKE_movieclip_get_ibuf(clip, &bgpic->cuser); + + image_aspect[0] = clip->aspx; + image_aspect[1] = clip->aspy; + + /* working with ibuf from image and clip has got different workflow now. + * ibuf acquired from clip is referenced by cache system and should + * be dereferenced after usage. */ + freeibuf = ibuf; + } + else { + /* perhaps when loading future files... */ + BLI_assert(0); + copy_v2_fl(image_aspect, 1.0f); + } + + if (ibuf == NULL) + continue; + + if ((ibuf->rect == NULL && ibuf->rect_float == NULL) || ibuf->channels != 4) { /* invalid image format */ + if (freeibuf) + IMB_freeImBuf(freeibuf); + if (releaseibuf) + BKE_image_release_ibuf(ima, releaseibuf, lock); + + continue; + } + + if (ibuf->rect == NULL) + IMB_rect_from_float(ibuf); + + if (rv3d->persp == RV3D_CAMOB) { + + if (do_camera_frame) { + rctf vb; + ED_view3d_calc_camera_border(scene, ar, v3d, rv3d, &vb, false); + x1 = vb.xmin; + y1 = vb.ymin; + x2 = vb.xmax; + y2 = vb.ymax; + } + else { + x1 = ar->winrct.xmin; + y1 = ar->winrct.ymin; + x2 = ar->winrct.xmax; + y2 = ar->winrct.ymax; + } + + /* apply offset last - camera offset is different to offset in blender units */ + /* so this has some sane way of working - this matches camera's shift _exactly_ */ + { + const float max_dim = max_ff(x2 - x1, y2 - y1); + const float xof_scale = bgpic->xof * max_dim; + const float yof_scale = bgpic->yof * max_dim; + + x1 += xof_scale; + y1 += yof_scale; + x2 += xof_scale; + y2 += yof_scale; + } + + centx = (x1 + x2) * 0.5f; + centy = (y1 + y2) * 0.5f; + + /* aspect correction */ + if (bgpic->flag & V3D_BGPIC_CAMERA_ASPECT) { + /* apply aspect from clip */ + const float w_src = ibuf->x * image_aspect[0]; + const float h_src = ibuf->y * image_aspect[1]; + + /* destination aspect is already applied from the camera frame */ + const float w_dst = x1 - x2; + const float h_dst = y1 - y2; + + const float asp_src = w_src / h_src; + const float asp_dst = w_dst / h_dst; + + if (fabsf(asp_src - asp_dst) >= FLT_EPSILON) { + if ((asp_src > asp_dst) == ((bgpic->flag & V3D_BGPIC_CAMERA_CROP) != 0)) { + /* fit X */ + const float div = asp_src / asp_dst; + x1 = ((x1 - centx) * div) + centx; + x2 = ((x2 - centx) * div) + centx; + } + else { + /* fit Y */ + const float div = asp_dst / asp_src; + y1 = ((y1 - centy) * div) + centy; + y2 = ((y2 - centy) * div) + centy; + } + } + } + } + else { + float tvec[3]; + float sco[2]; + const float mval_f[2] = {1.0f, 0.0f}; + const float co_zero[3] = {0}; + + /* calc window coord */ + float zfac = ED_view3d_calc_zfac(rv3d, co_zero, NULL); + ED_view3d_win_to_delta(ar, mval_f, tvec, zfac); + float fac = 1.0f / max_ff(fabsf(tvec[0]), max_ff(fabsf(tvec[1]), fabsf(tvec[2]))); /* largest abs axis */ + float asp = (float)ibuf->y / (float)ibuf->x; + + zero_v3(tvec); + ED_view3d_project_float_v2_m4(ar, tvec, sco, rv3d->persmat); + + x1 = sco[0] + fac * (bgpic->xof - bgpic->size); + y1 = sco[1] + asp * fac * (bgpic->yof - bgpic->size); + x2 = sco[0] + fac * (bgpic->xof + bgpic->size); + y2 = sco[1] + asp * fac * (bgpic->yof + bgpic->size); + + centx = (x1 + x2) / 2.0f; + centy = (y1 + y2) / 2.0f; + } + + /* complete clip? */ + rctf clip_rect; + BLI_rctf_init(&clip_rect, x1, x2, y1, y2); + if (bgpic->rotation) { + BLI_rctf_rotate_expand(&clip_rect, &clip_rect, bgpic->rotation); + } + + if (clip_rect.xmax < 0 || clip_rect.ymax < 0 || clip_rect.xmin > ar->winx || clip_rect.ymin > ar->winy) { + if (freeibuf) + IMB_freeImBuf(freeibuf); + if (releaseibuf) + BKE_image_release_ibuf(ima, releaseibuf, lock); + + continue; + } + + float zoomx = (x2 - x1) / ibuf->x; + float zoomy = (y2 - y1) / ibuf->y; + + /* for some reason; zoomlevels down refuses to use GL_ALPHA_SCALE */ + if (zoomx < 1.0f || zoomy < 1.0f) { + float tzoom = min_ff(zoomx, zoomy); + int mip = 0; + + if ((ibuf->userflags & IB_MIPMAP_INVALID) != 0) { + IMB_remakemipmap(ibuf, 0); + ibuf->userflags &= ~IB_MIPMAP_INVALID; + } + else if (ibuf->mipmap[0] == NULL) + IMB_makemipmap(ibuf, 0); + + while (tzoom < 1.0f && mip < 8 && ibuf->mipmap[mip]) { + tzoom *= 2.0f; + zoomx *= 2.0f; + zoomy *= 2.0f; + mip++; + } + if (mip > 0) + ibuf = ibuf->mipmap[mip - 1]; + } + + if (v3d->zbuf) glDisable(GL_DEPTH_TEST); + glDepthMask(GL_FALSE); + + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + + glMatrixMode(GL_PROJECTION); + glPushMatrix(); + glMatrixMode(GL_MODELVIEW); + glPushMatrix(); + ED_region_pixelspace(ar); + + glTranslatef(centx, centy, 0.0); + glRotatef(RAD2DEGF(-bgpic->rotation), 0.0f, 0.0f, 1.0f); + + if (bgpic->flag & V3D_BGPIC_FLIP_X) { + zoomx *= -1.0f; + x1 = x2; + } + if (bgpic->flag & V3D_BGPIC_FLIP_Y) { + zoomy *= -1.0f; + y1 = y2; + } + glPixelZoom(zoomx, zoomy); + glColor4f(1.0f, 1.0f, 1.0f, 1.0f - bgpic->blend); + + /* could not use glaDrawPixelsAuto because it could fallback to + * glaDrawPixelsSafe in some cases, which will end up in missing + * alpha transparency for the background image (sergey) + */ + glaDrawPixelsTex(x1 - centx, y1 - centy, ibuf->x, ibuf->y, GL_RGBA, GL_UNSIGNED_BYTE, GL_LINEAR, ibuf->rect); + + glPixelZoom(1.0, 1.0); + glPixelTransferf(GL_ALPHA_SCALE, 1.0f); + + glMatrixMode(GL_PROJECTION); + glPopMatrix(); + glMatrixMode(GL_MODELVIEW); + glPopMatrix(); + + glDisable(GL_BLEND); + + glDepthMask(GL_TRUE); + if (v3d->zbuf) glEnable(GL_DEPTH_TEST); + + if (freeibuf) + IMB_freeImBuf(freeibuf); + if (releaseibuf) + BKE_image_release_ibuf(ima, releaseibuf, lock); + } + } +} + +static void view3d_draw_bgpic_test(Scene *scene, ARegion *ar, View3D *v3d, + const bool do_foreground, const bool do_camera_frame) +{ + RegionView3D *rv3d = ar->regiondata; + + if ((v3d->flag & V3D_DISPBGPICS) == 0) + return; + + /* disabled - mango request, since footage /w only render is quite useful + * and this option is easy to disable all background images at once */ +#if 0 + if (v3d->flag2 & V3D_RENDER_OVERRIDE) + return; +#endif + + if ((rv3d->view == RV3D_VIEW_USER) || (rv3d->persp != RV3D_ORTHO)) { + if (rv3d->persp == RV3D_CAMOB) { + view3d_draw_bgpic(scene, ar, v3d, do_foreground, do_camera_frame); + } + } + else { + view3d_draw_bgpic(scene, ar, v3d, do_foreground, do_camera_frame); + } +} + +/* ****************** View3d afterdraw *************** */ + +typedef struct View3DAfter { + struct View3DAfter *next, *prev; + struct BaseLegacy *base; + short dflag; +} View3DAfter; + +/* temp storage of Objects that need to be drawn as last */ +void ED_view3d_after_add(ListBase *lb, BaseLegacy *base, const short dflag) +{ + View3DAfter *v3da = MEM_callocN(sizeof(View3DAfter), "View 3d after"); + BLI_assert((base->flag_legacy & OB_FROMDUPLI) == 0); + BLI_addtail(lb, v3da); + v3da->base = base; + v3da->dflag = dflag; +} + +/* disables write in zbuffer and draws it over */ +static void view3d_draw_transp(Scene *scene, SceneLayer *sl, ARegion *ar, View3D *v3d) +{ + View3DAfter *v3da; + + glDepthMask(GL_FALSE); + v3d->transp = true; + + while ((v3da = BLI_pophead(&v3d->afterdraw_transp))) { + draw_object(scene, sl, ar, v3d, v3da->base, v3da->dflag); + MEM_freeN(v3da); + } + v3d->transp = false; + + glDepthMask(GL_TRUE); + +} + +/* clears zbuffer and draws it over */ +static void view3d_draw_xray(Scene *scene, SceneLayer *sl, ARegion *ar, View3D *v3d, bool *clear) +{ + if (*clear && v3d->zbuf) { + glClear(GL_DEPTH_BUFFER_BIT); + *clear = false; + } + + v3d->xray = true; + View3DAfter *v3da; + while ((v3da = BLI_pophead(&v3d->afterdraw_xray))) { + draw_object(scene, sl, ar, v3d, v3da->base, v3da->dflag); + MEM_freeN(v3da); + } + v3d->xray = false; +} + + +/* clears zbuffer and draws it over */ +static void view3d_draw_xraytransp(Scene *scene, SceneLayer *sl, ARegion *ar, View3D *v3d, const bool clear) +{ + if (clear && v3d->zbuf) + glClear(GL_DEPTH_BUFFER_BIT); + + v3d->xray = true; + v3d->transp = true; + + glDepthMask(GL_FALSE); + + View3DAfter *v3da; + while ((v3da = BLI_pophead(&v3d->afterdraw_xraytransp))) { + draw_object(scene, sl, ar, v3d, v3da->base, v3da->dflag); + MEM_freeN(v3da); + } + + v3d->transp = false; + v3d->xray = false; + + glDepthMask(GL_TRUE); +} + +/* *********************** */ + +/* + * In most cases call draw_dupli_objects, + * draw_dupli_objects_color was added because when drawing set dupli's + * we need to force the color + */ + +#if 0 +int dupli_ob_sort(void *arg1, void *arg2) +{ + void *p1 = ((DupliObject *)arg1)->ob; + void *p2 = ((DupliObject *)arg2)->ob; + int val = 0; + if (p1 < p2) val = -1; + else if (p1 > p2) val = 1; + return val; +} +#endif + + +static DupliObject *dupli_step(DupliObject *dob) +{ + while (dob && dob->no_draw) + dob = dob->next; + return dob; +} + +static void draw_dupli_objects_color( + Scene *scene, SceneLayer *sl, ARegion *ar, View3D *v3d, BaseLegacy *base, + const short dflag, const int color) +{ + RegionView3D *rv3d = ar->regiondata; + ListBase *lb; + LodLevel *savedlod; + Base tbase = {NULL}; + BoundBox bb, *bb_tmp; /* use a copy because draw_object, calls clear_mesh_caches */ + GLuint displist = 0; + unsigned char color_rgb[3]; + const short dflag_dupli = dflag | DRAW_CONSTCOLOR; + short transflag; + bool use_displist = false; /* -1 is initialize */ + char dt; + short dtx; + DupliApplyData *apply_data; + + if ((base->flag & BASE_VISIBLED) == 0) return; + if ((base->object->restrictflag & OB_RESTRICT_RENDER) && (v3d->flag2 & V3D_RENDER_OVERRIDE)) return; + + if (dflag & DRAW_CONSTCOLOR) { + BLI_assert(color == TH_UNDEFINED); + } + else { + UI_GetThemeColorBlend3ubv(color, TH_BACK, 0.5f, color_rgb); + } + + tbase.flag_legacy = OB_FROMDUPLI | base->flag_legacy; + tbase.flag = base->flag; + lb = object_duplilist(G.main->eval_ctx, scene, base->object); + // BLI_listbase_sort(lb, dupli_ob_sort); /* might be nice to have if we have a dupli list with mixed objects. */ + + apply_data = duplilist_apply(base->object, scene, lb); + + DupliObject *dob_prev = NULL, *dob_next = NULL; + DupliObject *dob = dupli_step(lb->first); + if (dob) dob_next = dupli_step(dob->next); + + for (; dob; dob_prev = dob, dob = dob_next, dob_next = dob_next ? dupli_step(dob_next->next) : NULL) { + bool testbb = false; + + tbase.object = dob->ob; + + /* Make sure lod is updated from dupli's position */ + savedlod = dob->ob->currentlod; + +#ifdef WITH_GAMEENGINE + if (rv3d->rflag & RV3D_IS_GAME_ENGINE) { + BKE_object_lod_update(dob->ob, rv3d->viewinv[3]); + } +#endif + + /* extra service: draw the duplicator in drawtype of parent, minimum taken + * to allow e.g. boundbox box objects in groups for LOD */ + dt = tbase.object->dt; + tbase.object->dt = MIN2(tbase.object->dt, base->object->dt); + + /* inherit draw extra, but not if a boundbox under the assumption that this + * is intended to speed up drawing, and drawing extra (especially wire) can + * slow it down too much */ + dtx = tbase.object->dtx; + if (tbase.object->dt != OB_BOUNDBOX) + tbase.object->dtx = base->object->dtx; + + /* negative scale flag has to propagate */ + transflag = tbase.object->transflag; + + if (is_negative_m4(dob->mat)) + tbase.object->transflag |= OB_NEG_SCALE; + else + tbase.object->transflag &= ~OB_NEG_SCALE; + + /* should move outside the loop but possible color is set in draw_object still */ + if ((dflag & DRAW_CONSTCOLOR) == 0) { + glColor3ubv(color_rgb); + } + + /* generate displist, test for new object */ + if (dob_prev && dob_prev->ob != dob->ob) { + if (use_displist == true) + glDeleteLists(displist, 1); + + use_displist = false; + } + + if ((bb_tmp = BKE_object_boundbox_get(dob->ob))) { + bb = *bb_tmp; /* must make a copy */ + testbb = true; + } + + if (!testbb || ED_view3d_boundbox_clip_ex(rv3d, &bb, dob->mat)) { + /* generate displist */ + if (use_displist == false) { + + /* note, since this was added, its checked (dob->type == OB_DUPLIGROUP) + * however this is very slow, it was probably needed for the NLA + * offset feature (used in group-duplicate.blend but no longer works in 2.5) + * so for now it should be ok to - campbell */ + + if ( /* if this is the last no need to make a displist */ + (dob_next == NULL || dob_next->ob != dob->ob) || + /* lamp drawing messes with matrices, could be handled smarter... but this works */ + (dob->ob->type == OB_LAMP) || + (dob->type == OB_DUPLIGROUP && dob->animated) || + !bb_tmp || + draw_glsl_material(scene, dob->ob, v3d, dt) || + check_object_draw_texture(scene, v3d, dt) || + (v3d->flag2 & V3D_SOLID_MATCAP) != 0) + { + // printf("draw_dupli_objects_color: skipping displist for %s\n", dob->ob->id.name + 2); + use_displist = false; + } + else { + // printf("draw_dupli_objects_color: using displist for %s\n", dob->ob->id.name + 2); + + /* disable boundbox check for list creation */ + BKE_object_boundbox_flag(dob->ob, BOUNDBOX_DISABLED, 1); + /* need this for next part of code */ + unit_m4(dob->ob->obmat); /* obmat gets restored */ + + displist = glGenLists(1); + glNewList(displist, GL_COMPILE); + draw_object(scene, sl, ar, v3d, &tbase, dflag_dupli); + glEndList(); + + use_displist = true; + BKE_object_boundbox_flag(dob->ob, BOUNDBOX_DISABLED, 0); + } + } + + if (use_displist) { + glPushMatrix(); + glMultMatrixf(dob->mat); + glCallList(displist); + glPopMatrix(); + } + else { + copy_m4_m4(dob->ob->obmat, dob->mat); + GPU_begin_dupli_object(dob); + draw_object(scene, sl, ar, v3d, &tbase, dflag_dupli); + GPU_end_dupli_object(); + } + } + + tbase.object->dt = dt; + tbase.object->dtx = dtx; + tbase.object->transflag = transflag; + tbase.object->currentlod = savedlod; + } + + if (apply_data) { + duplilist_restore(lb, apply_data); + duplilist_free_apply_data(apply_data); + } + + free_object_duplilist(lb); + + if (use_displist) + glDeleteLists(displist, 1); +} + +void draw_dupli_objects(Scene *scene, SceneLayer *sl, ARegion *ar, View3D *v3d, BaseLegacy *base) +{ + /* define the color here so draw_dupli_objects_color can be called + * from the set loop */ + + int color = (base->flag & BASE_SELECTED) ? TH_SELECT : TH_WIRE; + /* debug */ + if (base->object->dup_group && base->object->dup_group->id.us < 1) + color = TH_REDALERT; + + draw_dupli_objects_color(scene, sl, ar, v3d, base, 0, color); +} + +/* XXX warning, not using gpu offscreen here */ +void view3d_update_depths_rect(ARegion *ar, ViewDepths *d, rcti *rect) +{ + /* clamp rect by region */ + rcti r = { + .xmin = 0, + .xmax = ar->winx - 1, + .ymin = 0, + .ymax = ar->winy - 1 + }; + + /* Constrain rect to depth bounds */ + BLI_rcti_isect(&r, rect, rect); + + /* assign values to compare with the ViewDepths */ + int x = rect->xmin; + int y = rect->ymin; + + int w = BLI_rcti_size_x(rect); + int h = BLI_rcti_size_y(rect); + + if (w <= 0 || h <= 0) { + if (d->depths) + MEM_freeN(d->depths); + d->depths = NULL; + + d->damaged = false; + } + else if (d->w != w || + d->h != h || + d->x != x || + d->y != y || + d->depths == NULL + ) + { + d->x = x; + d->y = y; + d->w = w; + d->h = h; + + if (d->depths) + MEM_freeN(d->depths); + + d->depths = MEM_mallocN(sizeof(float) * d->w * d->h, "View depths Subset"); + + d->damaged = true; + } + + if (d->damaged) { + /* XXX using special function here, it doesn't use the gpu offscreen system */ + view3d_opengl_read_Z_pixels(ar, d->x, d->y, d->w, d->h, GL_DEPTH_COMPONENT, GL_FLOAT, d->depths); + glGetDoublev(GL_DEPTH_RANGE, d->depth_range); + d->damaged = false; + } +} + +/* note, with nouveau drivers the glReadPixels() is very slow. [#24339] */ +void ED_view3d_depth_update(ARegion *ar) +{ + RegionView3D *rv3d = ar->regiondata; + + /* Create storage for, and, if necessary, copy depth buffer */ + if (!rv3d->depths) rv3d->depths = MEM_callocN(sizeof(ViewDepths), "ViewDepths"); + if (rv3d->depths) { + ViewDepths *d = rv3d->depths; + if (d->w != ar->winx || + d->h != ar->winy || + !d->depths) + { + d->w = ar->winx; + d->h = ar->winy; + if (d->depths) + MEM_freeN(d->depths); + d->depths = MEM_mallocN(sizeof(float) * d->w * d->h, "View depths"); + d->damaged = true; + } + + if (d->damaged) { + view3d_opengl_read_pixels(ar, 0, 0, d->w, d->h, GL_DEPTH_COMPONENT, GL_FLOAT, d->depths); + glGetDoublev(GL_DEPTH_RANGE, d->depth_range); + + d->damaged = false; + } + } +} + +/* utility function to find the closest Z value, use for autodepth */ +float view3d_depth_near(ViewDepths *d) +{ + /* convert to float for comparisons */ + const float near = (float)d->depth_range[0]; + const float far_real = (float)d->depth_range[1]; + float far = far_real; + + const float *depths = d->depths; + float depth = FLT_MAX; + int i = (int)d->w * (int)d->h; /* cast to avoid short overflow */ + + /* far is both the starting 'far' value + * and the closest value found. */ + while (i--) { + depth = *depths++; + if ((depth < far) && (depth > near)) { + far = depth; + } + } + + return far == far_real ? FLT_MAX : far; +} + +void ED_view3d_draw_depth_gpencil(Scene *scene, ARegion *ar, View3D *v3d) +{ + short zbuf = v3d->zbuf; + RegionView3D *rv3d = ar->regiondata; + + view3d_winmatrix_set(ar, v3d, NULL); + view3d_viewmatrix_set(scene, v3d, rv3d); /* note: calls BKE_object_where_is_calc for camera... */ + + mul_m4_m4m4(rv3d->persmat, rv3d->winmat, rv3d->viewmat); + invert_m4_m4(rv3d->persinv, rv3d->persmat); + invert_m4_m4(rv3d->viewinv, rv3d->viewmat); + + glClear(GL_DEPTH_BUFFER_BIT); + + glLoadMatrixf(rv3d->viewmat); + + v3d->zbuf = true; + glEnable(GL_DEPTH_TEST); + + if (v3d->flag2 & V3D_SHOW_GPENCIL) { + ED_gpencil_draw_view3d(NULL, scene, v3d, ar, true); + } + + v3d->zbuf = zbuf; +} + +void ED_view3d_draw_depth(Scene *scene, ARegion *ar, View3D *v3d, bool alphaoverride) +{ + RegionView3D *rv3d = ar->regiondata; + Base *base; + short zbuf = v3d->zbuf; + short flag = v3d->flag; + float glalphaclip = U.glalphaclip; + int obcenter_dia = U.obcenter_dia; + SceneLayer *sl = BKE_scene_layer_context_active(scene); + /* no need for color when drawing depth buffer */ + const short dflag_depth = DRAW_CONSTCOLOR; + /* temp set drawtype to solid */ + /* Setting these temporarily is not nice */ + v3d->flag &= ~V3D_SELECT_OUTLINE; + U.glalphaclip = alphaoverride ? 0.5f : glalphaclip; /* not that nice but means we wont zoom into billboards */ + U.obcenter_dia = 0; + + view3d_winmatrix_set(ar, v3d, NULL); + view3d_viewmatrix_set(scene, v3d, rv3d); /* note: calls BKE_object_where_is_calc for camera... */ + + mul_m4_m4m4(rv3d->persmat, rv3d->winmat, rv3d->viewmat); + invert_m4_m4(rv3d->persinv, rv3d->persmat); + invert_m4_m4(rv3d->viewinv, rv3d->viewmat); + + glClear(GL_DEPTH_BUFFER_BIT); + + glLoadMatrixf(rv3d->viewmat); + + if (rv3d->rflag & RV3D_CLIPPING) { + ED_view3d_clipping_set(rv3d); + } + /* get surface depth without bias */ + rv3d->rflag |= RV3D_ZOFFSET_DISABLED; + + v3d->zbuf = true; + glEnable(GL_DEPTH_TEST); + + /* draw set first */ + if (scene->set) { + Scene *sce_iter; + for (SETLOOPER(scene->set, sce_iter, base)) { + if ((base->flag & BASE_VISIBLED) != 0) { + draw_object(scene, sl, ar, v3d, base, 0); + if (base->object->transflag & OB_DUPLI) { + draw_dupli_objects_color(scene, sl, ar, v3d, base, dflag_depth, TH_UNDEFINED); + } + } + } + } + + for (base = sl->object_bases.first; base; base = base->next) { + if ((base->flag & BASE_VISIBLED) != 0) { + /* dupli drawing */ + if (base->object->transflag & OB_DUPLI) { + draw_dupli_objects_color(scene, sl, ar, v3d, base, dflag_depth, TH_UNDEFINED); + } + draw_object(scene, sl, ar, v3d, base, dflag_depth); + } + } + + /* this isn't that nice, draw xray objects as if they are normal */ + if (v3d->afterdraw_transp.first || + v3d->afterdraw_xray.first || + v3d->afterdraw_xraytransp.first) + { + View3DAfter *v3da; + int mask_orig; + + v3d->xray = true; + + /* transp materials can change the depth mask, see #21388 */ + glGetIntegerv(GL_DEPTH_WRITEMASK, &mask_orig); + + + if (v3d->afterdraw_xray.first || v3d->afterdraw_xraytransp.first) { + glDepthFunc(GL_ALWAYS); /* always write into the depth bufer, overwriting front z values */ + for (v3da = v3d->afterdraw_xray.first; v3da; v3da = v3da->next) { + draw_object(scene, sl, ar, v3d, v3da->base, dflag_depth); + } + glDepthFunc(GL_LEQUAL); /* Now write the depth buffer normally */ + } + + /* draw 3 passes, transp/xray/xraytransp */ + v3d->xray = false; + v3d->transp = true; + while ((v3da = BLI_pophead(&v3d->afterdraw_transp))) { + draw_object(scene, sl, ar, v3d, v3da->base, dflag_depth); + MEM_freeN(v3da); + } + + v3d->xray = true; + v3d->transp = false; + while ((v3da = BLI_pophead(&v3d->afterdraw_xray))) { + draw_object(scene, sl, ar, v3d, v3da->base, dflag_depth); + MEM_freeN(v3da); + } + + v3d->xray = true; + v3d->transp = true; + while ((v3da = BLI_pophead(&v3d->afterdraw_xraytransp))) { + draw_object(scene, sl, ar, v3d, v3da->base, dflag_depth); + MEM_freeN(v3da); + } + + + v3d->xray = false; + v3d->transp = false; + + glDepthMask(mask_orig); + } + + if (rv3d->rflag & RV3D_CLIPPING) { + ED_view3d_clipping_disable(); + } + rv3d->rflag &= ~RV3D_ZOFFSET_DISABLED; + + v3d->zbuf = zbuf; + if (!v3d->zbuf) glDisable(GL_DEPTH_TEST); + + U.glalphaclip = glalphaclip; + v3d->flag = flag; + U.obcenter_dia = obcenter_dia; +} + +typedef struct View3DShadow { + struct View3DShadow *next, *prev; + GPULamp *lamp; +} View3DShadow; + +static void gpu_render_lamp_update(Scene *scene, View3D *v3d, + Object *ob, Object *par, + float obmat[4][4], unsigned int lay, + ListBase *shadows, SceneRenderLayer *srl) +{ + GPULamp *lamp = GPU_lamp_from_blender(scene, ob, par); + + if (lamp) { + Lamp *la = (Lamp *)ob->data; + + GPU_lamp_update(lamp, lay, (ob->restrictflag & OB_RESTRICT_RENDER), obmat); + GPU_lamp_update_colors(lamp, la->r, la->g, la->b, la->energy); + + unsigned int layers = lay & v3d->lay; + if (srl) + layers &= srl->lay; + + if (layers && + GPU_lamp_has_shadow_buffer(lamp) && + /* keep last, may do string lookup */ + GPU_lamp_override_visible(lamp, srl, NULL)) + { + View3DShadow *shadow = MEM_callocN(sizeof(View3DShadow), "View3DShadow"); + shadow->lamp = lamp; + BLI_addtail(shadows, shadow); + } + } +} + +static void gpu_update_lamps_shadows_world(Scene *scene, View3D *v3d) +{ + ListBase shadows; + Scene *sce_iter; + Base *base; + World *world = scene->world; + SceneRenderLayer *srl = v3d->scenelock ? BLI_findlink(&scene->r.layers, scene->r.actlay) : NULL; + + BLI_listbase_clear(&shadows); + + /* update lamp transform and gather shadow lamps */ + for (SETLOOPER(scene, sce_iter, base)) { + Object *ob = base->object; + + if (ob->type == OB_LAMP) + gpu_render_lamp_update(scene, v3d, ob, NULL, ob->obmat, ob->lay, &shadows, srl); + + if (ob->transflag & OB_DUPLI) { + DupliObject *dob; + ListBase *lb = object_duplilist(G.main->eval_ctx, scene, ob); + + for (dob = lb->first; dob; dob = dob->next) + if (dob->ob->type == OB_LAMP) + gpu_render_lamp_update(scene, v3d, dob->ob, ob, dob->mat, ob->lay, &shadows, srl); + + free_object_duplilist(lb); + } + } + + /* render shadows after updating all lamps, nested object_duplilist + * don't work correct since it's replacing object matrices */ + for (View3DShadow *shadow = shadows.first; shadow; shadow = shadow->next) { + /* this needs to be done better .. */ + float viewmat[4][4], winmat[4][4]; + ARegion ar = {NULL}; + RegionView3D rv3d = {{{0}}}; + + int drawtype = v3d->drawtype; + int lay = v3d->lay; + int flag2 = v3d->flag2; + + v3d->drawtype = OB_SOLID; + v3d->lay &= GPU_lamp_shadow_layer(shadow->lamp); + v3d->flag2 &= ~(V3D_SOLID_TEX | V3D_SHOW_SOLID_MATCAP); + v3d->flag2 |= V3D_RENDER_OVERRIDE | V3D_RENDER_SHADOW; + + int winsize; + GPU_lamp_shadow_buffer_bind(shadow->lamp, viewmat, &winsize, winmat); + + ar.regiondata = &rv3d; + ar.regiontype = RGN_TYPE_WINDOW; + rv3d.persp = RV3D_CAMOB; + copy_m4_m4(rv3d.winmat, winmat); + copy_m4_m4(rv3d.viewmat, viewmat); + invert_m4_m4(rv3d.viewinv, rv3d.viewmat); + mul_m4_m4m4(rv3d.persmat, rv3d.winmat, rv3d.viewmat); + invert_m4_m4(rv3d.persinv, rv3d.viewinv); + + /* no need to call ED_view3d_draw_offscreen_init since shadow buffers were already updated */ + ED_view3d_draw_offscreen( + scene, v3d, &ar, winsize, winsize, viewmat, winmat, + false, false, true, + NULL, NULL, NULL, NULL); + GPU_lamp_shadow_buffer_unbind(shadow->lamp); + + v3d->drawtype = drawtype; + v3d->lay = lay; + v3d->flag2 = flag2; + } + + BLI_freelistN(&shadows); + + /* update world values */ + if (world) { + GPU_mist_update_enable(world->mode & WO_MIST); + GPU_mist_update_values(world->mistype, world->miststa, world->mistdist, world->misi, &world->horr); + GPU_horizon_update_color(&world->horr); + GPU_ambient_update_color(&world->ambr); + GPU_zenith_update_color(&world->zenr); + } +} + +/* *********************** customdata **************** */ + +CustomDataMask ED_view3d_datamask(const Scene *scene, const View3D *v3d) +{ + CustomDataMask mask = 0; + const int drawtype = view3d_effective_drawtype(v3d); + + if (ELEM(drawtype, OB_TEXTURE, OB_MATERIAL) || + ((drawtype == OB_SOLID) && (v3d->flag2 & V3D_SOLID_TEX))) + { + mask |= CD_MASK_MTEXPOLY | CD_MASK_MLOOPUV | CD_MASK_MLOOPCOL; + + if (BKE_scene_use_new_shading_nodes(scene)) { + if (drawtype == OB_MATERIAL) + mask |= CD_MASK_ORCO; + } + else { + if ((scene->gm.matmode == GAME_MAT_GLSL && drawtype == OB_TEXTURE) || + (drawtype == OB_MATERIAL)) + { + mask |= CD_MASK_ORCO; + } + } + } + + return mask; +} + +/* goes over all modes and view3d settings */ +CustomDataMask ED_view3d_screen_datamask(const bScreen *screen) +{ + const Scene *scene = screen->scene; + CustomDataMask mask = CD_MASK_BAREMESH; + + /* check if we need tfaces & mcols due to view mode */ + for (const ScrArea *sa = screen->areabase.first; sa; sa = sa->next) { + if (sa->spacetype == SPACE_VIEW3D) { + mask |= ED_view3d_datamask(scene, sa->spacedata.first); + } + } + + return mask; +} + +/** + * Shared by #ED_view3d_draw_offscreen and #view3d_main_region_draw_objects + * + * \note \a C and \a grid_unit will be NULL when \a draw_offscreen is set. + * \note Drawing lamps and opengl render uses this, so dont do grease pencil or view widgets here. + */ +static void view3d_draw_objects( + const bContext *C, + Scene *scene, View3D *v3d, ARegion *ar, + const char **grid_unit, + const bool do_bgpic, const bool draw_offscreen, GPUFX *fx) +{ + SceneLayer *sl = C ? CTX_data_scene_layer(C) : BKE_scene_layer_render_active(scene); + RegionView3D *rv3d = ar->regiondata; + Base *base; + const bool do_camera_frame = !draw_offscreen; + const bool draw_grids = !draw_offscreen && (v3d->flag2 & V3D_RENDER_OVERRIDE) == 0; + const bool draw_floor = (rv3d->view == RV3D_VIEW_USER) || (rv3d->persp != RV3D_ORTHO); + /* only draw grids after in solid modes, else it hovers over mesh wires */ + const bool draw_grids_after = draw_grids && draw_floor && (v3d->drawtype > OB_WIRE) && fx; + bool do_composite_xray = false; + bool xrayclear = true; + + if (!draw_offscreen) { + ED_region_draw_cb_draw(C, ar, REGION_DRAW_PRE_VIEW); + } + + if (rv3d->rflag & RV3D_CLIPPING) + view3d_draw_clipping(rv3d); + + /* set zbuffer after we draw clipping region */ + v3d->zbuf = VP_legacy_use_depth(scene, v3d); + + if (v3d->zbuf) { + glEnable(GL_DEPTH_TEST); + } + + /* ortho grid goes first, does not write to depth buffer and doesn't need depth test so it will override + * objects if done last */ + if (draw_grids) { + /* needs to be done always, gridview is adjusted in drawgrid() now, but only for ortho views. */ + rv3d->gridview = ED_view3d_grid_scale(scene, v3d, grid_unit); + + if (!draw_floor) { + ED_region_pixelspace(ar); + *grid_unit = NULL; /* drawgrid need this to detect/affect smallest valid unit... */ + VP_legacy_drawgrid(&scene->unit, ar, v3d, grid_unit); + /* XXX make function? replaces persp(1) */ + glMatrixMode(GL_PROJECTION); + glLoadMatrixf(rv3d->winmat); + glMatrixMode(GL_MODELVIEW); + glLoadMatrixf(rv3d->viewmat); + } + else if (!draw_grids_after) { + VP_legacy_drawfloor(scene, v3d, grid_unit, true); + } + } + + /* important to do before clipping */ + if (do_bgpic) { + view3d_draw_bgpic_test(scene, ar, v3d, false, do_camera_frame); + } + + if (rv3d->rflag & RV3D_CLIPPING) { + ED_view3d_clipping_set(rv3d); + } + + /* draw set first */ + if (scene->set) { + const short dflag = DRAW_CONSTCOLOR | DRAW_SCENESET; + Scene *sce_iter; + for (SETLOOPER(scene->set, sce_iter, base)) { + if ((base->flag & BASE_VISIBLED) != 0) { + UI_ThemeColorBlend(TH_WIRE, TH_BACK, 0.6f); + draw_object(scene, sl, ar, v3d, base, dflag); + + if (base->object->transflag & OB_DUPLI) { + draw_dupli_objects_color(scene, sl, ar, v3d, base, dflag, TH_UNDEFINED); + } + } + } + + /* Transp and X-ray afterdraw stuff for sets is done later */ + } + + if (draw_offscreen) { + for (base = sl->object_bases.first; base; base = base->next) { + if ((base->flag & BASE_VISIBLED) != 0) { + /* dupli drawing */ + if (base->object->transflag & OB_DUPLI) + draw_dupli_objects(scene, sl, ar, v3d, base); + + draw_object(scene, sl, ar, v3d, base, 0); + } + } + } + else { + unsigned int lay_used = 0; + + /* then draw not selected and the duplis, but skip editmode object */ + for (base = sl->object_bases.first; base; base = base->next) { + lay_used |= base->lay; + + if ((base->flag & BASE_VISIBLED) != 0) { + + /* dupli drawing */ + if (base->object->transflag & OB_DUPLI) { + draw_dupli_objects(scene, sl, ar, v3d, base); + } + if ((base->flag & BASE_SELECTED) == 0) { + if (base->object != scene->obedit) + draw_object(scene, sl, ar, v3d, base, 0); + } + } + } + + /* mask out localview */ + v3d->lay_used = lay_used & ((1 << 20) - 1); + + /* draw selected and editmode */ + for (base = sl->object_bases.first; base; base = base->next) { + if ((base->flag & BASE_VISIBLED) != 0) { + if (base->object == scene->obedit || (base->flag & BASE_SELECTED)) { + draw_object(scene, sl, ar, v3d, base, 0); + } + } + } + } + + /* perspective floor goes last to use scene depth and avoid writing to depth buffer */ + if (draw_grids_after) { + VP_legacy_drawfloor(scene, v3d, grid_unit, false); + } + + /* must be before xray draw which clears the depth buffer */ + if (v3d->flag2 & V3D_SHOW_GPENCIL) { + wmWindowManager *wm = (C != NULL) ? CTX_wm_manager(C) : NULL; + + /* must be before xray draw which clears the depth buffer */ + if (v3d->zbuf) glDisable(GL_DEPTH_TEST); + ED_gpencil_draw_view3d(wm, scene, v3d, ar, true); + if (v3d->zbuf) glEnable(GL_DEPTH_TEST); + } + + /* transp and X-ray afterdraw stuff */ + if (v3d->afterdraw_transp.first) view3d_draw_transp(scene, sl, ar, v3d); + + /* always do that here to cleanup depth buffers if none needed */ + if (fx) { + do_composite_xray = v3d->zbuf && (v3d->afterdraw_xray.first || v3d->afterdraw_xraytransp.first); + GPU_fx_compositor_setup_XRay_pass(fx, do_composite_xray); + } + + if (v3d->afterdraw_xray.first) view3d_draw_xray(scene, sl, ar, v3d, &xrayclear); + if (v3d->afterdraw_xraytransp.first) view3d_draw_xraytransp(scene, sl, ar, v3d, xrayclear); + + if (fx && do_composite_xray) { + GPU_fx_compositor_XRay_resolve(fx); + } + + if (!draw_offscreen) { + ED_region_draw_cb_draw(C, ar, REGION_DRAW_POST_VIEW); + } + + if (rv3d->rflag & RV3D_CLIPPING) + ED_view3d_clipping_disable(); + + /* important to do after clipping */ + if (do_bgpic) { + view3d_draw_bgpic_test(scene, ar, v3d, true, do_camera_frame); + } + + if (!draw_offscreen) { + BIF_draw_manipulator(C); + } + + /* cleanup */ + if (v3d->zbuf) { + v3d->zbuf = false; + glDisable(GL_DEPTH_TEST); + } + + if ((v3d->flag2 & V3D_RENDER_SHADOW) == 0) { + GPU_free_images_old(); + } +} + +/** + * Store values from #RegionView3D, set when drawing. + * This is needed when we draw with to a viewport using a different matrix (offscreen drawing for example). + * + * Values set by #ED_view3d_update_viewmat should be handled here. + */ +struct RV3DMatrixStore { + float winmat[4][4]; + float viewmat[4][4]; + float viewinv[4][4]; + float persmat[4][4]; + float persinv[4][4]; + float viewcamtexcofac[4]; + float pixsize; +}; + +void *ED_view3d_mats_rv3d_backup(struct RegionView3D *rv3d) +{ + struct RV3DMatrixStore *rv3dmat = MEM_mallocN(sizeof(*rv3dmat), __func__); + copy_m4_m4(rv3dmat->winmat, rv3d->winmat); + copy_m4_m4(rv3dmat->viewmat, rv3d->viewmat); + copy_m4_m4(rv3dmat->persmat, rv3d->persmat); + copy_m4_m4(rv3dmat->persinv, rv3d->persinv); + copy_m4_m4(rv3dmat->viewinv, rv3d->viewinv); + copy_v4_v4(rv3dmat->viewcamtexcofac, rv3d->viewcamtexcofac); + rv3dmat->pixsize = rv3d->pixsize; + return (void *)rv3dmat; +} + +void ED_view3d_mats_rv3d_restore(struct RegionView3D *rv3d, void *rv3dmat_pt) +{ + struct RV3DMatrixStore *rv3dmat = rv3dmat_pt; + copy_m4_m4(rv3d->winmat, rv3dmat->winmat); + copy_m4_m4(rv3d->viewmat, rv3dmat->viewmat); + copy_m4_m4(rv3d->persmat, rv3dmat->persmat); + copy_m4_m4(rv3d->persinv, rv3dmat->persinv); + copy_m4_m4(rv3d->viewinv, rv3dmat->viewinv); + copy_v4_v4(rv3d->viewcamtexcofac, rv3dmat->viewcamtexcofac); + rv3d->pixsize = rv3dmat->pixsize; +} + +void ED_view3d_draw_offscreen_init(Scene *scene, View3D *v3d) +{ + /* shadow buffers, before we setup matrices */ + if (draw_glsl_material(scene, NULL, v3d, v3d->drawtype)) + gpu_update_lamps_shadows_world(scene, v3d); +} + +/* + * Function to clear the view + */ +static void view3d_main_region_clear(Scene *scene, View3D *v3d, ARegion *ar) +{ + if (scene->world && (v3d->flag3 & V3D_SHOW_WORLD)) { + VP_view3d_draw_background_world(scene, v3d, ar->regiondata); + } + else { + VP_view3d_draw_background_none(); + } +} + +/* ED_view3d_draw_offscreen_init should be called before this to initialize + * stuff like shadow buffers + */ +void ED_view3d_draw_offscreen( + Scene *scene, View3D *v3d, ARegion *ar, int winx, int winy, + float viewmat[4][4], float winmat[4][4], + bool do_bgpic, bool do_sky, bool is_persp, const char *viewname, + GPUFX *fx, GPUFXSettings *fx_settings, + GPUOffScreen *ofs) +{ + bool do_compositing = false; + RegionView3D *rv3d = ar->regiondata; + + glPushMatrix(); + + /* set temporary new size */ + int bwinx = ar->winx; + int bwiny = ar->winy; + rcti brect = ar->winrct; + + ar->winx = winx; + ar->winy = winy; + ar->winrct.xmin = 0; + ar->winrct.ymin = 0; + ar->winrct.xmax = winx; + ar->winrct.ymax = winy; + + struct bThemeState theme_state; + UI_Theme_Store(&theme_state); + UI_SetTheme(SPACE_VIEW3D, RGN_TYPE_WINDOW); + + /* set flags */ + G.f |= G_RENDER_OGL; + + if ((v3d->flag2 & V3D_RENDER_SHADOW) == 0) { + /* free images which can have changed on frame-change + * warning! can be slow so only free animated images - campbell */ + GPU_free_images_anim(); + } + + /* setup view matrices before fx or unbinding the offscreen buffers will cause issues */ + if ((viewname != NULL && viewname[0] != '\0') && (viewmat == NULL) && rv3d->persp == RV3D_CAMOB && v3d->camera) + view3d_stereo3d_setup_offscreen(scene, v3d, ar, winmat, viewname); + else + VP_legacy_view3d_main_region_setup_view(scene, v3d, ar, viewmat, winmat); + + /* framebuffer fx needed, we need to draw offscreen first */ + if (v3d->fx_settings.fx_flag && fx) { + GPUSSAOSettings *ssao = NULL; + + if (v3d->drawtype < OB_SOLID) { + ssao = v3d->fx_settings.ssao; + v3d->fx_settings.ssao = NULL; + } + + do_compositing = GPU_fx_compositor_initialize_passes(fx, &ar->winrct, NULL, fx_settings); + + if (ssao) + v3d->fx_settings.ssao = ssao; + } + + /* clear opengl buffers */ + if (do_sky) { + view3d_main_region_clear(scene, v3d, ar); + } + else { + glClearColor(0.0f, 0.0f, 0.0f, 0.0f); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + } + + /* main drawing call */ + view3d_draw_objects(NULL, scene, v3d, ar, NULL, do_bgpic, true, do_compositing ? fx : NULL); + + /* post process */ + if (do_compositing) { + if (!winmat) + is_persp = rv3d->is_persp; + GPU_fx_do_composite_pass(fx, winmat, is_persp, scene, ofs); + } + + if ((v3d->flag2 & V3D_RENDER_SHADOW) == 0) { + /* draw grease-pencil stuff */ + ED_region_pixelspace(ar); + + + if (v3d->flag2 & V3D_SHOW_GPENCIL) { + /* draw grease-pencil stuff - needed to get paint-buffer shown too (since it's 2D) */ + ED_gpencil_draw_view3d(NULL, scene, v3d, ar, false); + } + + /* freeing the images again here could be done after the operator runs, leaving for now */ + GPU_free_images_anim(); + } + + /* restore size */ + ar->winx = bwinx; + ar->winy = bwiny; + ar->winrct = brect; + + glPopMatrix(); + + UI_Theme_Restore(&theme_state); + + G.f &= ~G_RENDER_OGL; +} + +/** + * Utility func for ED_view3d_draw_offscreen + * + * \param ofs: Optional off-screen buffer, can be NULL. + * (avoids re-creating when doing multiple GL renders). + */ +ImBuf *ED_view3d_draw_offscreen_imbuf( + Scene *scene, View3D *v3d, ARegion *ar, int sizex, int sizey, + unsigned int flag, bool draw_background, + int alpha_mode, int samples, bool full_samples, const char *viewname, + /* output vars */ + GPUFX *fx, GPUOffScreen *ofs, char err_out[256]) +{ + RegionView3D *rv3d = ar->regiondata; + const bool draw_sky = (alpha_mode == R_ADDSKY); + + /* view state */ + GPUFXSettings fx_settings = v3d->fx_settings; + bool is_ortho = false; + float winmat[4][4]; + + if (ofs && ((GPU_offscreen_width(ofs) != sizex) || (GPU_offscreen_height(ofs) != sizey))) { + /* sizes differ, can't reuse */ + ofs = NULL; + } + + const bool own_ofs = (ofs == NULL); + + if (own_ofs) { + /* bind */ + ofs = GPU_offscreen_create(sizex, sizey, full_samples ? 0 : samples, err_out); + if (ofs == NULL) { + return NULL; + } + } + + ED_view3d_draw_offscreen_init(scene, v3d); + + GPU_offscreen_bind(ofs, true); + + /* read in pixels & stamp */ + ImBuf *ibuf = IMB_allocImBuf(sizex, sizey, 32, flag); + + /* render 3d view */ + if (rv3d->persp == RV3D_CAMOB && v3d->camera) { + CameraParams params; + Object *camera = BKE_camera_multiview_render(scene, v3d->camera, viewname); + + BKE_camera_params_init(¶ms); + /* fallback for non camera objects */ + params.clipsta = v3d->near; + params.clipend = v3d->far; + BKE_camera_params_from_object(¶ms, camera); + BKE_camera_multiview_params(&scene->r, ¶ms, camera, viewname); + BKE_camera_params_compute_viewplane(¶ms, sizex, sizey, scene->r.xasp, scene->r.yasp); + BKE_camera_params_compute_matrix(¶ms); + + BKE_camera_to_gpu_dof(camera, &fx_settings); + + is_ortho = params.is_ortho; + copy_m4_m4(winmat, params.winmat); + } + else { + rctf viewplane; + float clipsta, clipend; + + is_ortho = ED_view3d_viewplane_get(v3d, rv3d, sizex, sizey, &viewplane, &clipsta, &clipend, NULL); + if (is_ortho) { + orthographic_m4(winmat, viewplane.xmin, viewplane.xmax, viewplane.ymin, viewplane.ymax, -clipend, clipend); + } + else { + perspective_m4(winmat, viewplane.xmin, viewplane.xmax, viewplane.ymin, viewplane.ymax, clipsta, clipend); + } + } + + if ((samples && full_samples) == 0) { + /* Single-pass render, common case */ + ED_view3d_draw_offscreen( + scene, v3d, ar, sizex, sizey, NULL, winmat, + draw_background, draw_sky, !is_ortho, viewname, + fx, &fx_settings, ofs); + + if (ibuf->rect_float) { + GPU_offscreen_read_pixels(ofs, GL_FLOAT, ibuf->rect_float); + } + else if (ibuf->rect) { + GPU_offscreen_read_pixels(ofs, GL_UNSIGNED_BYTE, ibuf->rect); + } + } + else { + /* Multi-pass render, use accumulation buffer & jitter for 'full' oversampling. + * Use because OpenGL may use a lower quality MSAA, and only over-sample edges. */ + static float jit_ofs[32][2]; + float winmat_jitter[4][4]; + /* use imbuf as temp storage, before writing into it from accumulation buffer */ + unsigned char *rect_temp = ibuf->rect ? (void *)ibuf->rect : (void *)ibuf->rect_float; + unsigned int *accum_buffer = MEM_mallocN(sizex * sizey * sizeof(int[4]), "accum1"); + + BLI_jitter_init(jit_ofs, samples); + + /* first sample buffer, also initializes 'rv3d->persmat' */ + ED_view3d_draw_offscreen( + scene, v3d, ar, sizex, sizey, NULL, winmat, + draw_background, draw_sky, !is_ortho, viewname, + fx, &fx_settings, ofs); + GPU_offscreen_read_pixels(ofs, GL_UNSIGNED_BYTE, rect_temp); + + unsigned i = sizex * sizey * 4; + while (i--) { + accum_buffer[i] = rect_temp[i]; + } + + /* skip the first sample */ + for (int j = 1; j < samples; j++) { + copy_m4_m4(winmat_jitter, winmat); + window_translate_m4( + winmat_jitter, rv3d->persmat, + (jit_ofs[j][0] * 2.0f) / sizex, + (jit_ofs[j][1] * 2.0f) / sizey); + + ED_view3d_draw_offscreen( + scene, v3d, ar, sizex, sizey, NULL, winmat_jitter, + draw_background, draw_sky, !is_ortho, viewname, + fx, &fx_settings, ofs); + GPU_offscreen_read_pixels(ofs, GL_UNSIGNED_BYTE, rect_temp); + + i = sizex * sizey * 4; + while (i--) { + accum_buffer[i] += rect_temp[i]; + } + } + + if (ibuf->rect_float) { + float *rect_float = ibuf->rect_float; + i = sizex * sizey * 4; + while (i--) { + rect_float[i] = (float)(accum_buffer[i] / samples) * (1.0f / 255.0f); + } + } + else { + unsigned char *rect_ub = (unsigned char *)ibuf->rect; + i = sizex * sizey * 4; + while (i--) { + rect_ub[i] = accum_buffer[i] / samples; + } + } + + MEM_freeN(accum_buffer); + } + + /* unbind */ + GPU_offscreen_unbind(ofs, true); + + if (own_ofs) { + GPU_offscreen_free(ofs); + } + + if (ibuf->rect_float && ibuf->rect) + IMB_rect_from_float(ibuf); + + return ibuf; +} + +/** + * Creates own fake 3d views (wrapping #ED_view3d_draw_offscreen_imbuf) + * + * \param ofs: Optional off-screen buffer can be NULL. + * (avoids re-creating when doing multiple GL renders). + * + * \note used by the sequencer + */ +ImBuf *ED_view3d_draw_offscreen_imbuf_simple( + Scene *scene, Object *camera, int width, int height, + unsigned int flag, int drawtype, bool use_solid_tex, bool use_gpencil, bool draw_background, + int alpha_mode, int samples, bool full_samples, const char *viewname, + GPUFX *fx, GPUOffScreen *ofs, char err_out[256]) +{ + View3D v3d = {NULL}; + ARegion ar = {NULL}; + RegionView3D rv3d = {{{0}}}; + + /* connect data */ + v3d.regionbase.first = v3d.regionbase.last = &ar; + ar.regiondata = &rv3d; + ar.regiontype = RGN_TYPE_WINDOW; + + v3d.camera = camera; + v3d.lay = scene->lay; + v3d.drawtype = drawtype; + v3d.flag2 = V3D_RENDER_OVERRIDE; + + if (use_gpencil) + v3d.flag2 |= V3D_SHOW_GPENCIL; + + if (use_solid_tex) + v3d.flag2 |= V3D_SOLID_TEX; + + if (draw_background) + v3d.flag3 |= V3D_SHOW_WORLD; + + rv3d.persp = RV3D_CAMOB; + + copy_m4_m4(rv3d.viewinv, v3d.camera->obmat); + normalize_m4(rv3d.viewinv); + invert_m4_m4(rv3d.viewmat, rv3d.viewinv); + + { + CameraParams params; + Object *view_camera = BKE_camera_multiview_render(scene, v3d.camera, viewname); + + BKE_camera_params_init(¶ms); + BKE_camera_params_from_object(¶ms, view_camera); + BKE_camera_multiview_params(&scene->r, ¶ms, view_camera, viewname); + BKE_camera_params_compute_viewplane(¶ms, width, height, scene->r.xasp, scene->r.yasp); + BKE_camera_params_compute_matrix(¶ms); + + copy_m4_m4(rv3d.winmat, params.winmat); + v3d.near = params.clipsta; + v3d.far = params.clipend; + v3d.lens = params.lens; + } + + mul_m4_m4m4(rv3d.persmat, rv3d.winmat, rv3d.viewmat); + invert_m4_m4(rv3d.persinv, rv3d.viewinv); + + return ED_view3d_draw_offscreen_imbuf( + scene, &v3d, &ar, width, height, flag, + draw_background, alpha_mode, samples, full_samples, viewname, + fx, ofs, err_out); +} + + +/** + * \note The info that this uses is updated in #ED_refresh_viewport_fps, + * which currently gets called during #SCREEN_OT_animation_step. + */ +void ED_scene_draw_fps(Scene *scene, const rcti *rect) +{ + ScreenFrameRateInfo *fpsi = scene->fps_info; + char printable[16]; + + if (!fpsi || !fpsi->lredrawtime || !fpsi->redrawtime) + return; + + printable[0] = '\0'; + +#if 0 + /* this is too simple, better do an average */ + fps = (float)(1.0 / (fpsi->lredrawtime - fpsi->redrawtime)) +#else + fpsi->redrawtimes_fps[fpsi->redrawtime_index] = (float)(1.0 / (fpsi->lredrawtime - fpsi->redrawtime)); + + float fps = 0.0f; + int tot = 0; + for (int i = 0; i < REDRAW_FRAME_AVERAGE; i++) { + if (fpsi->redrawtimes_fps[i]) { + fps += fpsi->redrawtimes_fps[i]; + tot++; + } + } + if (tot) { + fpsi->redrawtime_index = (fpsi->redrawtime_index + 1) % REDRAW_FRAME_AVERAGE; + + //fpsi->redrawtime_index++; + //if (fpsi->redrawtime >= REDRAW_FRAME_AVERAGE) + // fpsi->redrawtime = 0; + + fps = fps / tot; + } +#endif + + const int font_id = BLF_default(); + + /* is this more than half a frame behind? */ + if (fps + 0.5f < (float)(FPS)) { + UI_FontThemeColor(font_id, TH_REDALERT); + BLI_snprintf(printable, sizeof(printable), IFACE_("fps: %.2f"), fps); + } + else { + UI_FontThemeColor(font_id, TH_TEXT_HI); + BLI_snprintf(printable, sizeof(printable), IFACE_("fps: %i"), (int)(fps + 0.5f)); + } + +#ifdef WITH_INTERNATIONAL + BLF_draw_default(rect->xmin + U.widget_unit, rect->ymax - U.widget_unit, 0.0f, printable, sizeof(printable)); +#else + BLF_draw_default_ascii(rect->xmin + U.widget_unit, rect->ymax - U.widget_unit, 0.0f, printable, sizeof(printable)); +#endif +} + +static bool view3d_main_region_do_render_draw(Scene *scene) +{ + RenderEngineType *type = RE_engines_find(scene->r.engine); + + return (type && type->view_update && type->view_draw); +} + +bool ED_view3d_calc_render_border(Scene *scene, View3D *v3d, ARegion *ar, rcti *rect) +{ + RegionView3D *rv3d = ar->regiondata; + bool use_border; + + /* test if there is a 3d view rendering */ + if (v3d->drawtype != OB_RENDER || !view3d_main_region_do_render_draw(scene)) + return false; + + /* test if there is a border render */ + if (rv3d->persp == RV3D_CAMOB) + use_border = (scene->r.mode & R_BORDER) != 0; + else + use_border = (v3d->flag2 & V3D_RENDER_BORDER) != 0; + + if (!use_border) + return false; + + /* compute border */ + if (rv3d->persp == RV3D_CAMOB) { + rctf viewborder; + ED_view3d_calc_camera_border(scene, ar, v3d, rv3d, &viewborder, false); + + rect->xmin = viewborder.xmin + scene->r.border.xmin * BLI_rctf_size_x(&viewborder); + rect->ymin = viewborder.ymin + scene->r.border.ymin * BLI_rctf_size_y(&viewborder); + rect->xmax = viewborder.xmin + scene->r.border.xmax * BLI_rctf_size_x(&viewborder); + rect->ymax = viewborder.ymin + scene->r.border.ymax * BLI_rctf_size_y(&viewborder); + } + else { + rect->xmin = v3d->render_border.xmin * ar->winx; + rect->xmax = v3d->render_border.xmax * ar->winx; + rect->ymin = v3d->render_border.ymin * ar->winy; + rect->ymax = v3d->render_border.ymax * ar->winy; + } + + BLI_rcti_translate(rect, ar->winrct.xmin, ar->winrct.ymin); + BLI_rcti_isect(&ar->winrct, rect, rect); + + return true; +} + +/** + * IMPORTANT: this is deprecated, any changes made in this function should + * be mirrored in view3d_draw_render_draw() in view3d_draw.c + */ +static bool view3d_main_region_draw_engine(const bContext *C, Scene *scene, + ARegion *ar, View3D *v3d, + bool clip_border, const rcti *border_rect) +{ + RegionView3D *rv3d = ar->regiondata; + RenderEngineType *type; + GLint scissor[4]; + + /* create render engine */ + if (!rv3d->render_engine) { + RenderEngine *engine; + + type = RE_engines_find(scene->r.engine); + + if (!(type->view_update && type->view_draw)) + return false; + + engine = RE_engine_create_ex(type, true); + + engine->tile_x = scene->r.tilex; + engine->tile_y = scene->r.tiley; + + type->view_update(engine, C); + + rv3d->render_engine = engine; + } + + /* setup view matrices */ + VP_legacy_view3d_main_region_setup_view(scene, v3d, ar, NULL, NULL); + + /* background draw */ + ED_region_pixelspace(ar); + + if (clip_border) { + /* for border draw, we only need to clear a subset of the 3d view */ + if (border_rect->xmax > border_rect->xmin && border_rect->ymax > border_rect->ymin) { + glGetIntegerv(GL_SCISSOR_BOX, scissor); + glScissor(border_rect->xmin, border_rect->ymin, + BLI_rcti_size_x(border_rect), BLI_rcti_size_y(border_rect)); + } + else { + return false; + } + } + + glClearColor(0.0f, 0.0f, 0.0f, 0.0f); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + if (v3d->flag & V3D_DISPBGPICS) + view3d_draw_bgpic_test(scene, ar, v3d, false, true); + else + fdrawcheckerboard(0, 0, ar->winx, ar->winy); + + /* render result draw */ + type = rv3d->render_engine->type; + type->view_draw(rv3d->render_engine, C); + + if (v3d->flag & V3D_DISPBGPICS) + view3d_draw_bgpic_test(scene, ar, v3d, true, true); + + if (clip_border) { + /* restore scissor as it was before */ + glScissor(scissor[0], scissor[1], scissor[2], scissor[3]); + } + + return true; +} + +static void view3d_main_region_draw_engine_info(View3D *v3d, RegionView3D *rv3d, ARegion *ar, bool render_border) +{ + float fill_color[4] = {0.0f, 0.0f, 0.0f, 0.25f}; + + if (!rv3d->render_engine || !rv3d->render_engine->text[0]) + return; + + if (render_border) { + /* draw darkened background color. no alpha because border render does + * partial redraw and will not redraw the region behind this info bar */ + float alpha = 1.0f - fill_color[3]; + Camera *camera = ED_view3d_camera_data_get(v3d, rv3d); + + if (camera) { + if (camera->flag & CAM_SHOWPASSEPARTOUT) { + alpha *= (1.0f - camera->passepartalpha); + } + } + + UI_GetThemeColor3fv(TH_HIGH_GRAD, fill_color); + mul_v3_fl(fill_color, alpha); + fill_color[3] = 1.0f; + } + + ED_region_info_draw(ar, rv3d->render_engine->text, fill_color, true); +} + +static void view3d_stereo3d_setup_offscreen(Scene *scene, View3D *v3d, ARegion *ar, + float winmat[4][4], const char *viewname) +{ + /* update the viewport matrices with the new camera */ + if (scene->r.views_format == SCE_VIEWS_FORMAT_STEREO_3D) { + float viewmat[4][4]; + const bool is_left = STREQ(viewname, STEREO_LEFT_NAME); + + BKE_camera_multiview_view_matrix(&scene->r, v3d->camera, is_left, viewmat); + VP_legacy_view3d_main_region_setup_view(scene, v3d, ar, viewmat, winmat); + } + else { /* SCE_VIEWS_FORMAT_MULTIVIEW */ + float viewmat[4][4]; + Object *camera = BKE_camera_multiview_render(scene, v3d->camera, viewname); + + BKE_camera_multiview_view_matrix(&scene->r, camera, false, viewmat); + VP_legacy_view3d_main_region_setup_view(scene, v3d, ar, viewmat, winmat); + } +} + +#ifdef WITH_GAMEENGINE +static void update_lods(Scene *scene, float camera_pos[3]) +{ + Scene *sce_iter; + Base *base; + + for (SETLOOPER(scene, sce_iter, base)) { + Object *ob = base->object; + BKE_object_lod_update(ob, camera_pos); + } +} +#endif + +static void view3d_main_region_draw_objects(const bContext *C, Scene *scene, View3D *v3d, + ARegion *ar, const char **grid_unit) +{ + wmWindow *win = CTX_wm_window(C); + RegionView3D *rv3d = ar->regiondata; + unsigned int lay_used = v3d->lay_used; + + /* post processing */ + bool do_compositing = false; + + /* shadow buffers, before we setup matrices */ + if (draw_glsl_material(scene, NULL, v3d, v3d->drawtype)) + gpu_update_lamps_shadows_world(scene, v3d); + + /* reset default OpenGL lights if needed (i.e. after preferences have been altered) */ + if (rv3d->rflag & RV3D_GPULIGHT_UPDATE) { + rv3d->rflag &= ~RV3D_GPULIGHT_UPDATE; + GPU_default_lights(); + } + + /* setup the view matrix */ + if (VP_legacy_view3d_stereo3d_active(C, scene, v3d, rv3d)) + VP_legacy_view3d_stereo3d_setup(scene, v3d, ar); + else + VP_legacy_view3d_main_region_setup_view(scene, v3d, ar, NULL, NULL); + + rv3d->rflag &= ~RV3D_IS_GAME_ENGINE; +#ifdef WITH_GAMEENGINE + if (STREQ(scene->r.engine, RE_engine_id_BLENDER_GAME)) { + rv3d->rflag |= RV3D_IS_GAME_ENGINE; + + /* Make sure LoDs are up to date */ + update_lods(scene, rv3d->viewinv[3]); + } +#endif + + /* framebuffer fx needed, we need to draw offscreen first */ + if (v3d->fx_settings.fx_flag && v3d->drawtype >= OB_SOLID) { + BKE_screen_gpu_fx_validate(&v3d->fx_settings); + GPUFXSettings fx_settings = v3d->fx_settings; + if (!rv3d->compositor) + rv3d->compositor = GPU_fx_compositor_create(); + + if (rv3d->persp == RV3D_CAMOB && v3d->camera) + BKE_camera_to_gpu_dof(v3d->camera, &fx_settings); + else { + fx_settings.dof = NULL; + } + + do_compositing = GPU_fx_compositor_initialize_passes(rv3d->compositor, &ar->winrct, &ar->drawrct, &fx_settings); + } + + /* clear the background */ + view3d_main_region_clear(scene, v3d, ar); + + /* enables anti-aliasing for 3D view drawing */ + if (win->multisamples != USER_MULTISAMPLE_NONE) { + glEnable(GL_MULTISAMPLE); + } + + /* main drawing call */ + view3d_draw_objects(C, scene, v3d, ar, grid_unit, true, false, do_compositing ? rv3d->compositor : NULL); + + /* post process */ + if (do_compositing) { + GPU_fx_do_composite_pass(rv3d->compositor, rv3d->winmat, rv3d->is_persp, scene, NULL); + } + + /* Disable back anti-aliasing */ + if (win->multisamples != USER_MULTISAMPLE_NONE) { + glDisable(GL_MULTISAMPLE); + } + + if (v3d->lay_used != lay_used) { /* happens when loading old files or loading with UI load */ + /* find header and force tag redraw */ + ScrArea *sa = CTX_wm_area(C); + ARegion *ar_header = BKE_area_find_region_type(sa, RGN_TYPE_HEADER); + ED_region_tag_redraw(ar_header); /* can be NULL */ + } + + if ((v3d->flag2 & V3D_RENDER_OVERRIDE) == 0) { + BDR_drawSketch(C); + } +} + +static void view3d_main_region_draw_info(const bContext *C, Scene *scene, + ARegion *ar, View3D *v3d, + const char *grid_unit, bool render_border) +{ + wmWindowManager *wm = CTX_wm_manager(C); + RegionView3D *rv3d = ar->regiondata; + rcti rect; + + /* local coordinate visible rect inside region, to accomodate overlapping ui */ + ED_region_visible_rect(ar, &rect); + + if (rv3d->persp == RV3D_CAMOB) { + VP_drawviewborder(scene, ar, v3d); + } + else if (v3d->flag2 & V3D_RENDER_BORDER) { + VP_drawrenderborder(ar, v3d); + } + + if (v3d->flag2 & V3D_SHOW_GPENCIL) { + /* draw grease-pencil stuff - needed to get paint-buffer shown too (since it's 2D) */ + ED_gpencil_draw_view3d(wm, scene, v3d, ar, false); + } + + if ((v3d->flag2 & V3D_RENDER_OVERRIDE) == 0) { + VP_legacy_drawcursor(scene, ar, v3d); /* 3D cursor */ + + if (U.uiflag & USER_SHOW_ROTVIEWICON) + VP_legacy_draw_view_axis(rv3d, &rect); + else + draw_view_icon(rv3d, &rect); + + if (U.uiflag & USER_DRAWVIEWINFO) { + SceneLayer *sl = CTX_data_scene_layer(C); + Object *ob = OBACT_NEW; + VP_legacy_draw_selected_name(scene, ob, &rect); + } + } + + if (rv3d->render_engine) { + view3d_main_region_draw_engine_info(v3d, rv3d, ar, render_border); + return; + } + + if ((v3d->flag2 & V3D_RENDER_OVERRIDE) == 0) { + if ((U.uiflag & USER_SHOW_FPS) && ED_screen_animation_no_scrub(wm)) { + ED_scene_draw_fps(scene, &rect); + } + else if (U.uiflag & USER_SHOW_VIEWPORTNAME) { + VP_legacy_draw_viewport_name(ar, v3d, &rect); + } + + if (grid_unit) { /* draw below the viewport name */ + char numstr[32] = ""; + + UI_FontThemeColor(BLF_default(), TH_TEXT_HI); + if (v3d->grid != 1.0f) { + BLI_snprintf(numstr, sizeof(numstr), "%s x %.4g", grid_unit, v3d->grid); + } + + BLF_draw_default_ascii(rect.xmin + U.widget_unit, + rect.ymax - (USER_SHOW_VIEWPORTNAME ? 2 * U.widget_unit : U.widget_unit), 0.0f, + numstr[0] ? numstr : grid_unit, sizeof(numstr)); + } + } +} + +void view3d_main_region_draw_legacy(const bContext *C, ARegion *ar) +{ + Scene *scene = CTX_data_scene(C); + View3D *v3d = CTX_wm_view3d(C); + const char *grid_unit = NULL; + rcti border_rect; + + /* if we only redraw render border area, skip opengl draw and also + * don't do scissor because it's already set */ + bool render_border = ED_view3d_calc_render_border(scene, v3d, ar, &border_rect); + bool clip_border = (render_border && !BLI_rcti_compare(&ar->drawrct, &border_rect)); + + /* draw viewport using opengl */ + if (v3d->drawtype != OB_RENDER || !view3d_main_region_do_render_draw(scene) || clip_border) { + view3d_main_region_draw_objects(C, scene, v3d, ar, &grid_unit); + + if (G.debug & G_DEBUG_SIMDATA) + draw_sim_debug_data(scene, v3d, ar); + + ED_region_pixelspace(ar); + } + + /* draw viewport using external renderer */ + if (v3d->drawtype == OB_RENDER) + view3d_main_region_draw_engine(C, scene, ar, v3d, clip_border, &border_rect); + + view3d_main_region_draw_info(C, scene, ar, v3d, grid_unit, render_border); + + v3d->flag |= V3D_INVALID_BACKBUF; + + BLI_assert(BLI_listbase_is_empty(&v3d->afterdraw_transp)); + BLI_assert(BLI_listbase_is_empty(&v3d->afterdraw_xray)); + BLI_assert(BLI_listbase_is_empty(&v3d->afterdraw_xraytransp)); +} diff --git a/source/blender/editors/space_view3d/view3d_edit.c b/source/blender/editors/space_view3d/view3d_edit.c index 5e13b3f27fc..902b9ebb5d5 100644 --- a/source/blender/editors/space_view3d/view3d_edit.c +++ b/source/blender/editors/space_view3d/view3d_edit.c @@ -657,7 +657,7 @@ static bool view3d_orbit_calc_center(bContext *C, float r_dyn_ofs[3]) else if (ob_act == NULL || ob_act->mode == OB_MODE_OBJECT) { /* object mode use boundbox centers */ View3D *v3d = CTX_wm_view3d(C); - Base *base; + BaseLegacy *base; unsigned int tot = 0; float select_center[3]; @@ -2940,7 +2940,7 @@ static int view3d_all_exec(bContext *C, wmOperator *op) /* was view3d_home() in ARegion *ar = CTX_wm_region(C); View3D *v3d = CTX_wm_view3d(C); Scene *scene = CTX_data_scene(C); - Base *base; + BaseLegacy *base; float *curs; const bool use_all_regions = RNA_boolean_get(op->ptr, "use_all_regions"); const bool skip_camera = (ED_view3d_camera_lock_check(v3d, ar->regiondata) || @@ -3045,7 +3045,7 @@ static int viewselected_exec(bContext *C, wmOperator *op) if (ob && (ob->mode & OB_MODE_WEIGHT_PAINT)) { /* hard-coded exception, we look for the one selected armature */ /* this is weak code this way, we should make a generic active/selection callback interface once... */ - Base *base; + BaseLegacy *base; for (base = scene->base.first; base; base = base->next) { if (TESTBASELIB(v3d, base)) { if (base->object->type == OB_ARMATURE) @@ -3091,7 +3091,7 @@ static int viewselected_exec(bContext *C, wmOperator *op) ok_dist = 0; /* don't zoom */ } else { - Base *base; + BaseLegacy *base; for (base = FIRSTBASE; base; base = base->next) { if (TESTBASE(v3d, base)) { diff --git a/source/blender/editors/space_view3d/view3d_fly.c b/source/blender/editors/space_view3d/view3d_fly.c index 04a6aa215f4..328e0b03bb8 100644 --- a/source/blender/editors/space_view3d/view3d_fly.c +++ b/source/blender/editors/space_view3d/view3d_fly.c @@ -56,6 +56,8 @@ #include "UI_interface.h" #include "UI_resources.h" +#include "GPU_immediate.h" + #include "view3d_intern.h" /* own include */ /* NOTE: these defines are saved in keymap files, do not change values but just add new ones */ @@ -257,36 +259,45 @@ static void drawFlyPixel(const struct bContext *UNUSED(C), ARegion *UNUSED(ar), x2 = xoff + 0.55f * fly->width; y2 = yoff + 0.55f * fly->height; - UI_ThemeColor(TH_VIEW_OVERLAY); - glBegin(GL_LINES); + VertexFormat *format = immVertexFormat(); + unsigned int pos = add_attrib(format, "pos", GL_FLOAT, 2, KEEP_FLOAT); + + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + + immUniformThemeColor(TH_VIEW_OVERLAY); + + immBegin(GL_LINES, 16); + /* bottom left */ - glVertex2f(x1, y1); - glVertex2f(x1, y1 + 5); + immVertex2f(pos, x1, y1); + immVertex2f(pos, x1, y1 + 5); - glVertex2f(x1, y1); - glVertex2f(x1 + 5, y1); + immVertex2f(pos, x1, y1); + immVertex2f(pos, x1 + 5, y1); /* top right */ - glVertex2f(x2, y2); - glVertex2f(x2, y2 - 5); + immVertex2f(pos, x2, y2); + immVertex2f(pos, x2, y2 - 5); - glVertex2f(x2, y2); - glVertex2f(x2 - 5, y2); + immVertex2f(pos, x2, y2); + immVertex2f(pos, x2 - 5, y2); /* top left */ - glVertex2f(x1, y2); - glVertex2f(x1, y2 - 5); + immVertex2f(pos, x1, y2); + immVertex2f(pos, x1, y2 - 5); - glVertex2f(x1, y2); - glVertex2f(x1 + 5, y2); + immVertex2f(pos, x1, y2); + immVertex2f(pos, x1 + 5, y2); /* bottom right */ - glVertex2f(x2, y1); - glVertex2f(x2, y1 + 5); + immVertex2f(pos, x2, y1); + immVertex2f(pos, x2, y1 + 5); + + immVertex2f(pos, x2, y1); + immVertex2f(pos, x2 - 5, y1); - glVertex2f(x2, y1); - glVertex2f(x2 - 5, y1); - glEnd(); + immEnd(); + immUnbindProgram(); } static void fly_update_header(bContext *C, wmOperator *op, FlyInfo *fly) diff --git a/source/blender/editors/space_view3d/view3d_header.c b/source/blender/editors/space_view3d/view3d_header.c index bf1bdf68619..39c2c2ed7dd 100644 --- a/source/blender/editors/space_view3d/view3d_header.c +++ b/source/blender/editors/space_view3d/view3d_header.c @@ -284,9 +284,10 @@ void uiTemplateHeader3D(uiLayout *layout, struct bContext *C) ScrArea *sa = CTX_wm_area(C); View3D *v3d = sa->spacedata.first; Scene *scene = CTX_data_scene(C); + SceneLayer *sl = CTX_data_scene_layer(C); ToolSettings *ts = CTX_data_tool_settings(C); PointerRNA v3dptr, toolsptr, sceneptr; - Object *ob = OBACT; + Object *ob = OBACT_NEW; Object *obedit = CTX_data_edit_object(C); bGPdata *gpd = CTX_data_gpencil_data(C); uiBlock *block; @@ -334,8 +335,10 @@ void uiTemplateHeader3D(uiLayout *layout, struct bContext *C) uiItemMenuEnumO(row, C, "OBJECT_OT_mode_set", "mode", name, icon); } - /* Draw type */ - uiItemR(layout, &v3dptr, "viewport_shade", UI_ITEM_R_ICON_ONLY, "", ICON_NONE); + if (IS_VIEWPORT_LEGACY(v3d)) { + /* Draw type */ + uiItemR(layout, &v3dptr, "viewport_shade", UI_ITEM_R_ICON_ONLY, "", ICON_NONE); + } row = uiLayoutRow(layout, true); uiItemR(row, &v3dptr, "pivot_point", UI_ITEM_R_ICON_ONLY, "", ICON_NONE); @@ -371,11 +374,6 @@ void uiTemplateHeader3D(uiLayout *layout, struct bContext *C) } if (obedit == NULL && v3d->localvd == NULL) { - unsigned int ob_lay = ob ? ob->lay : 0; - - /* Layers */ - uiTemplateLayers(layout, v3d->scenelock ? &sceneptr : &v3dptr, "layers", &v3dptr, "layers_used", ob_lay); - /* Scene lock */ uiItemR(layout, &v3dptr, "lock_camera_and_layers", UI_ITEM_R_ICON_ONLY, "", ICON_NONE); } diff --git a/source/blender/editors/space_view3d/view3d_intern.h b/source/blender/editors/space_view3d/view3d_intern.h index b11f42bcfef..f3cc2a42460 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; @@ -46,6 +47,7 @@ struct bContext; struct bMotionPath; struct bPoseChannel; struct Mesh; +struct SceneLayer; struct wmOperatorType; struct wmWindowManager; struct wmKeyConfig; @@ -142,11 +144,23 @@ void draw_motion_paths_cleanup(View3D *v3d); /* drawobject.c */ -void draw_object(Scene *scene, struct ARegion *ar, View3D *v3d, Base *base, const short dflag); +void draw_object(Scene *scene, struct SceneLayer *sl, struct ARegion *ar, View3D *v3d, BaseLegacy *base, const short dflag); +void draw_mesh_object_outline(View3D *v3d, Object *ob, struct DerivedMesh *dm); + bool draw_glsl_material(Scene *scene, struct Object *ob, View3D *v3d, const char dt); -void draw_object_instance(Scene *scene, View3D *v3d, RegionView3D *rv3d, struct Object *ob, const char dt, int outline); +void draw_object_instance(Scene *scene, View3D *v3d, RegionView3D *rv3d, struct Object *ob, const char dt, int outline, float wire_col[4]); void draw_object_backbufsel(Scene *scene, View3D *v3d, RegionView3D *rv3d, struct Object *ob); -void drawaxes(const float viewmat_local[4][4], float size, char drawtype); + +void draw_object_wire_color(Scene *scene, struct SceneLayer *, Base *base, unsigned char r_ob_wire_col[4]); +void drawaxes(const float viewmat_local[4][4], float size, char drawtype, const unsigned char color[4]); +void drawlamp(View3D *v3d, RegionView3D *rv3d, Base *base, + const char dt, const short dflag, const unsigned char ob_wire_col[4], + const bool is_obact); +void drawcamera(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base *base, + const short dflag, const unsigned char ob_wire_col[4]); +void drawspeaker(const unsigned char ob_wire_col[3]); +void draw_bounding_volume(struct Object *ob, char type); +void draw_rigidbody_shape(struct Object *ob); void view3d_cached_text_draw_begin(void); void view3d_cached_text_draw_add(const float co[3], @@ -167,7 +181,7 @@ enum { int view3d_effective_drawtype(const struct View3D *v3d); /* drawarmature.c */ -bool draw_armature(Scene *scene, View3D *v3d, ARegion *ar, Base *base, +bool draw_armature(Scene *scene, struct SceneLayer *sl, View3D *v3d, ARegion *ar, Base *base, const short dt, const short dflag, const unsigned char ob_wire_col[4], const bool is_outline); @@ -193,11 +207,14 @@ void draw_sim_debug_data(Scene *scene, View3D *v3d, ARegion *ar); /* view3d_draw.c */ void view3d_main_region_draw(const struct bContext *C, struct ARegion *ar); +void view3d_draw_region_info(const struct bContext *C, struct ARegion *ar); + +/* view3d_draw_legacy.c */ +void view3d_main_region_draw_legacy(const struct bContext *C, struct ARegion *ar); void ED_view3d_draw_depth(Scene *scene, struct ARegion *ar, View3D *v3d, bool alphaoverride); void ED_view3d_draw_depth_gpencil(Scene *scene, ARegion *ar, View3D *v3d); -void ED_view3d_after_add(ListBase *lb, Base *base, const short dflag); +void ED_view3d_after_add(ListBase *lb, BaseLegacy *base, const short dflag); -void circf(float x, float y, float rad); void circ(float x, float y, float rad); void view3d_update_depths_rect(struct ARegion *ar, struct ViewDepths *d, struct rcti *rect); float view3d_depth_near(struct ViewDepths *d); @@ -309,5 +326,24 @@ extern unsigned char view3d_camera_border_hack_col[3]; extern bool view3d_camera_border_hack_test; #endif -#endif /* __VIEW3D_INTERN_H__ */ +/* temporary test for blender 2.8 viewport */ +#define IS_VIEWPORT_LEGACY(v3d) ((v3d->tmp_compat_flag & V3D_NEW_VIEWPORT) == 0) + +/* temporary for legacy viewport to work */ +void VP_legacy_drawcursor(Scene *scene, ARegion *ar, View3D *v3d); +void VP_legacy_draw_view_axis(RegionView3D *rv3d, rcti *rect); +void VP_legacy_draw_viewport_name(ARegion *ar, View3D *v3d, rcti *rect); +void VP_legacy_draw_selected_name(Scene *scene, Object *ob, rcti *rect); +void VP_legacy_drawgrid(UnitSettings *unit, ARegion *ar, View3D *v3d, const char **grid_unit); +void VP_legacy_drawfloor(Scene *scene, View3D *v3d, const char **grid_unit, bool write_depth); +void VP_legacy_view3d_main_region_setup_view(Scene *scene, View3D *v3d, ARegion *ar, float viewmat[4][4], float winmat[4][4]); +bool VP_legacy_view3d_stereo3d_active(const struct bContext *C, Scene *scene, View3D *v3d, RegionView3D *rv3d); +void VP_legacy_view3d_stereo3d_setup(Scene *scene, View3D *v3d, ARegion *ar); +void draw_dupli_objects(Scene *scene, SceneLayer *sl, ARegion *ar, View3D *v3d, BaseLegacy *base); +bool VP_legacy_use_depth(Scene *scene, View3D *v3d); +void VP_drawviewborder(Scene *scene, ARegion *ar, View3D *v3d); +void VP_drawrenderborder(ARegion *ar, View3D *v3d); +void VP_view3d_draw_background_none(void); +void VP_view3d_draw_background_world(Scene *scene, View3D *v3d, RegionView3D *rv3d); +#endif /* __VIEW3D_INTERN_H__ */ diff --git a/source/blender/editors/space_view3d/view3d_ruler.c b/source/blender/editors/space_view3d/view3d_ruler.c index aefe30bbe32..4a4d008f779 100644 --- a/source/blender/editors/space_view3d/view3d_ruler.c +++ b/source/blender/editors/space_view3d/view3d_ruler.c @@ -43,6 +43,8 @@ #include "BIF_gl.h" +#include "GPU_immediate.h" + #include "WM_api.h" #include "WM_types.h" @@ -429,9 +431,9 @@ static void ruler_info_draw_pixel(const struct bContext *C, ARegion *ar, void *a //unsigned int color_act = 0x666600; unsigned int color_act = 0xffffff; unsigned int color_base = 0x0; - unsigned char color_back[4] = {0xff, 0xff, 0xff, 0x80}; unsigned char color_text[3]; unsigned char color_wire[3]; + float color_back[4] = {1.0f, 1.0f, 1.0f, 0.5f}; /* anti-aliased lines for more consistent appearance */ glEnable(GL_LINE_SMOOTH); @@ -456,28 +458,38 @@ static void ruler_info_draw_pixel(const struct bContext *C, ARegion *ar, void *a glEnable(GL_BLEND); - cpack(is_act ? color_act : color_base); - if (ruler_item->flag & RULERITEM_USE_ANGLE) { - glBegin(GL_LINE_STRIP); + unsigned pos = add_attrib(immVertexFormat(), "pos", GL_FLOAT, 2, KEEP_FLOAT); + + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + imm_cpack(is_act ? color_act : color_base); + + immBegin(GL_LINE_STRIP, 3); + for (j = 0; j < 3; j++) { - glVertex2fv(co_ss[j]); + immVertex2fv(pos, co_ss[j]); } - glEnd(); - cpack(0xaaaaaa); + + immEnd(); + + imm_cpack(0xaaaaaa); setlinestyle(3); - glBegin(GL_LINE_STRIP); + + immBegin(GL_LINE_STRIP, 3); + for (j = 0; j < 3; j++) { - glVertex2fv(co_ss[j]); + immVertex2fv(pos, co_ss[j]); } - glEnd(); + + immEnd(); + setlinestyle(0); /* arc */ { float dir_tmp[3]; float co_tmp[3]; - float arc_ss_coords[ARC_STEPS + 1][2]; + float arc_ss_coord[2]; float dir_a[3]; float dir_b[3]; @@ -501,46 +513,19 @@ static void ruler_info_draw_pixel(const struct bContext *C, ARegion *ar, void *a copy_v3_v3(dir_tmp, dir_a); - glColor3ubv(color_wire); + immUniformColor3ubv(color_wire); + + immBegin(GL_LINE_STRIP, arc_steps + 1); for (j = 0; j <= arc_steps; j++) { madd_v3_v3v3fl(co_tmp, ruler_item->co[1], dir_tmp, px_scale); - ED_view3d_project_float_global(ar, co_tmp, arc_ss_coords[j], V3D_PROJ_TEST_NOP); + ED_view3d_project_float_global(ar, co_tmp, arc_ss_coord, V3D_PROJ_TEST_NOP); mul_qt_v3(quat, dir_tmp); - } - - glEnableClientState(GL_VERTEX_ARRAY); - glVertexPointer(2, GL_FLOAT, 0, arc_ss_coords); - glDrawArrays(GL_LINE_STRIP, 0, arc_steps + 1); - glDisableClientState(GL_VERTEX_ARRAY); - } - - /* text */ - { - char numstr[256]; - float numstr_size[2]; - float pos[2]; - const int prec = 2; /* XXX, todo, make optional */ - ruler_item_as_string(ruler_item, unit, numstr, sizeof(numstr), prec); - - BLF_width_and_height(blf_mono_font, numstr, sizeof(numstr), &numstr_size[0], &numstr_size[1]); - - pos[0] = co_ss[1][0] + (cap_size * 2.0f); - pos[1] = co_ss[1][1] - (numstr_size[1] / 2.0f); + immVertex2fv(pos, arc_ss_coord); + } - /* draw text (bg) */ - glColor4ubv(color_back); - UI_draw_roundbox_corner_set(UI_CNR_ALL); - UI_draw_roundbox( - pos[0] - bg_margin, pos[1] - bg_margin, - pos[0] + bg_margin + numstr_size[0], pos[1] + bg_margin + numstr_size[1], - bg_radius); - /* draw text */ - glColor3ubv(color_text); - BLF_position(blf_mono_font, pos[0], pos[1], 0.0f); - BLF_rotation(blf_mono_font, 0.0f); - BLF_draw(blf_mono_font, numstr, sizeof(numstr)); + immEnd(); } /* capping */ @@ -561,75 +546,88 @@ static void ruler_info_draw_pixel(const struct bContext *C, ARegion *ar, void *a glEnable(GL_BLEND); - glColor3ubv(color_wire); + immUniformColor3ubv(color_wire); - glBegin(GL_LINES); + immBegin(GL_LINES, 8); madd_v2_v2v2fl(cap, co_ss[0], rot_90_vec_a, cap_size); - glVertex2fv(cap); + immVertex2fv(pos, cap); madd_v2_v2v2fl(cap, co_ss[0], rot_90_vec_a, -cap_size); - glVertex2fv(cap); + immVertex2fv(pos, cap); madd_v2_v2v2fl(cap, co_ss[2], rot_90_vec_b, cap_size); - glVertex2fv(cap); + immVertex2fv(pos, cap); madd_v2_v2v2fl(cap, co_ss[2], rot_90_vec_b, -cap_size); - glVertex2fv(cap); + immVertex2fv(pos, cap); /* angle vertex */ - glVertex2f(co_ss[1][0] - cap_size, co_ss[1][1] - cap_size); - glVertex2f(co_ss[1][0] + cap_size, co_ss[1][1] + cap_size); - glVertex2f(co_ss[1][0] - cap_size, co_ss[1][1] + cap_size); - glVertex2f(co_ss[1][0] + cap_size, co_ss[1][1] - cap_size); - glEnd(); + immVertex2f(pos, co_ss[1][0] - cap_size, co_ss[1][1] - cap_size); + immVertex2f(pos, co_ss[1][0] + cap_size, co_ss[1][1] + cap_size); + immVertex2f(pos, co_ss[1][0] - cap_size, co_ss[1][1] + cap_size); + immVertex2f(pos, co_ss[1][0] + cap_size, co_ss[1][1] - cap_size); + + immEnd(); glDisable(GL_BLEND); } - } - else { - glBegin(GL_LINE_STRIP); - for (j = 0; j < 3; j += 2) { - glVertex2fv(co_ss[j]); - } - glEnd(); - cpack(0xaaaaaa); - setlinestyle(3); - glBegin(GL_LINE_STRIP); - for (j = 0; j < 3; j += 2) { - glVertex2fv(co_ss[j]); - } - glEnd(); - setlinestyle(0); - sub_v2_v2v2(dir_ruler, co_ss[0], co_ss[2]); + immUnbindProgram(); /* text */ { char numstr[256]; float numstr_size[2]; - const int prec = 6; /* XXX, todo, make optional */ - float pos[2]; + float posit[2]; + const int prec = 2; /* XXX, todo, make optional */ ruler_item_as_string(ruler_item, unit, numstr, sizeof(numstr), prec); BLF_width_and_height(blf_mono_font, numstr, sizeof(numstr), &numstr_size[0], &numstr_size[1]); - mid_v2_v2v2(pos, co_ss[0], co_ss[2]); - - /* center text */ - pos[0] -= numstr_size[0] / 2.0f; - pos[1] -= numstr_size[1] / 2.0f; + posit[0] = co_ss[1][0] + (cap_size * 2.0f); + posit[1] = co_ss[1][1] - (numstr_size[1] / 2.0f); /* draw text (bg) */ - glColor4ubv(color_back); UI_draw_roundbox_corner_set(UI_CNR_ALL); - UI_draw_roundbox(pos[0] - bg_margin, pos[1] - bg_margin, - pos[0] + bg_margin + numstr_size[0], pos[1] + bg_margin + numstr_size[1], - bg_radius); + UI_draw_roundbox( + posit[0] - bg_margin, posit[1] - bg_margin, + posit[0] + bg_margin + numstr_size[0], posit[1] + bg_margin + numstr_size[1], + bg_radius, color_back); /* draw text */ - glColor3ubv(color_text); - BLF_position(blf_mono_font, pos[0], pos[1], 0.0f); + BLF_color3ubv(blf_mono_font, color_text); + BLF_position(blf_mono_font, posit[0], posit[1], 0.0f); + BLF_rotation(blf_mono_font, 0.0f); BLF_draw(blf_mono_font, numstr, sizeof(numstr)); } + } + else { + unsigned pos = add_attrib(immVertexFormat(), "pos", GL_FLOAT, 2, KEEP_FLOAT); + + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + imm_cpack(is_act ? color_act : color_base); + + immBegin(GL_LINE_STRIP, 2); + + for (j = 0; j < 3; j += 2) { + immVertex2fv(pos, co_ss[j]); + } + + immEnd(); + + imm_cpack(0xaaaaaa); + setlinestyle(3); + + immBegin(GL_LINE_STRIP, 2); + + for (j = 0; j < 3; j += 2) { + immVertex2fv(pos, co_ss[j]); + } + + immEnd(); + + setlinestyle(0); + + sub_v2_v2v2(dir_ruler, co_ss[0], co_ss[2]); /* capping */ { @@ -639,22 +637,55 @@ static void ruler_info_draw_pixel(const struct bContext *C, ARegion *ar, void *a normalize_v2(rot_90_vec); glEnable(GL_BLEND); - glColor3ubv(color_wire); - glBegin(GL_LINES); + immUniformColor3ubv(color_wire); + + immBegin(GL_LINES, 4); + madd_v2_v2v2fl(cap, co_ss[0], rot_90_vec, cap_size); - glVertex2fv(cap); + immVertex2fv(pos, cap); madd_v2_v2v2fl(cap, co_ss[0], rot_90_vec, -cap_size); - glVertex2fv(cap); + immVertex2fv(pos, cap); madd_v2_v2v2fl(cap, co_ss[2], rot_90_vec, cap_size); - glVertex2fv(cap); + immVertex2fv(pos, cap); madd_v2_v2v2fl(cap, co_ss[2], rot_90_vec, -cap_size); - glVertex2fv(cap); - glEnd(); + immVertex2fv(pos, cap); + + immEnd(); glDisable(GL_BLEND); } + + immUnbindProgram(); + + /* text */ + { + char numstr[256]; + float numstr_size[2]; + const int prec = 6; /* XXX, todo, make optional */ + float posit[2]; + + ruler_item_as_string(ruler_item, unit, numstr, sizeof(numstr), prec); + + BLF_width_and_height(blf_mono_font, numstr, sizeof(numstr), &numstr_size[0], &numstr_size[1]); + + mid_v2_v2v2(posit, co_ss[0], co_ss[2]); + + /* center text */ + posit[0] -= numstr_size[0] / 2.0f; + posit[1] -= numstr_size[1] / 2.0f; + + /* draw text (bg) */ + UI_draw_roundbox_corner_set(UI_CNR_ALL); + UI_draw_roundbox(posit[0] - bg_margin, posit[1] - bg_margin, + posit[0] + bg_margin + numstr_size[0], posit[1] + bg_margin + numstr_size[1], + bg_radius, color_back); + /* draw text */ + BLF_color3ubv(blf_mono_font, color_text); + BLF_position(blf_mono_font, posit[0], posit[1], 0.0f); + BLF_draw(blf_mono_font, numstr, sizeof(numstr)); + } } } @@ -673,8 +704,14 @@ static void ruler_info_draw_pixel(const struct bContext *C, ARegion *ar, void *a float co_ss[3]; ED_view3d_project_float_global(ar, ruler_item->co[ruler_item->co_index], co_ss, V3D_PROJ_TEST_NOP); - cpack(color_act); - circ(co_ss[0], co_ss[1], size * U.pixelsize); + unsigned pos = add_attrib(immVertexFormat(), "pos", GL_FLOAT, 2, KEEP_FLOAT); + + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + imm_cpack(color_act); + + imm_draw_lined_circle(pos, co_ss[0], co_ss[1], size * U.pixelsize, 32); + + immUnbindProgram(); } } diff --git a/source/blender/editors/space_view3d/view3d_select.c b/source/blender/editors/space_view3d/view3d_select.c index 3239d07553f..60bf078acc3 100644 --- a/source/blender/editors/space_view3d/view3d_select.c +++ b/source/blender/editors/space_view3d/view3d_select.c @@ -64,11 +64,13 @@ #include "BKE_context.h" #include "BKE_curve.h" #include "BKE_depsgraph.h" +#include "BKE_layer.h" #include "BKE_mball.h" #include "BKE_mesh.h" #include "BKE_object.h" #include "BKE_paint.h" #include "BKE_editmesh.h" +#include "BKE_scene.h" #include "BKE_tracking.h" #include "BKE_utildefines.h" @@ -109,6 +111,7 @@ void view3d_set_viewcontext(bContext *C, ViewContext *vc) memset(vc, 0, sizeof(ViewContext)); vc->ar = CTX_wm_region(C); vc->scene = CTX_data_scene(C); + vc->sl = CTX_data_scene_layer(C); vc->v3d = CTX_wm_view3d(C); vc->win = CTX_wm_window(C); vc->rv3d = CTX_wm_region_view3d(C); @@ -399,13 +402,13 @@ static void do_lasso_select_pose(ViewContext *vc, Object *ob, const int mcords[] } } -static void object_deselect_all_visible(Scene *scene, View3D *v3d) +static void object_deselect_all_visible(SceneLayer *sl) { Base *base; - for (base = scene->base.first; base; base = base->next) { - if (BASE_SELECTABLE(v3d, base)) { - ED_base_object_select(base, BA_DESELECT); + for (base = sl->object_bases.first; base; base = base->next) { + if (BASE_SELECTABLE_NEW(base)) { + ED_object_base_select(base, BA_DESELECT); } } } @@ -416,15 +419,14 @@ static void do_lasso_select_objects(ViewContext *vc, const int mcords[][2], cons Base *base; if (extend == false && select) - object_deselect_all_visible(vc->scene, vc->v3d); + object_deselect_all_visible(vc->sl); - for (base = vc->scene->base.first; base; base = base->next) { - if (BASE_SELECTABLE(vc->v3d, base)) { /* use this to avoid un-needed lasso lookups */ + for (base = vc->sl->object_bases.first; base; base = base->next) { + if (BASE_SELECTABLE_NEW(base)) { /* use this to avoid un-needed lasso lookups */ if (ED_view3d_project_base(vc->ar, base) == V3D_PROJ_RET_OK) { if (BLI_lasso_is_point_inside(mcords, moves, base->sx, base->sy, IS_CLIPPED)) { - ED_base_object_select(base, select ? BA_SELECT : BA_DESELECT); - base->object->flag = base->flag; + ED_object_base_select(base, select ? BA_SELECT : BA_DESELECT); } } if (vc->obact == base->object && (base->object->mode & OB_MODE_POSE)) { @@ -1017,8 +1019,8 @@ static int object_select_menu_exec(bContext *C, wmOperator *op) if (!toggle) { CTX_DATA_BEGIN (C, Base *, base, selectable_bases) { - if (base->flag & SELECT) { - ED_base_object_select(base, BA_DESELECT); + if ((base->flag & BASE_SELECTED) != 0) { + ED_object_base_select(base, BA_DESELECT); changed = true; } } @@ -1029,8 +1031,8 @@ static int object_select_menu_exec(bContext *C, wmOperator *op) { /* this is a bit dodjy, there should only be ONE object with this name, but library objects can mess this up */ if (STREQ(name, base->object->id.name + 2)) { - ED_base_object_activate(C, base); - ED_base_object_select(base, BA_SELECT); + ED_object_base_activate(C, base); + ED_object_base_select(base, BA_SELECT); changed = true; } } @@ -1074,14 +1076,12 @@ void VIEW3D_OT_select_menu(wmOperatorType *ot) RNA_def_boolean(ot->srna, "toggle", 0, "Toggle", "Toggle selection instead of deselecting everything first"); } -static void deselectall_except(Scene *scene, Base *b) /* deselect all except b */ +static void deselectall_except(SceneLayer *sl, Base *b) /* deselect all except b */ { - Base *base; - - for (base = FIRSTBASE; base; base = base->next) { - if (base->flag & SELECT) { + for (Base *base = sl->object_bases.first; base; base = base->next) { + if (base->flag & BASE_SELECTED) { if (b != base) { - ED_base_object_select(base, BA_DESELECT); + ED_object_base_select(base, BA_DESELECT); } } } @@ -1092,7 +1092,8 @@ static Base *object_mouse_select_menu(bContext *C, ViewContext *vc, unsigned int short baseCount = 0; bool ok; LinkNode *linklist = NULL; - + + /* handle base->selcol */ CTX_DATA_BEGIN (C, Base *, base, selectable_bases) { ok = false; @@ -1278,8 +1279,7 @@ static short mixed_bones_object_selectbuffer( static Base *mouse_select_eval_buffer(ViewContext *vc, unsigned int *buffer, int hits, Base *startbase, bool has_bones, bool do_nearest) { - Scene *scene = vc->scene; - View3D *v3d = vc->v3d; + SceneLayer *sl = vc->sl; Base *base, *basact = NULL; int a; @@ -1299,7 +1299,7 @@ static Base *mouse_select_eval_buffer(ViewContext *vc, unsigned int *buffer, int } else { /* only exclude active object when it is selected... */ - if (BASACT && (BASACT->flag & SELECT) && hits > 1) notcol = BASACT->selcol; + if (BASACT_NEW && (BASACT_NEW->flag & BASE_SELECTED) && hits > 1) notcol = BASACT_NEW->selcol; for (a = 0; a < hits; a++) { if (min > buffer[4 * a + 1] && notcol != (buffer[4 * a + 3] & 0xFFFF)) { @@ -1309,9 +1309,9 @@ static Base *mouse_select_eval_buffer(ViewContext *vc, unsigned int *buffer, int } } - base = FIRSTBASE; + base = FIRSTBASE_NEW; while (base) { - if (BASE_SELECTABLE(v3d, base)) { + if (BASE_SELECTABLE_NEW(base)) { if (base->selcol == selcol) break; } base = base->next; @@ -1324,13 +1324,13 @@ static Base *mouse_select_eval_buffer(ViewContext *vc, unsigned int *buffer, int while (base) { /* skip objects with select restriction, to prevent prematurely ending this loop * with an un-selectable choice */ - if (base->object->restrictflag & OB_RESTRICT_SELECT) { + if ((base->flag & BASE_SELECTABLED) == 0) { base = base->next; - if (base == NULL) base = FIRSTBASE; + if (base == NULL) base = FIRSTBASE_NEW; if (base == startbase) break; } - if (BASE_SELECTABLE(v3d, base)) { + if (BASE_SELECTABLE_NEW(base)) { for (a = 0; a < hits; a++) { if (has_bones) { /* skip non-bone objects */ @@ -1349,7 +1349,7 @@ static Base *mouse_select_eval_buffer(ViewContext *vc, unsigned int *buffer, int if (basact) break; base = base->next; - if (base == NULL) base = FIRSTBASE; + if (base == NULL) base = FIRSTBASE_NEW; if (base == startbase) break; } } @@ -1374,7 +1374,7 @@ Base *ED_view3d_give_base_under_cursor(bContext *C, const int mval[2]) if (hits > 0) { const bool has_bones = selectbuffer_has_bones(buffer, hits); - basact = mouse_select_eval_buffer(&vc, buffer, hits, vc.scene->base.first, has_bones, do_nearest); + basact = mouse_select_eval_buffer(&vc, buffer, hits, vc.sl->object_bases.first, has_bones, do_nearest); } return basact; @@ -1406,8 +1406,8 @@ static bool ed_object_select_pick( { ViewContext vc; ARegion *ar = CTX_wm_region(C); - View3D *v3d = CTX_wm_view3d(C); Scene *scene = CTX_data_scene(C); + SceneLayer *sl = CTX_data_scene_layer(C); Base *base, *startbase = NULL, *basact = NULL, *oldbasact = NULL; bool is_obedit; float dist = ED_view3d_select_dist_px() * 1.3333f; @@ -1426,8 +1426,8 @@ static bool ed_object_select_pick( } /* always start list from basact in wire mode */ - startbase = FIRSTBASE; - if (BASACT && BASACT->next) startbase = BASACT->next; + startbase = FIRSTBASE_NEW; + if (BASACT_NEW && BASACT_NEW->next) startbase = BASACT_NEW->next; /* This block uses the control key to make the object selected by its center point rather than its contents */ /* in editmode do not activate */ @@ -1440,13 +1440,13 @@ static bool ed_object_select_pick( else { base = startbase; while (base) { - if (BASE_SELECTABLE(v3d, base)) { + if (BASE_SELECTABLE_NEW(base)) { float screen_co[2]; if (ED_view3d_project_float_global(ar, base->object->obmat[3], screen_co, V3D_PROJ_TEST_CLIP_BB | V3D_PROJ_TEST_CLIP_WIN | V3D_PROJ_TEST_CLIP_NEAR) == V3D_PROJ_RET_OK) { float dist_temp = len_manhattan_v2v2(mval_fl, screen_co); - if (base == BASACT) dist_temp += 10.0f; + if (base == BASACT_NEW) dist_temp += 10.0f; if (dist_temp < dist) { dist = dist_temp; basact = base; @@ -1455,7 +1455,7 @@ static bool ed_object_select_pick( } base = base->next; - if (base == NULL) base = FIRSTBASE; + if (base == NULL) base = FIRSTBASE_NEW; if (base == startbase) break; } } @@ -1482,7 +1482,7 @@ static bool ed_object_select_pick( if (has_bones && basact) { if (basact->object->type == OB_CAMERA) { - if (BASACT == basact) { + if (BASACT_NEW == basact) { int i, hitresult; bool changed = false; @@ -1520,8 +1520,8 @@ static bool ed_object_select_pick( changed = true; } - basact->flag |= SELECT; - basact->object->flag = basact->flag; + basact->flag |= BASE_SELECTED; + BKE_scene_object_base_flag_sync_from_base(basact); retval = true; @@ -1544,22 +1544,22 @@ static bool ed_object_select_pick( /* we make the armature selected: * not-selected active object in posemode won't work well for tools */ - basact->flag |= SELECT; - basact->object->flag = basact->flag; + basact->flag |= BASE_SELECTED; + BKE_scene_base_flag_sync_from_base(basact); retval = true; WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, basact->object); WM_event_add_notifier(C, NC_OBJECT | ND_BONE_ACTIVE, basact->object); /* in weightpaint, we use selected bone to select vertexgroup, so no switch to new active object */ - if (BASACT && (BASACT->object->mode & OB_MODE_WEIGHT_PAINT)) { + if (BASACT_NEW && (BASACT_NEW->object->mode & OB_MODE_WEIGHT_PAINT)) { /* prevent activating */ basact = NULL; } } /* prevent bone selecting to pass on to object selecting */ - if (basact == BASACT) + if (basact == BASACT_NEW) basact = NULL; } } @@ -1571,37 +1571,37 @@ static bool ed_object_select_pick( if (vc.obedit) { /* only do select */ - deselectall_except(scene, basact); - ED_base_object_select(basact, BA_SELECT); + deselectall_except(sl, basact); + ED_object_base_select(basact, BA_SELECT); } /* also prevent making it active on mouse selection */ - else if (BASE_SELECTABLE(v3d, basact)) { + else if (BASE_SELECTABLE_NEW(basact)) { - oldbasact = BASACT; + oldbasact = BASACT_NEW; if (extend) { - ED_base_object_select(basact, BA_SELECT); + ED_object_base_select(basact, BA_SELECT); } else if (deselect) { - ED_base_object_select(basact, BA_DESELECT); + ED_object_base_select(basact, BA_DESELECT); } else if (toggle) { - if (basact->flag & SELECT) { + if (basact->flag & BASE_SELECTED) { if (basact == oldbasact) { - ED_base_object_select(basact, BA_DESELECT); + ED_object_base_select(basact, BA_DESELECT); } } else { - ED_base_object_select(basact, BA_SELECT); + ED_object_base_select(basact, BA_SELECT); } } else { - deselectall_except(scene, basact); - ED_base_object_select(basact, BA_SELECT); + deselectall_except(sl, basact); + ED_object_base_select(basact, BA_SELECT); } if ((oldbasact != basact) && (is_obedit == false)) { - ED_base_object_activate(C, basact); /* adds notifier */ + ED_object_base_activate(C, basact); /* adds notifier */ } } @@ -2031,7 +2031,7 @@ static int do_object_pose_box_select(bContext *C, ViewContext *vc, rcti *rect, b CTX_DATA_END; } else { - object_deselect_all_visible(vc->scene, vc->v3d); + object_deselect_all_visible(vc->sl); } } @@ -2051,7 +2051,7 @@ static int do_object_pose_box_select(bContext *C, ViewContext *vc, rcti *rect, b */ if (hits > 0) { /* no need to loop if there's no hit */ - Base *base; + BaseLegacy *base; col = vbuffer + 3; for (base = vc->scene->base.first; base && hits; base = base->next) { @@ -2786,22 +2786,22 @@ static void obedit_circle_select(ViewContext *vc, const bool select, const int m static bool object_circle_select(ViewContext *vc, const bool select, const int mval[2], float rad) { - Scene *scene = vc->scene; + SceneLayer *sl = vc->sl; const float radius_squared = rad * rad; const float mval_fl[2] = {mval[0], mval[1]}; bool changed = false; - const int select_flag = select ? SELECT : 0; + const int select_flag = select ? BASE_SELECTED : 0; Base *base; - for (base = FIRSTBASE; base; base = base->next) { - if (BASE_SELECTABLE(vc->v3d, base) && ((base->flag & SELECT) != select_flag)) { + for (base = FIRSTBASE_NEW; base; base = base->next) { + if (BASE_SELECTABLE_NEW(base) && ((base->flag & BASE_SELECTED) != select_flag)) { float screen_co[2]; if (ED_view3d_project_float_global(vc->ar, base->object->obmat[3], screen_co, V3D_PROJ_TEST_CLIP_BB | V3D_PROJ_TEST_CLIP_WIN | V3D_PROJ_TEST_CLIP_NEAR) == V3D_PROJ_RET_OK) { if (len_squared_v2v2(mval_fl, screen_co) <= radius_squared) { - ED_base_object_select(base, select ? BA_SELECT : BA_DESELECT); + ED_object_base_select(base, select ? BA_SELECT : BA_DESELECT); changed = true; } } diff --git a/source/blender/editors/space_view3d/view3d_view.c b/source/blender/editors/space_view3d/view3d_view.c index 8582952d1a0..2da1871009e 100644 --- a/source/blender/editors/space_view3d/view3d_view.c +++ b/source/blender/editors/space_view3d/view3d_view.c @@ -1091,29 +1091,28 @@ void view3d_viewmatrix_set(Scene *scene, const View3D *v3d, RegionView3D *rv3d) } } -static void view3d_select_loop(ViewContext *vc, Scene *scene, View3D *v3d, ARegion *ar, bool use_obedit_skip) +static void view3d_select_loop(ViewContext *vc, Scene *scene, SceneLayer *sl, View3D *v3d, ARegion *ar, bool use_obedit_skip) { short code = 1; char dt; short dtx; if (vc->obedit && vc->obedit->type == OB_MBALL) { - draw_object(scene, ar, v3d, BASACT, DRAW_PICKING | DRAW_CONSTCOLOR); + draw_object(scene, sl, ar, v3d, BASACT_NEW, DRAW_PICKING | DRAW_CONSTCOLOR); } else if ((vc->obedit && vc->obedit->type == OB_ARMATURE)) { /* if not drawing sketch, draw bones */ if (!BDR_drawSketchNames(vc)) { - draw_object(scene, ar, v3d, BASACT, DRAW_PICKING | DRAW_CONSTCOLOR); + draw_object(scene, sl, ar, v3d, BASACT_NEW, DRAW_PICKING | DRAW_CONSTCOLOR); } } else { Base *base; v3d->xray = true; /* otherwise it postpones drawing */ - for (base = scene->base.first; base; base = base->next) { - if (base->lay & v3d->lay) { - - if ((base->object->restrictflag & OB_RESTRICT_SELECT) || + for (base = sl->object_bases.first; base; base = base->next) { + if ((base->flag & BASE_VISIBLED) != 0) { + if (((base->flag & BASE_SELECTABLED) == 0) || (use_obedit_skip && (scene->obedit->data == base->object->data))) { base->selcol = 0; @@ -1122,7 +1121,7 @@ static void view3d_select_loop(ViewContext *vc, Scene *scene, View3D *v3d, ARegi base->selcol = code; if (GPU_select_load_id(code)) { - draw_object(scene, ar, v3d, base, DRAW_PICKING | DRAW_CONSTCOLOR); + draw_object(scene, sl, ar, v3d, base, DRAW_PICKING | DRAW_CONSTCOLOR); /* we draw duplicators for selection too */ if ((base->object->transflag & OB_DUPLI)) { @@ -1130,7 +1129,7 @@ static void view3d_select_loop(ViewContext *vc, Scene *scene, View3D *v3d, ARegi DupliObject *dob; Base tbase; - tbase.flag = OB_FROMDUPLI; + tbase.flag_legacy = OB_FROMDUPLI; lb = object_duplilist(G.main->eval_ctx, scene, base->object); for (dob = lb->first; dob; dob = dob->next) { @@ -1145,7 +1144,7 @@ static void view3d_select_loop(ViewContext *vc, Scene *scene, View3D *v3d, ARegi dt = tbase.object->dt; tbase.object->dt = MIN2(tbase.object->dt, base->object->dt); dtx = tbase.object->dtx; tbase.object->dtx = base->object->dtx; - draw_object(scene, ar, v3d, &tbase, DRAW_PICKING | DRAW_CONSTCOLOR); + draw_object(scene, sl, ar, v3d, &tbase, DRAW_PICKING | DRAW_CONSTCOLOR); tbase.object->dt = dt; tbase.object->dtx = dtx; @@ -1173,6 +1172,7 @@ static void view3d_select_loop(ViewContext *vc, Scene *scene, View3D *v3d, ARegi short view3d_opengl_select(ViewContext *vc, unsigned int *buffer, unsigned int bufsize, const rcti *input, bool do_nearest) { Scene *scene = vc->scene; + SceneLayer *sl = vc->sl; View3D *v3d = vc->v3d; ARegion *ar = vc->ar; rctf rect; @@ -1209,7 +1209,7 @@ short view3d_opengl_select(ViewContext *vc, unsigned int *buffer, unsigned int b else GPU_select_begin(buffer, bufsize, &rect, GPU_SELECT_ALL, 0); - view3d_select_loop(vc, scene, v3d, ar, use_obedit_skip); + view3d_select_loop(vc, scene, sl, v3d, ar, use_obedit_skip); hits = GPU_select_end(); @@ -1217,7 +1217,7 @@ short view3d_opengl_select(ViewContext *vc, unsigned int *buffer, unsigned int b if (do_passes) { GPU_select_begin(buffer, bufsize, &rect, GPU_SELECT_NEAREST_SECOND_PASS, hits); - view3d_select_loop(vc, scene, v3d, ar, use_obedit_skip); + view3d_select_loop(vc, scene, sl, v3d, ar, use_obedit_skip); GPU_select_end(); } @@ -1319,7 +1319,7 @@ static bool view3d_localview_init( ReportList *reports) { View3D *v3d = sa->spacedata.first; - Base *base; + BaseLegacy *base; float min[3], max[3], box[3], mid[3]; float size = 0.0f; unsigned int locallay; @@ -1422,7 +1422,7 @@ static bool view3d_localview_init( if (base->lay & locallay) { base->lay -= locallay; if (base->lay == 0) base->lay = v3d->layact; - if (base->object != scene->obedit) base->flag |= SELECT; + if (base->object != scene->obedit) base->flag_legacy |= SELECT; base->object->lay = base->lay; } } @@ -1493,7 +1493,7 @@ static bool view3d_localview_exit( Main *bmain, Scene *scene, ScrArea *sa, const int smooth_viewtx) { View3D *v3d = sa->spacedata.first; - struct Base *base; + struct BaseLegacy *base; unsigned int locallay; if (v3d->localvd) { @@ -1510,7 +1510,7 @@ static bool view3d_localview_exit( base->lay -= locallay; if (base->lay == 0) base->lay = v3d->layact; if (base->object != scene->obedit) { - base->flag |= SELECT; + base->flag_legacy |= SELECT; base->object->flag |= SELECT; } base->object->lay = base->lay; diff --git a/source/blender/editors/space_view3d/view3d_walk.c b/source/blender/editors/space_view3d/view3d_walk.c index 542dc410bc3..8390d56c610 100644 --- a/source/blender/editors/space_view3d/view3d_walk.c +++ b/source/blender/editors/space_view3d/view3d_walk.c @@ -57,6 +57,8 @@ #include "UI_interface.h" #include "UI_resources.h" +#include "GPU_immediate.h" + #include "view3d_intern.h" /* own include */ #ifdef WITH_INPUT_NDOF @@ -338,24 +340,33 @@ static void drawWalkPixel(const struct bContext *UNUSED(C), ARegion *ar, void *a yoff = walk->ar->winy / 2; } - UI_ThemeColor(TH_VIEW_OVERLAY); - glBegin(GL_LINES); + VertexFormat *format = immVertexFormat(); + unsigned int pos = add_attrib(format, "pos", GL_INT, 2, CONVERT_INT_TO_FLOAT); + + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + + immUniformThemeColor(TH_VIEW_OVERLAY); + + immBegin(GL_LINES, 8); + /* North */ - glVertex2i(xoff, yoff + inner_length); - glVertex2i(xoff, yoff + outter_length); + immVertex2i(pos, xoff, yoff + inner_length); + immVertex2i(pos, xoff, yoff + outter_length); /* East */ - glVertex2i(xoff + inner_length, yoff); - glVertex2i(xoff + outter_length, yoff); + immVertex2i(pos, xoff + inner_length, yoff); + immVertex2i(pos, xoff + outter_length, yoff); /* South */ - glVertex2i(xoff, yoff - inner_length); - glVertex2i(xoff, yoff - outter_length); + immVertex2i(pos, xoff, yoff - inner_length); + immVertex2i(pos, xoff, yoff - outter_length); /* West */ - glVertex2i(xoff - inner_length, yoff); - glVertex2i(xoff - outter_length, yoff); - glEnd(); + immVertex2i(pos, xoff - inner_length, yoff); + immVertex2i(pos, xoff - outter_length, yoff); + + immEnd(); + immUnbindProgram(); } static void walk_update_header(bContext *C, wmOperator *op, WalkInfo *walk) diff --git a/source/blender/editors/transform/CMakeLists.txt b/source/blender/editors/transform/CMakeLists.txt index b7de49d8158..1a41d9ac95a 100644 --- a/source/blender/editors/transform/CMakeLists.txt +++ b/source/blender/editors/transform/CMakeLists.txt @@ -58,10 +58,6 @@ if(WITH_INTERNATIONAL) add_definitions(-DWITH_INTERNATIONAL) endif() -if(WITH_LEGACY_DEPSGRAPH) - add_definitions(-DWITH_LEGACY_DEPSGRAPH) -endif() - add_definitions(${GL_DEFINITIONS}) blender_add_lib(bf_editor_transform "${SRC}" "${INC}" "${INC_SYS}") diff --git a/source/blender/editors/transform/transform.c b/source/blender/editors/transform/transform.c index 1916f9b4dab..9316465fd5c 100644 --- a/source/blender/editors/transform/transform.c +++ b/source/blender/editors/transform/transform.c @@ -64,9 +64,11 @@ #include "BKE_mask.h" #include "BKE_report.h" -#include "BIF_gl.h" #include "BIF_glutil.h" +#include "GPU_immediate.h" +#include "GPU_matrix.h" + #include "ED_image.h" #include "ED_keyframing.h" #include "ED_screen.h" @@ -1598,8 +1600,16 @@ typedef enum { LEFT, RIGHT } ArrowDirection; + +#define POS_INDEX 0 +/* NOTE: this --^ is a bit hackish, but simplifies VertexFormat usage among functions + * private to this file - merwin + */ + static void drawArrow(ArrowDirection d, short offset, short length, short size) { + immBegin(PRIM_LINES, 6); + switch (d) { case LEFT: offset = -offset; @@ -1607,14 +1617,12 @@ static void drawArrow(ArrowDirection d, short offset, short length, short size) size = -size; /* fall-through */ case RIGHT: - glBegin(GL_LINES); - glVertex2s(offset, 0); - glVertex2s(offset + length, 0); - glVertex2s(offset + length, 0); - glVertex2s(offset + length - size, -size); - glVertex2s(offset + length, 0); - glVertex2s(offset + length - size, size); - glEnd(); + immVertex2f(POS_INDEX, offset, 0); + immVertex2f(POS_INDEX, offset + length, 0); + immVertex2f(POS_INDEX, offset + length, 0); + immVertex2f(POS_INDEX, offset + length - size, -size); + immVertex2f(POS_INDEX, offset + length, 0); + immVertex2f(POS_INDEX, offset + length - size, size); break; case DOWN: @@ -1623,45 +1631,45 @@ static void drawArrow(ArrowDirection d, short offset, short length, short size) size = -size; /* fall-through */ case UP: - glBegin(GL_LINES); - glVertex2s(0, offset); - glVertex2s(0, offset + length); - glVertex2s(0, offset + length); - glVertex2s(-size, offset + length - size); - glVertex2s(0, offset + length); - glVertex2s(size, offset + length - size); - glEnd(); + immVertex2f(POS_INDEX, 0, offset); + immVertex2f(POS_INDEX, 0, offset + length); + immVertex2f(POS_INDEX, 0, offset + length); + immVertex2f(POS_INDEX, -size, offset + length - size); + immVertex2f(POS_INDEX, 0, offset + length); + immVertex2f(POS_INDEX, size, offset + length - size); break; } + + immEnd(); } static void drawArrowHead(ArrowDirection d, short size) { + immBegin(PRIM_LINES, 4); + switch (d) { case LEFT: size = -size; /* fall-through */ case RIGHT: - glBegin(GL_LINES); - glVertex2s(0, 0); - glVertex2s(-size, -size); - glVertex2s(0, 0); - glVertex2s(-size, size); - glEnd(); + immVertex2f(POS_INDEX, 0, 0); + immVertex2f(POS_INDEX, -size, -size); + immVertex2f(POS_INDEX, 0, 0); + immVertex2f(POS_INDEX, -size, size); break; case DOWN: size = -size; /* fall-through */ case UP: - glBegin(GL_LINES); - glVertex2s(0, 0); - glVertex2s(-size, -size); - glVertex2s(0, 0); - glVertex2s(size, -size); - glEnd(); + immVertex2f(POS_INDEX, 0, 0); + immVertex2f(POS_INDEX, -size, -size); + immVertex2f(POS_INDEX, 0, 0); + immVertex2f(POS_INDEX, size, -size); break; } + + immEnd(); } static void drawArc(float size, float angle_start, float angle_end, int segments) @@ -1670,14 +1678,14 @@ static void drawArc(float size, float angle_start, float angle_end, int segments float angle; int a; - glBegin(GL_LINE_STRIP); + immBegin(PRIM_LINE_STRIP, segments + 1); for (angle = angle_start, a = 0; a < segments; angle += delta, a++) { - glVertex2f(cosf(angle) * size, sinf(angle) * size); + immVertex2f(POS_INDEX, cosf(angle) * size, sinf(angle) * size); } - glVertex2f(cosf(angle_end) * size, sinf(angle_end) * size); + immVertex2f(POS_INDEX, cosf(angle_end) * size, sinf(angle_end) * size); - glEnd(); + immEnd(); } static int helpline_poll(bContext *C) @@ -1695,10 +1703,7 @@ static void drawHelpline(bContext *UNUSED(C), int x, int y, void *customdata) if (t->helpline != HLP_NONE && !(t->flag & T_USES_MANIPULATOR)) { float vecrot[3], cent[2]; - int mval[2]; - - mval[0] = x; - mval[1] = y; + float mval[3] = { x, y, 0.0f }; copy_v3_v3(vecrot, t->center); if (t->flag & T_EDIT) { @@ -1712,42 +1717,45 @@ static void drawHelpline(bContext *UNUSED(C), int x, int y, void *customdata) projectFloatViewEx(t, vecrot, cent, V3D_PROJ_TEST_CLIP_ZERO); - glPushMatrix(); + gpuMatrixBegin3D_legacy(); /* TODO(merwin): finish the 2D matrix API & use here */ + + unsigned pos = add_attrib(immVertexFormat(), "pos", COMP_F32, 2, KEEP_FLOAT); + BLI_assert(pos == POS_INDEX); + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); switch (t->helpline) { case HLP_SPRING: - UI_ThemeColor(TH_VIEW_OVERLAY); - + immUniformThemeColor(TH_VIEW_OVERLAY); setlinestyle(3); - glLineWidth(1); - glBegin(GL_LINES); - glVertex2iv(t->mval); - glVertex2fv(cent); - glEnd(); + glLineWidth(1.0f); + + immBegin(PRIM_LINES, 2); + immVertex2f(POS_INDEX, (float)t->mval[0], (float)t->mval[1]); + immVertex2fv(POS_INDEX, cent); + immEnd(); - glTranslate2iv(mval); - glRotatef(-RAD2DEGF(atan2f(cent[0] - t->mval[0], cent[1] - t->mval[1])), 0, 0, 1); + gpuTranslate3fv(mval); + gpuRotateAxis(-RAD2DEGF(atan2f(cent[0] - t->mval[0], cent[1] - t->mval[1])), 'Z'); setlinestyle(0); - glLineWidth(3.0); + glLineWidth(3.0f); drawArrow(UP, 5, 10, 5); drawArrow(DOWN, 5, 10, 5); break; case HLP_HARROW: - UI_ThemeColor(TH_VIEW_OVERLAY); - - glTranslate2iv(mval); + immUniformThemeColor(TH_VIEW_OVERLAY); + gpuTranslate3fv(mval); - glLineWidth(3.0); + glLineWidth(3.0f); drawArrow(RIGHT, 5, 10, 5); drawArrow(LEFT, 5, 10, 5); break; case HLP_VARROW: - UI_ThemeColor(TH_VIEW_OVERLAY); + immUniformThemeColor(TH_VIEW_OVERLAY); - glTranslate2iv(mval); + gpuTranslate3fv(mval); - glLineWidth(3.0); + glLineWidth(3.0f); drawArrow(UP, 5, 10, 5); drawArrow(DOWN, 5, 10, 5); break; @@ -1758,33 +1766,35 @@ static void drawHelpline(bContext *UNUSED(C), int x, int y, void *customdata) float dist = hypotf(dx, dy); float delta_angle = min_ff(15.0f / dist, (float)M_PI / 4.0f); float spacing_angle = min_ff(5.0f / dist, (float)M_PI / 12.0f); - UI_ThemeColor(TH_VIEW_OVERLAY); + + immUniformThemeColor(TH_VIEW_OVERLAY); setlinestyle(3); - glLineWidth(1); - glBegin(GL_LINES); - glVertex2iv(t->mval); - glVertex2fv(cent); - glEnd(); + glLineWidth(1.0f); + + immBegin(PRIM_LINES, 2); + immVertex2f(POS_INDEX, (float)t->mval[0], (float)t->mval[1]); + immVertex2fv(POS_INDEX, cent); + immEnd(); - glTranslatef(cent[0] - t->mval[0] + mval[0], cent[1] - t->mval[1] + mval[1], 0); + gpuTranslate3f(cent[0] - t->mval[0] + mval[0], cent[1] - t->mval[1] + mval[1], 0); setlinestyle(0); - glLineWidth(3.0); + glLineWidth(3.0f); drawArc(dist, angle - delta_angle, angle - spacing_angle, 10); drawArc(dist, angle + spacing_angle, angle + delta_angle, 10); - glPushMatrix(); + gpuPushMatrix(); - glTranslatef(cosf(angle - delta_angle) * dist, sinf(angle - delta_angle) * dist, 0); - glRotatef(RAD2DEGF(angle - delta_angle), 0, 0, 1); + gpuTranslate3f(cosf(angle - delta_angle) * dist, sinf(angle - delta_angle) * dist, 0); + gpuRotateAxis(RAD2DEGF(angle - delta_angle), 'Z'); drawArrowHead(DOWN, 5); - glPopMatrix(); + gpuPopMatrix(); - glTranslatef(cosf(angle + delta_angle) * dist, sinf(angle + delta_angle) * dist, 0); - glRotatef(RAD2DEGF(angle + delta_angle), 0, 0, 1); + gpuTranslate3f(cosf(angle + delta_angle) * dist, sinf(angle + delta_angle) * dist, 0); + gpuRotateAxis(RAD2DEGF(angle + delta_angle), 'Z'); drawArrowHead(UP, 5); break; @@ -1794,18 +1804,18 @@ static void drawHelpline(bContext *UNUSED(C), int x, int y, void *customdata) unsigned char col[3], col2[3]; UI_GetThemeColor3ubv(TH_GRID, col); - glTranslate2iv(mval); + gpuTranslate3fv(mval); - glLineWidth(3.0); + glLineWidth(3.0f); UI_make_axis_color(col, col2, 'X'); - glColor3ubv((GLubyte *)col2); + immUniformColor3ubv((GLubyte *)col2); drawArrow(RIGHT, 5, 10, 5); drawArrow(LEFT, 5, 10, 5); UI_make_axis_color(col, col2, 'Y'); - glColor3ubv((GLubyte *)col2); + immUniformColor3ubv((GLubyte *)col2); drawArrow(UP, 5, 10, 5); drawArrow(DOWN, 5, 10, 5); @@ -1813,7 +1823,8 @@ static void drawHelpline(bContext *UNUSED(C), int x, int y, void *customdata) } } - glPopMatrix(); + immUnbindProgram(); + gpuMatrixEnd(); } } @@ -1821,7 +1832,7 @@ static void drawTransformView(const struct bContext *C, ARegion *UNUSED(ar), voi { TransInfo *t = arg; - glLineWidth(1.0); + glLineWidth(1.0f); drawConstraint(t); drawPropCircle(C, t); @@ -1841,8 +1852,9 @@ static void drawAutoKeyWarning(TransInfo *UNUSED(t), ARegion *ar) int xco, yco; ED_region_visible_rect(ar, &rect); - - BLF_width_and_height_default(printable, BLF_DRAW_STR_DUMMY_MAX, &printable_size[0], &printable_size[1]); + + const int font_id = BLF_default(); + BLF_width_and_height(font_id, printable, BLF_DRAW_STR_DUMMY_MAX, &printable_size[0], &printable_size[1]); xco = (rect.xmax - U.widget_unit) - (int)printable_size[0]; yco = (rect.ymax - U.widget_unit); @@ -1850,7 +1862,9 @@ static void drawAutoKeyWarning(TransInfo *UNUSED(t), ARegion *ar) /* warning text (to clarify meaning of overlays) * - original color was red to match the icon, but that clashes badly with a less nasty border */ - UI_ThemeColorShade(TH_TEXT_HI, -50); + unsigned char color[3]; + UI_GetThemeColorShade3ubv(TH_TEXT_HI, -50, color); + BLF_color3ubv(font_id, color); #ifdef WITH_INTERNATIONAL BLF_draw_default(xco, yco, 0.0f, printable, BLF_DRAW_STR_DUMMY_MAX); #else @@ -1873,7 +1887,8 @@ static void drawTransformPixel(const struct bContext *UNUSED(C), ARegion *ar, vo { TransInfo *t = arg; Scene *scene = t->scene; - Object *ob = OBACT; + SceneLayer *sl = t->sl; + Object *ob = OBACT_NEW; /* draw autokeyframing hint in the corner * - only draw if enabled (advanced users may be distracted/annoyed), @@ -6850,10 +6865,13 @@ static void drawEdgeSlide(TransInfo *t) glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - glPushAttrib(GL_CURRENT_BIT | GL_LINE_BIT | GL_POINT_BIT); - glPushMatrix(); + gpuMatrixBegin3D_legacy(); + + gpuMultMatrix3D(t->obedit->obmat); + + unsigned pos = add_attrib(immVertexFormat(), "pos", COMP_F32, 3, KEEP_FLOAT); - glMultMatrixf(t->obedit->obmat); + immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR); if (sld->use_even == true) { float co_a[3], co_b[3], co_mark[3]; @@ -6867,39 +6885,35 @@ static void drawEdgeSlide(TransInfo *t) add_v3_v3v3(co_b, curr_sv->v_co_orig, curr_sv->dir_side[1]); glLineWidth(line_size); - UI_ThemeColorShadeAlpha(TH_EDGE_SELECT, 80, alpha_shade); - glBegin(GL_LINES); + immUniformThemeColorShadeAlpha(TH_EDGE_SELECT, 80, alpha_shade); + immBeginAtMost(PRIM_LINES, 4); if (curr_sv->v_side[0]) { - glVertex3fv(curr_sv->v_side[0]->co); - glVertex3fv(curr_sv->v_co_orig); + immVertex3fv(pos, curr_sv->v_side[0]->co); + immVertex3fv(pos, curr_sv->v_co_orig); } if (curr_sv->v_side[1]) { - glVertex3fv(curr_sv->v_side[1]->co); - glVertex3fv(curr_sv->v_co_orig); + immVertex3fv(pos, curr_sv->v_side[1]->co); + immVertex3fv(pos, curr_sv->v_co_orig); } - glEnd(); + immEnd(); - UI_ThemeColorShadeAlpha(TH_SELECT, -30, alpha_shade); + immUniformThemeColorShadeAlpha(TH_SELECT, -30, alpha_shade); glPointSize(ctrl_size); - glBegin(GL_POINTS); + immBegin(PRIM_POINTS, 1); if (sld->flipped) { - if (curr_sv->v_side[1]) glVertex3fv(curr_sv->v_side[1]->co); + if (curr_sv->v_side[1]) immVertex3fv(pos, curr_sv->v_side[1]->co); } else { - if (curr_sv->v_side[0]) glVertex3fv(curr_sv->v_side[0]->co); + if (curr_sv->v_side[0]) immVertex3fv(pos, curr_sv->v_side[0]->co); } - glEnd(); + immEnd(); - UI_ThemeColorShadeAlpha(TH_SELECT, 255, alpha_shade); + immUniformThemeColorShadeAlpha(TH_SELECT, 255, alpha_shade); glPointSize(guide_size); - glBegin(GL_POINTS); -#if 0 - interp_v3_v3v3(co_mark, co_b, co_a, fac); - glVertex3fv(co_mark); -#endif + immBegin(PRIM_POINTS, 1); interp_line_v3_v3v3v3(co_mark, co_b, curr_sv->v_co_orig, co_a, fac); - glVertex3fv(co_mark); - glEnd(); + immVertex3fv(pos, co_mark); + immEnd(); } else { if (is_clamp == false) { @@ -6909,8 +6923,8 @@ static void drawEdgeSlide(TransInfo *t) const int alpha_shade = -160; glLineWidth(line_size); - UI_ThemeColorShadeAlpha(TH_EDGE_SELECT, 80, alpha_shade); - glBegin(GL_LINES); + immUniformThemeColorShadeAlpha(TH_EDGE_SELECT, 80, alpha_shade); + immBegin(PRIM_LINES, sld->totsv * 2); sv = sld->sv; for (i = 0; i < sld->totsv; i++, sv++) { @@ -6928,18 +6942,19 @@ static void drawEdgeSlide(TransInfo *t) add_v3_v3(a, sv->v_co_orig); add_v3_v3(b, sv->v_co_orig); - glVertex3fv(a); - glVertex3fv(b); + immVertex3fv(pos, a); + immVertex3fv(pos, b); } - glEnd(); + immEnd(); } else { BLI_assert(0); } } - glPopMatrix(); - glPopAttrib(); + immUnbindProgram(); + + gpuMatrixEnd(); glDisable(GL_BLEND); @@ -7463,19 +7478,23 @@ static void drawVertSlide(TransInfo *t) glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - glPushAttrib(GL_CURRENT_BIT | GL_LINE_BIT | GL_POINT_BIT); - glPushMatrix(); + gpuMatrixBegin3D_legacy(); - glMultMatrixf(t->obedit->obmat); + gpuMultMatrix3D(t->obedit->obmat); glLineWidth(line_size); - UI_ThemeColorShadeAlpha(TH_EDGE_SELECT, 80, alpha_shade); - glBegin(GL_LINES); + + unsigned pos = add_attrib(immVertexFormat(), "pos", COMP_F32, 3, KEEP_FLOAT); + + immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR); + immUniformThemeColorShadeAlpha(TH_EDGE_SELECT, 80, alpha_shade); + + immBegin(PRIM_LINES, sld->totsv * 2); if (is_clamp) { sv = sld->sv; for (i = 0; i < sld->totsv; i++, sv++) { - glVertex3fv(sv->co_orig_3d); - glVertex3fv(sv->co_link_orig_3d[sv->co_link_curr]); + immVertex3fv(pos, sv->co_orig_3d); + immVertex3fv(pos, sv->co_link_orig_3d[sv->co_link_curr]); } } else { @@ -7488,19 +7507,19 @@ static void drawVertSlide(TransInfo *t) add_v3_v3(a, sv->co_orig_3d); add_v3_v3(b, sv->co_orig_3d); - glVertex3fv(a); - glVertex3fv(b); + immVertex3fv(pos, a); + immVertex3fv(pos, b); } } - glEnd(); + immEnd(); glPointSize(ctrl_size); - glBegin(GL_POINTS); - glVertex3fv((sld->flipped && sld->use_even) ? + immBegin(PRIM_POINTS, 1); + immVertex3fv(pos, (sld->flipped && sld->use_even) ? curr_sv->co_link_orig_3d[curr_sv->co_link_curr] : curr_sv->co_orig_3d); - glEnd(); + immEnd(); glDisable(GL_BLEND); @@ -7526,19 +7545,20 @@ static void drawVertSlide(TransInfo *t) add_v3_v3(co_dest_3d, curr_sv->co_orig_3d); - glLineWidth(1); + glLineWidth(1.0f); setlinestyle(1); - cpack(0xffffff); - glBegin(GL_LINES); - glVertex3fv(curr_sv->co_orig_3d); - glVertex3fv(co_dest_3d); + imm_cpack(0xffffff); - glEnd(); + immBegin(PRIM_LINES, 2); + immVertex3fv(pos, curr_sv->co_orig_3d); + immVertex3fv(pos, co_dest_3d); + immEnd(); } - glPopMatrix(); - glPopAttrib(); + immUnbindProgram(); + + gpuMatrixEnd(); if (v3d && v3d->zbuf) glEnable(GL_DEPTH_TEST); diff --git a/source/blender/editors/transform/transform.h b/source/blender/editors/transform/transform.h index d60eb2f0778..3abd86384cc 100644 --- a/source/blender/editors/transform/transform.h +++ b/source/blender/editors/transform/transform.h @@ -464,6 +464,7 @@ typedef struct TransInfo { struct ScrArea *sa; struct ARegion *ar; struct Scene *scene; + struct SceneLayer *sl; struct ToolSettings *settings; struct wmTimer *animtimer; struct wmKeyMap *keymap; /* so we can do lookups for header text */ diff --git a/source/blender/editors/transform/transform_constraints.c b/source/blender/editors/transform/transform_constraints.c index d7b670b6476..60689be5500 100644 --- a/source/blender/editors/transform/transform_constraints.c +++ b/source/blender/editors/transform/transform_constraints.c @@ -40,9 +40,10 @@ #include "DNA_space_types.h" #include "DNA_view3d_types.h" -#include "BIF_gl.h" #include "BIF_glutil.h" +#include "GPU_immediate.h" + #include "BLI_math.h" #include "BLI_utildefines.h" #include "BLI_string.h" @@ -715,7 +716,6 @@ void drawConstraint(TransInfo *t) else { if (tc->mode & CON_SELECT) { float vec[3]; - char col2[3] = {255, 255, 255}; int depth_test_enabled; convertViewVec(t, vec, (t->mval[0] - t->con.imval[0]), (t->mval[1] - t->con.imval[1])); @@ -725,19 +725,26 @@ void drawConstraint(TransInfo *t) drawLine(t, t->center_global, tc->mtx[1], 'Y', 0); drawLine(t, t->center_global, tc->mtx[2], 'Z', 0); - glColor3ubv((GLubyte *)col2); - depth_test_enabled = glIsEnabled(GL_DEPTH_TEST); if (depth_test_enabled) glDisable(GL_DEPTH_TEST); + unsigned pos = add_attrib(immVertexFormat(), "pos", GL_FLOAT, 3, KEEP_FLOAT); + + immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR); + immUniformColor3ub(255, 255, 255); + setlinestyle(1); - glBegin(GL_LINES); - glVertex3fv(t->center_global); - glVertex3fv(vec); - glEnd(); + + immBegin(GL_LINES, 2); + immVertex3fv(pos, t->center_global); + immVertex3fv(pos, vec); + immEnd(); + setlinestyle(0); + immUnbindProgram(); + if (depth_test_enabled) glEnable(GL_DEPTH_TEST); } @@ -762,8 +769,6 @@ void drawPropCircle(const struct bContext *C, TransInfo *t) float tmat[4][4], imat[4][4]; int depth_test_enabled; - UI_ThemeColor(TH_GRID); - if (t->spacetype == SPACE_VIEW3D && rv3d != NULL) { copy_m4_m4(tmat, rv3d->viewmat); invert_m4_m4(imat, tmat); @@ -796,10 +801,17 @@ void drawPropCircle(const struct bContext *C, TransInfo *t) if (depth_test_enabled) glDisable(GL_DEPTH_TEST); + unsigned int pos = add_attrib(immVertexFormat(), "pos", GL_FLOAT, 3, KEEP_FLOAT); + + immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR); + immUniformThemeColor(TH_GRID); + set_inverted_drawing(1); - drawcircball(GL_LINE_LOOP, t->center_global, t->prop_size, imat); + imm_drawcircball(t->center_global, t->prop_size, imat, pos); set_inverted_drawing(0); + immUnbindProgram(); + if (depth_test_enabled) glEnable(GL_DEPTH_TEST); diff --git a/source/blender/editors/transform/transform_conversions.c b/source/blender/editors/transform/transform_conversions.c index 091a5773cf0..b68b3365e46 100644 --- a/source/blender/editors/transform/transform_conversions.c +++ b/source/blender/editors/transform/transform_conversions.c @@ -72,6 +72,7 @@ #include "BKE_fcurve.h" #include "BKE_global.h" #include "BKE_gpencil.h" +#include "BKE_layer.h" #include "BKE_key.h" #include "BKE_main.h" #include "BKE_mesh.h" @@ -828,7 +829,6 @@ static void pose_grab_with_ik_clear(Object *ob) bKinematicConstraint *data; bPoseChannel *pchan; bConstraint *con, *next; - bool need_dependency_update = false; for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) { /* clear all temporary lock flags */ @@ -843,7 +843,6 @@ static void pose_grab_with_ik_clear(Object *ob) data = con->data; if (data->flag & CONSTRAINT_IK_TEMP) { /* iTaSC needs clear for removed constraints */ - need_dependency_update = true; BIK_clear_data(ob->pose); BLI_remlink(&pchan->constraints, con); @@ -858,13 +857,8 @@ static void pose_grab_with_ik_clear(Object *ob) } } -#ifdef WITH_LEGACY_DEPSGRAPH - if (!DEG_depsgraph_use_legacy() && need_dependency_update) -#endif - { - /* TODO(sergey): Consider doing partial update only. */ - DAG_relations_tag_update(G.main); - } + /* TODO(sergey): Consider doing partial update only. */ + DAG_relations_tag_update(G.main); } /* adds the IK to pchan - returns if added */ @@ -1017,13 +1011,8 @@ static short pose_grab_with_ik(Object *ob) /* iTaSC needs clear for new IK constraints */ if (tot_ik) { BIK_clear_data(ob->pose); -#ifdef WITH_LEGACY_DEPSGRAPH - if (!DEG_depsgraph_use_legacy()) -#endif - { - /* TODO(sergey): Consuder doing partial update only. */ - DAG_relations_tag_update(G.main); - } + /* TODO(sergey): Consuder doing partial update only. */ + DAG_relations_tag_update(G.main); } return (tot_ik) ? 1 : 0; @@ -5363,12 +5352,11 @@ static void ObjectToTransData(TransInfo *t, TransData *td, Object *ob) /* it deselects Bases, so we have to call the clear function always after */ static void set_trans_object_base_flags(TransInfo *t) { - Scene *scene = t->scene; - View3D *v3d = t->view; + SceneLayer *sl = t->sl; /* * if Base selected and has parent selected: - * base->flag = BA_WAS_SEL + * base->flag_legacy = BA_WAS_SEL */ Base *base; @@ -5377,32 +5365,32 @@ static void set_trans_object_base_flags(TransInfo *t) return; /* makes sure base flags and object flags are identical */ - BKE_scene_base_flag_to_objects(t->scene); + BKE_scene_base_flag_to_objects(t->sl); /* Make sure depsgraph is here. */ DAG_scene_relations_update(G.main, t->scene); /* handle pending update events, otherwise they got copied below */ - for (base = scene->base.first; base; base = base->next) { + for (base = sl->object_bases.first; base; base = base->next) { if (base->object->recalc & OB_RECALC_ALL) { /* TODO(sergey): Ideally, it's not needed. */ BKE_object_handle_update(G.main->eval_ctx, t->scene, base->object); } } - for (base = scene->base.first; base; base = base->next) { - base->flag &= ~BA_WAS_SEL; + for (base = sl->object_bases.first; base; base = base->next) { + base->flag_legacy &= ~BA_WAS_SEL; - if (TESTBASELIB_BGMODE(v3d, scene, base)) { + if (TESTBASELIB_BGMODE_NEW(base)) { Object *ob = base->object; Object *parsel = ob->parent; /* if parent selected, deselect */ while (parsel) { - if (parsel->flag & SELECT) { - Base *parbase = BKE_scene_base_find(scene, parsel); + Base *parbase = BKE_scene_layer_base_find(sl, parsel); + if (parbase->flag & BASE_SELECTED) { if (parbase) { /* in rare cases this can fail */ - if (TESTBASELIB_BGMODE(v3d, scene, parbase)) { + if (TESTBASELIB_BGMODE_NEW(parbase)) { break; } } @@ -5415,29 +5403,24 @@ static void set_trans_object_base_flags(TransInfo *t) if ((t->around == V3D_AROUND_LOCAL_ORIGINS) && (t->mode == TFM_ROTATION || t->mode == TFM_TRACKBALL)) { - base->flag |= BA_TRANSFORM_CHILD; + base->flag_legacy |= BA_TRANSFORM_CHILD; } else { - base->flag &= ~SELECT; - base->flag |= BA_WAS_SEL; + base->flag &= ~BASE_SELECTED; + base->flag_legacy |= BA_WAS_SEL; } } DAG_id_tag_update(&ob->id, OB_RECALC_OB); } } - /* all recalc flags get flushed to all layers, so a layer flip later on works fine */ -#ifdef WITH_LEGACY_DEPSGRAPH - DAG_scene_flush_update(G.main, t->scene, -1, 0); -#endif - /* and we store them temporal in base (only used for transform code) */ /* this because after doing updates, the object->recalc is cleared */ - for (base = scene->base.first; base; base = base->next) { + for (base = sl->object_bases.first; base; base = base->next) { if (base->object->recalc & OB_RECALC_OB) - base->flag |= BA_HAS_RECALC_OB; + base->flag_legacy |= BA_HAS_RECALC_OB; if (base->object->recalc & OB_RECALC_DATA) - base->flag |= BA_HAS_RECALC_DATA; + base->flag_legacy |= BA_HAS_RECALC_DATA; } } @@ -5459,8 +5442,7 @@ static bool mark_children(Object *ob) static int count_proportional_objects(TransInfo *t) { int total = 0; - Scene *scene = t->scene; - View3D *v3d = t->view; + SceneLayer *sl = t->sl; Base *base; /* rotations around local centers are allowed to propagate, so we take all objects */ @@ -5468,8 +5450,8 @@ static int count_proportional_objects(TransInfo *t) (t->mode == TFM_ROTATION || t->mode == TFM_TRACKBALL))) { /* mark all parents */ - for (base = scene->base.first; base; base = base->next) { - if (TESTBASELIB_BGMODE(v3d, scene, base)) { + for (base = sl->object_bases.first; base; base = base->next) { + if (TESTBASELIB_BGMODE_NEW(base)) { Object *parent = base->object->parent; /* flag all parents */ @@ -5481,22 +5463,24 @@ static int count_proportional_objects(TransInfo *t) } /* mark all children */ - for (base = scene->base.first; base; base = base->next) { + for (base = sl->object_bases.first; base; base = base->next) { /* all base not already selected or marked that is editable */ - if ((base->object->flag & (SELECT | BA_TRANSFORM_CHILD | BA_TRANSFORM_PARENT)) == 0 && - (BASE_EDITABLE_BGMODE(v3d, scene, base))) + if ((base->object->flag & (BA_TRANSFORM_CHILD | BA_TRANSFORM_PARENT)) == 0 && + (base->flag & BASE_SELECTED) == 0 && + (BASE_EDITABLE_BGMODE_NEW(base))) { mark_children(base->object); } } } - for (base = scene->base.first; base; base = base->next) { + for (base = sl->object_bases.first; base; base = base->next) { Object *ob = base->object; /* if base is not selected, not a parent of selection or not a child of selection and it is editable */ - if ((ob->flag & (SELECT | BA_TRANSFORM_CHILD | BA_TRANSFORM_PARENT)) == 0 && - (BASE_EDITABLE_BGMODE(v3d, scene, base))) + if ((ob->flag & (BA_TRANSFORM_CHILD | BA_TRANSFORM_PARENT)) == 0 && + (base->flag & BASE_SELECTED) == 0 && + (BASE_EDITABLE_BGMODE_NEW(base))) { DAG_id_tag_update(&ob->id, OB_RECALC_OB); @@ -5508,17 +5492,14 @@ static int count_proportional_objects(TransInfo *t) /* all recalc flags get flushed to all layers, so a layer flip later on works fine */ DAG_scene_relations_update(G.main, t->scene); -#ifdef WITH_LEGACY_DEPSGRAPH - DAG_scene_flush_update(G.main, t->scene, -1, 0); -#endif /* and we store them temporal in base (only used for transform code) */ /* this because after doing updates, the object->recalc is cleared */ - for (base = scene->base.first; base; base = base->next) { + for (base = sl->object_bases.first; base; base = base->next) { if (base->object->recalc & OB_RECALC_OB) - base->flag |= BA_HAS_RECALC_OB; + base->flag_legacy |= BA_HAS_RECALC_OB; if (base->object->recalc & OB_RECALC_DATA) - base->flag |= BA_HAS_RECALC_DATA; + base->flag_legacy |= BA_HAS_RECALC_DATA; } return total; @@ -5526,14 +5507,15 @@ static int count_proportional_objects(TransInfo *t) static void clear_trans_object_base_flags(TransInfo *t) { - Scene *sce = t->scene; + SceneLayer *sl = t->sl; Base *base; - for (base = sce->base.first; base; base = base->next) { - if (base->flag & BA_WAS_SEL) - base->flag |= SELECT; + for (base = sl->object_bases.first; base; base = base->next) { + if (base->flag_legacy & BA_WAS_SEL) { + base->flag |= BASE_SELECTED; + } - base->flag &= ~(BA_WAS_SEL | BA_HAS_RECALC_OB | BA_HAS_RECALC_DATA | BA_TEMP_TAG | BA_TRANSFORM_CHILD | BA_TRANSFORM_PARENT); + base->flag_legacy &= ~(BA_WAS_SEL | BA_HAS_RECALC_OB | BA_HAS_RECALC_DATA | BA_TEMP_TAG | BA_TRANSFORM_CHILD | BA_TRANSFORM_PARENT); } } @@ -6451,7 +6433,7 @@ static void createTransObject(bContext *C, TransInfo *t) if (is_prop_edit) { View3D *v3d = t->view; - Base *base; + BaseLegacy *base; for (base = scene->base.first; base; base = base->next) { Object *ob = base->object; @@ -7905,7 +7887,8 @@ static void createTransGPencil(bContext *C, TransInfo *t) void createTransData(bContext *C, TransInfo *t) { Scene *scene = t->scene; - Object *ob = OBACT; + SceneLayer *sl = t->sl; + Object *ob = OBACT_NEW; /* if tests must match recalcData for correct updates */ if (t->options & CTX_TEXTURE) { @@ -8065,10 +8048,9 @@ void createTransData(bContext *C, TransInfo *t) * lines below just check is also visible */ Object *ob_armature = modifiers_isDeformedByArmature(ob); if (ob_armature && ob_armature->mode & OB_MODE_POSE) { - Base *base_arm = BKE_scene_base_find(t->scene, ob_armature); + Base *base_arm = BKE_scene_layer_base_find(t->sl, ob_armature); if (base_arm) { - View3D *v3d = t->view; - if (BASE_VISIBLE(v3d, base_arm)) { + if (BASE_VISIBLE_NEW(base_arm)) { createTransPose(t, ob_armature); } } diff --git a/source/blender/editors/transform/transform_generics.c b/source/blender/editors/transform/transform_generics.c index f78a23be7b8..012342c16fc 100644 --- a/source/blender/editors/transform/transform_generics.c +++ b/source/blender/editors/transform/transform_generics.c @@ -62,8 +62,7 @@ #include "RNA_access.h" -#include "BIF_gl.h" -#include "BIF_glutil.h" +#include "GPU_immediate.h" #include "BIK_api.h" @@ -315,7 +314,7 @@ static bool fcu_test_selected(FCurve *fcu) /* helper for recalcData() - for Action Editor transforms */ static void recalcData_actedit(TransInfo *t) { - Scene *scene = t->scene; + SceneLayer *sl= t->sl; SpaceAction *saction = (SpaceAction *)t->sa->spacedata.first; bAnimContext ac = {NULL}; @@ -326,7 +325,7 @@ static void recalcData_actedit(TransInfo *t) /* initialize relevant anim-context 'context' data from TransInfo data */ /* NOTE: sync this with the code in ANIM_animdata_get_context() */ ac.scene = t->scene; - ac.obact = OBACT; + ac.obact = OBACT_NEW; ac.sa = t->sa; ac.ar = t->ar; ac.sl = (t->sa) ? t->sa->spacedata.first : NULL; @@ -363,7 +362,7 @@ static void recalcData_actedit(TransInfo *t) static void recalcData_graphedit(TransInfo *t) { SpaceIpo *sipo = (SpaceIpo *)t->sa->spacedata.first; - Scene *scene; + SceneLayer *sl = t->sl; ListBase anim_data = {NULL, NULL}; bAnimContext ac = {NULL}; @@ -374,8 +373,8 @@ static void recalcData_graphedit(TransInfo *t) /* initialize relevant anim-context 'context' data from TransInfo data */ /* NOTE: sync this with the code in ANIM_animdata_get_context() */ - scene = ac.scene = t->scene; - ac.obact = OBACT; + ac.scene = t->scene; + ac.obact = OBACT_NEW; ac.sa = t->sa; ac.ar = t->ar; ac.sl = (t->sa) ? t->sa->spacedata.first : NULL; @@ -709,7 +708,7 @@ static void recalcData_spaceclip(TransInfo *t) /* helper for recalcData() - for object transforms, typically in the 3D view */ static void recalcData_objects(TransInfo *t) { - Base *base = t->scene->basact; + BaseLegacy *base = t->scene->basact; if (t->obedit) { if (ELEM(t->obedit->type, OB_CURVE, OB_SURF)) { @@ -1050,14 +1049,19 @@ void drawLine(TransInfo *t, const float center[3], const float dir[3], char axis UI_GetThemeColor3ubv(TH_GRID, col); } UI_make_axis_color(col, col2, axis); - glColor3ubv(col2); - - setlinestyle(0); - glBegin(GL_LINES); - glVertex3fv(v1); - glVertex3fv(v2); - glEnd(); - + + unsigned pos = add_attrib(immVertexFormat(), "pos", GL_FLOAT, 3, KEEP_FLOAT); + + immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR); + immUniformColor3ubv(col2); + + immBegin(GL_LINES, 2); + immVertex3fv(pos, v1); + immVertex3fv(pos, v2); + immEnd(); + + immUnbindProgram(); + glPopMatrix(); } } @@ -1104,6 +1108,7 @@ static int initTransInfo_edit_pet_to_flag(const int proportional) void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *event) { Scene *sce = CTX_data_scene(C); + SceneLayer *sl = CTX_data_scene_layer(C); ToolSettings *ts = CTX_data_tool_settings(C); ARegion *ar = CTX_wm_region(C); ScrArea *sa = CTX_wm_area(C); @@ -1113,6 +1118,7 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve PropertyRNA *prop; t->scene = sce; + t->sl = sl; t->sa = sa; t->ar = ar; t->obedit = obedit; @@ -1767,8 +1773,8 @@ bool calculateCenterActive(TransInfo *t, bool select_only, float r_center[3]) } } else if (t->flag & T_POSE) { - Scene *scene = t->scene; - Object *ob = OBACT; + SceneLayer *sl = t->sl; + Object *ob = OBACT_NEW; if (ob) { bPoseChannel *pchan = BKE_pose_channel_active(ob); if (pchan && (!select_only || (pchan->bone->flag & BONE_SELECTED))) { @@ -1787,9 +1793,10 @@ bool calculateCenterActive(TransInfo *t, bool select_only, float r_center[3]) } else { /* object mode */ - Scene *scene = t->scene; - Object *ob = OBACT; - if (ob && (!select_only || (ob->flag & SELECT))) { + SceneLayer *sl = t->sl; + Object *ob = OBACT_NEW; + Base *base = BASACT_NEW; + if (ob && ((!select_only) || ((base->flag & BASE_SELECTED) != 0))) { copy_v3_v3(r_center, ob->obmat[3]); ok = true; } diff --git a/source/blender/editors/transform/transform_manipulator.c b/source/blender/editors/transform/transform_manipulator.c index e141724f2df..9072f963460 100644 --- a/source/blender/editors/transform/transform_manipulator.c +++ b/source/blender/editors/transform/transform_manipulator.c @@ -77,6 +77,8 @@ #include "transform.h" #include "GPU_select.h" +#include "GPU_immediate.h" +#include "GPU_matrix.h" /* return codes for select, and drawing flags */ @@ -271,11 +273,12 @@ static int calc_manipulator_stats(const bContext *C) ScrArea *sa = CTX_wm_area(C); ARegion *ar = CTX_wm_region(C); Scene *scene = CTX_data_scene(C); + SceneLayer *sl = CTX_data_scene_layer(C); Object *obedit = CTX_data_edit_object(C); View3D *v3d = sa->spacedata.first; RegionView3D *rv3d = ar->regiondata; Base *base; - Object *ob = OBACT; + Object *ob = OBACT_NEW; bGPdata *gpd = CTX_data_gpencil_data(C); const bool is_gp_edit = ((gpd) && (gpd->flag & GP_DATA_STROKE_EDITMODE)); int a, totsel = 0; @@ -587,11 +590,12 @@ static int calc_manipulator_stats(const bContext *C) else { /* we need the one selected object, if its not active */ - ob = OBACT; - if (ob && !(ob->flag & SELECT)) ob = NULL; + base = BASACT_NEW; + ob = OBACT_NEW; + if (base && ((base->flag & BASE_SELECTED) == 0)) ob = NULL; - for (base = scene->base.first; base; base = base->next) { - if (TESTBASELIB(v3d, base)) { + for (base = sl->object_bases.first; base; base = base->next) { + if (TESTBASELIB_NEW(base)) { if (ob == NULL) ob = base->object; calc_tw_center(scene, base->object->obmat[3]); @@ -704,10 +708,10 @@ static void test_manipulator_axis(const bContext *C) static float screen_aligned(RegionView3D *rv3d, float mat[4][4]) { - glTranslate3fv(mat[3]); + gpuTranslate3fv(mat[3]); /* sets view screen aligned */ - glRotatef(-360.0f * saacos(rv3d->viewquat[0]) / (float)M_PI, rv3d->viewquat[1], rv3d->viewquat[2], rv3d->viewquat[3]); + gpuRotate3f(-360.0f * saacos(rv3d->viewquat[0]) / (float)M_PI, rv3d->viewquat[1], rv3d->viewquat[2], rv3d->viewquat[3]); return len_v3(mat[0]); /* draw scale */ } @@ -720,7 +724,7 @@ static float screen_aligned(RegionView3D *rv3d, float mat[4][4]) * nsides = amount of points in ring * nrigns = amount of rings */ -static void partial_doughnut(float radring, float radhole, int start, int end, int nsides, int nrings) +static void partial_doughnut(unsigned int pos, float radring, float radhole, int start, int end, int nsides, int nrings) { float theta, phi, theta1; float cos_theta, sin_theta; @@ -743,7 +747,7 @@ static void partial_doughnut(float radring, float radhole, int start, int end, i sin_theta1 = sinf(theta1); if (do_caps && i == start) { // cap - glBegin(GL_POLYGON); + immBegin(GL_TRIANGLE_FAN, nsides+1); phi = 0.0; for (j = nsides; j >= 0; j--) { float cos_phi, sin_phi, dist; @@ -753,12 +757,12 @@ static void partial_doughnut(float radring, float radhole, int start, int end, i sin_phi = sinf(phi); dist = radhole + radring * cos_phi; - glVertex3f(cos_theta1 * dist, -sin_theta1 * dist, radring * sin_phi); + immVertex3f(pos, cos_theta1 * dist, -sin_theta1 * dist, radring * sin_phi); } - glEnd(); + immEnd(); } if (i >= start && i <= end) { - glBegin(GL_QUAD_STRIP); + immBegin(GL_TRIANGLE_STRIP, (nsides+1) * 2); phi = 0.0; for (j = nsides; j >= 0; j--) { float cos_phi, sin_phi, dist; @@ -768,14 +772,14 @@ static void partial_doughnut(float radring, float radhole, int start, int end, i sin_phi = sinf(phi); dist = radhole + radring * cos_phi; - glVertex3f(cos_theta1 * dist, -sin_theta1 * dist, radring * sin_phi); - glVertex3f(cos_theta * dist, -sin_theta * dist, radring * sin_phi); + immVertex3f(pos, cos_theta1 * dist, -sin_theta1 * dist, radring * sin_phi); + immVertex3f(pos, cos_theta * dist, -sin_theta * dist, radring * sin_phi); } - glEnd(); + immEnd(); } if (do_caps && i == end) { // cap - glBegin(GL_POLYGON); + immBegin(GL_TRIANGLE_FAN, nsides+1); phi = 0.0; for (j = nsides; j >= 0; j--) { float cos_phi, sin_phi, dist; @@ -785,9 +789,9 @@ static void partial_doughnut(float radring, float radhole, int start, int end, i sin_phi = sinf(phi); dist = radhole + radring * cos_phi; - glVertex3f(cos_theta * dist, -sin_theta * dist, radring * sin_phi); + immVertex3f(pos, cos_theta * dist, -sin_theta * dist, radring * sin_phi); } - glEnd(); + immEnd(); } @@ -856,7 +860,7 @@ static void manipulator_setcolor(View3D *v3d, char axis, int colcode, unsigned c } } - glColor4ubv(col); + immUniformColor4ubv(col); } static void manipulator_axis_order(RegionView3D *rv3d, int r_axis_order[3]) @@ -876,7 +880,7 @@ static void manipulator_axis_order(RegionView3D *rv3d, int r_axis_order[3]) /* viewmatrix should have been set OK, also no shademode! */ static void draw_manipulator_axes_single(View3D *v3d, RegionView3D *rv3d, int colcode, int flagx, int flagy, int flagz, int axis, - const bool is_picksel) + const bool is_picksel, unsigned int pos) { switch (axis) { case 0: @@ -889,10 +893,10 @@ static void draw_manipulator_axes_single(View3D *v3d, RegionView3D *rv3d, int co else { manipulator_setcolor(v3d, 'X', colcode, axisBlendAngle(rv3d->tw_idot[0])); } - glBegin(GL_LINES); - glVertex3f(0.2f, 0.0f, 0.0f); - glVertex3f(1.0f, 0.0f, 0.0f); - glEnd(); + immBegin(GL_LINES, 2); + immVertex3f(pos, 0.2f, 0.0f, 0.0f); + immVertex3f(pos, 1.0f, 0.0f, 0.0f); + immEnd(); } break; case 1: @@ -904,10 +908,10 @@ static void draw_manipulator_axes_single(View3D *v3d, RegionView3D *rv3d, int co else { manipulator_setcolor(v3d, 'Y', colcode, axisBlendAngle(rv3d->tw_idot[1])); } - glBegin(GL_LINES); - glVertex3f(0.0f, 0.2f, 0.0f); - glVertex3f(0.0f, 1.0f, 0.0f); - glEnd(); + immBegin(GL_LINES, 2); + immVertex3f(pos, 0.0f, 0.2f, 0.0f); + immVertex3f(pos, 0.0f, 1.0f, 0.0f); + immEnd(); } break; case 2: @@ -919,21 +923,21 @@ static void draw_manipulator_axes_single(View3D *v3d, RegionView3D *rv3d, int co else { manipulator_setcolor(v3d, 'Z', colcode, axisBlendAngle(rv3d->tw_idot[2])); } - glBegin(GL_LINES); - glVertex3f(0.0f, 0.0f, 0.2f); - glVertex3f(0.0f, 0.0f, 1.0f); - glEnd(); + immBegin(GL_LINES, 2); + immVertex3f(pos, 0.0f, 0.0f, 0.2f); + immVertex3f(pos, 0.0f, 0.0f, 1.0f); + immEnd(); } break; } } static void draw_manipulator_axes(View3D *v3d, RegionView3D *rv3d, int colcode, int flagx, int flagy, int flagz, - const int axis_order[3], const bool is_picksel) + const int axis_order[3], const bool is_picksel, unsigned int pos) { int i; for (i = 0; i < 3; i++) { - draw_manipulator_axes_single(v3d, rv3d, colcode, flagx, flagy, flagz, axis_order[i], is_picksel); + draw_manipulator_axes_single(v3d, rv3d, colcode, flagx, flagy, flagz, axis_order[i], is_picksel, pos); } } @@ -943,8 +947,8 @@ static void preOrthoFront(const bool ortho, float twmat[4][4], int axis) float omat[4][4]; copy_m4_m4(omat, twmat); orthogonalize_m4(omat, axis); - glPushMatrix(); - glMultMatrixf(omat); + gpuPushMatrix(); + gpuMultMatrix3D(omat); glFrontFace(is_negative_m4(omat) ? GL_CW : GL_CCW); } } @@ -952,7 +956,7 @@ static void preOrthoFront(const bool ortho, float twmat[4][4], int axis) static void postOrtho(const bool ortho) { if (ortho == false) { - glPopMatrix(); + gpuPopMatrix(); } } @@ -981,10 +985,18 @@ static void draw_manipulator_rotate( glDisable(GL_DEPTH_TEST); unit_m4(unitmat); + /* prepare for screen aligned draw */ size = len_v3(rv3d->twmat[0]); - glPushMatrix(); - glTranslate3fv(rv3d->twmat[3]); + gpuMatrixBegin3D_legacy(); + gpuPushMatrix(); + gpuTranslate3fv(rv3d->twmat[3]); + + + const unsigned pos = add_attrib(immVertexFormat(), "pos", GL_FLOAT, 3, KEEP_FLOAT); + + immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR); + if (arcs) { /* clipplane makes nice handles, calc here because of multmatrix but with translate! */ @@ -993,29 +1005,29 @@ static void draw_manipulator_rotate( glClipPlane(GL_CLIP_PLANE0, plane); } /* sets view screen aligned */ - glRotatef(-360.0f * saacos(rv3d->viewquat[0]) / (float)M_PI, rv3d->viewquat[1], rv3d->viewquat[2], rv3d->viewquat[3]); + gpuRotate3f(-360.0f * saacos(rv3d->viewquat[0]) / (float)M_PI, rv3d->viewquat[1], rv3d->viewquat[2], rv3d->viewquat[3]); /* Screen aligned help circle */ if (arcs) { if (is_picksel == false) { - UI_ThemeColorShade(TH_BACK, -30); - drawcircball(GL_LINE_LOOP, unitmat[3], size, unitmat); + immUniformThemeColorShade(TH_BACK, -30); + imm_drawcircball(unitmat[3], size, unitmat, pos); } } /* Screen aligned trackball rot circle */ if (drawflags & MAN_ROT_T) { if (is_picksel) GPU_select_load_id(MAN_ROT_T); - else UI_ThemeColor(TH_TRANSFORM); + else immUniformThemeColor(TH_TRANSFORM); - drawcircball(GL_LINE_LOOP, unitmat[3], 0.2f * size, unitmat); + imm_drawcircball(unitmat[3], 0.2f * size, unitmat, pos); } /* Screen aligned view rot circle */ if (drawflags & MAN_ROT_V) { if (is_picksel) GPU_select_load_id(MAN_ROT_V); - else UI_ThemeColor(TH_TRANSFORM); - drawcircball(GL_LINE_LOOP, unitmat[3], 1.2f * size, unitmat); + else immUniformThemeColor(TH_TRANSFORM); + imm_drawcircball(unitmat[3], 1.2f * size, unitmat, pos); if (is_moving) { float vec[3]; @@ -1023,14 +1035,15 @@ static void draw_manipulator_rotate( vec[1] = 0; // XXX (float)(t->mouse.imval[1] - t->center2d[1]); vec[2] = 0.0f; normalize_v3_length(vec, 1.2f * size); - glBegin(GL_LINES); - glVertex3f(0.0f, 0.0f, 0.0f); - glVertex3fv(vec); - glEnd(); + immBegin(GL_LINES, 2); + immVertex3f(pos, 0.0f, 0.0f, 0.0f); + immVertex3fv(pos,vec); + immEnd(); } } - glPopMatrix(); + gpuPopMatrix(); + gpuPushMatrix(); ortho = is_orthogonal_m4(rv3d->twmat); @@ -1039,14 +1052,14 @@ static void draw_manipulator_rotate( copy_m4_m4(matt, rv3d->twmat); // to copy the parts outside of [3][3] // XXX mul_m4_m3m4(matt, t->mat, rv3d->twmat); if (ortho) { - glMultMatrixf(matt); + gpuMultMatrix3D(matt); glFrontFace(is_negative_m4(matt) ? GL_CW : GL_CCW); } } else { if (ortho) { glFrontFace(is_negative_m4(rv3d->twmat) ? GL_CW : GL_CCW); - glMultMatrixf(rv3d->twmat); + gpuMultMatrix3D(rv3d->twmat); } } @@ -1058,28 +1071,28 @@ static void draw_manipulator_rotate( if ((drawflags & MAN_ROT_X) || (is_moving && (drawflags & MAN_ROT_Z))) { preOrthoFront(ortho, rv3d->twmat, 2); manipulator_setcolor(v3d, 'X', colcode, 255); - glBegin(GL_LINES); - glVertex3f(0.2f, 0.0f, 0.0f); - glVertex3f(1.0f, 0.0f, 0.0f); - glEnd(); + immBegin(GL_LINES, 2); + immVertex3f(pos, 0.2f, 0.0f, 0.0f); + immVertex3f(pos, 1.0f, 0.0f, 0.0f); + immEnd(); postOrtho(ortho); } if ((drawflags & MAN_ROT_Y) || (is_moving && (drawflags & MAN_ROT_X))) { preOrthoFront(ortho, rv3d->twmat, 0); manipulator_setcolor(v3d, 'Y', colcode, 255); - glBegin(GL_LINES); - glVertex3f(0.0f, 0.2f, 0.0f); - glVertex3f(0.0f, 1.0f, 0.0f); - glEnd(); + immBegin(GL_LINES, 2); + immVertex3f(pos, 0.0f, 0.2f, 0.0f); + immVertex3f(pos, 0.0f, 1.0f, 0.0f); + immEnd(); postOrtho(ortho); } if ((drawflags & MAN_ROT_Z) || (is_moving && (drawflags & MAN_ROT_Y))) { preOrthoFront(ortho, rv3d->twmat, 1); manipulator_setcolor(v3d, 'Z', colcode, 255); - glBegin(GL_LINES); - glVertex3f(0.0f, 0.0f, 0.2f); - glVertex3f(0.0f, 0.0f, 1.0f); - glEnd(); + immBegin(GL_LINES, 2); + immVertex3f(pos, 0.0f, 0.0f, 0.2f); + immVertex3f(pos, 0.0f, 0.0f, 1.0f); + immEnd(); postOrtho(ortho); } } @@ -1093,7 +1106,7 @@ static void draw_manipulator_rotate( preOrthoFront(ortho, matt, 2); if (is_picksel) GPU_select_load_id(MAN_ROT_Z); else manipulator_setcolor(v3d, 'Z', colcode, 255); - drawcircball(GL_LINE_LOOP, unitmat[3], 1.0, unitmat); + imm_drawcircball(unitmat[3], 1.0, unitmat, pos); postOrtho(ortho); } /* X circle */ @@ -1101,9 +1114,9 @@ static void draw_manipulator_rotate( preOrthoFront(ortho, matt, 0); if (is_picksel) GPU_select_load_id(MAN_ROT_X); else manipulator_setcolor(v3d, 'X', colcode, 255); - glRotatef(90.0, 0.0, 1.0, 0.0); - drawcircball(GL_LINE_LOOP, unitmat[3], 1.0, unitmat); - glRotatef(-90.0, 0.0, 1.0, 0.0); + gpuRotate3f(90.0, 0.0, 1.0, 0.0); + imm_drawcircball(unitmat[3], 1.0, unitmat, pos); + gpuRotate3f(-90.0, 0.0, 1.0, 0.0); postOrtho(ortho); } /* Y circle */ @@ -1111,9 +1124,9 @@ static void draw_manipulator_rotate( preOrthoFront(ortho, matt, 1); if (is_picksel) GPU_select_load_id(MAN_ROT_Y); else manipulator_setcolor(v3d, 'Y', colcode, 255); - glRotatef(-90.0, 1.0, 0.0, 0.0); - drawcircball(GL_LINE_LOOP, unitmat[3], 1.0, unitmat); - glRotatef(90.0, 1.0, 0.0, 0.0); + gpuRotate3f(-90.0, 1.0, 0.0, 0.0); + imm_drawcircball(unitmat[3], 1.0, unitmat, pos); + gpuRotate3f(90.0, 1.0, 0.0, 0.0); postOrtho(ortho); } } @@ -1126,7 +1139,7 @@ static void draw_manipulator_rotate( preOrthoFront(ortho, rv3d->twmat, 2); if (is_picksel) GPU_select_load_id(MAN_ROT_Z); else manipulator_setcolor(v3d, 'Z', colcode, 255); - partial_doughnut(cusize / 4.0f, 1.0f, 0, 48, 8, 48); + partial_doughnut(pos, cusize / 4.0f, 1.0f, 0, 48, 8, 48); postOrtho(ortho); } /* X circle */ @@ -1134,9 +1147,9 @@ static void draw_manipulator_rotate( preOrthoFront(ortho, rv3d->twmat, 0); if (is_picksel) GPU_select_load_id(MAN_ROT_X); else manipulator_setcolor(v3d, 'X', colcode, 255); - glRotatef(90.0, 0.0, 1.0, 0.0); - partial_doughnut(cusize / 4.0f, 1.0f, 0, 48, 8, 48); - glRotatef(-90.0, 0.0, 1.0, 0.0); + gpuRotate3f(90.0, 0.0, 1.0, 0.0); + partial_doughnut(pos, cusize / 4.0f, 1.0f, 0, 48, 8, 48); + gpuRotate3f(-90.0, 0.0, 1.0, 0.0); postOrtho(ortho); } /* Y circle */ @@ -1144,9 +1157,9 @@ static void draw_manipulator_rotate( preOrthoFront(ortho, rv3d->twmat, 1); if (is_picksel) GPU_select_load_id(MAN_ROT_Y); else manipulator_setcolor(v3d, 'Y', colcode, 255); - glRotatef(-90.0, 1.0, 0.0, 0.0); - partial_doughnut(cusize / 4.0f, 1.0f, 0, 48, 8, 48); - glRotatef(90.0, 1.0, 0.0, 0.0); + gpuRotate3f(-90.0, 1.0, 0.0, 0.0); + partial_doughnut(pos, cusize / 4.0f, 1.0f, 0, 48, 8, 48); + gpuRotate3f(90.0, 1.0, 0.0, 0.0); postOrtho(ortho); } @@ -1158,55 +1171,57 @@ static void draw_manipulator_rotate( /* Z handle on X axis */ if (drawflags & MAN_ROT_Z) { preOrthoFront(ortho, rv3d->twmat, 2); - glPushMatrix(); + gpuPushMatrix(); if (is_picksel) GPU_select_load_id(MAN_ROT_Z); else manipulator_setcolor(v3d, 'Z', colcode, 255); - partial_doughnut(0.7f * cusize, 1.0f, 31, 33, 8, 64); + partial_doughnut(pos, 0.7f * cusize, 1.0f, 31, 33, 8, 64); - glPopMatrix(); + gpuPopMatrix(); postOrtho(ortho); } /* Y handle on X axis */ if (drawflags & MAN_ROT_Y) { preOrthoFront(ortho, rv3d->twmat, 1); - glPushMatrix(); + gpuPushMatrix(); if (is_picksel) GPU_select_load_id(MAN_ROT_Y); else manipulator_setcolor(v3d, 'Y', colcode, 255); - glRotatef(90.0, 1.0, 0.0, 0.0); - glRotatef(90.0, 0.0, 0.0, 1.0); - partial_doughnut(0.7f * cusize, 1.0f, 31, 33, 8, 64); + gpuRotate3f(90.0, 1.0, 0.0, 0.0); + gpuRotate3f(90.0, 0.0, 0.0, 1.0); + partial_doughnut(pos, 0.7f * cusize, 1.0f, 31, 33, 8, 64); - glPopMatrix(); + gpuPopMatrix(); postOrtho(ortho); } /* X handle on Z axis */ if (drawflags & MAN_ROT_X) { preOrthoFront(ortho, rv3d->twmat, 0); - glPushMatrix(); + gpuPushMatrix(); if (is_picksel) GPU_select_load_id(MAN_ROT_X); else manipulator_setcolor(v3d, 'X', colcode, 255); - glRotatef(-90.0, 0.0, 1.0, 0.0); - glRotatef(90.0, 0.0, 0.0, 1.0); - partial_doughnut(0.7f * cusize, 1.0f, 31, 33, 8, 64); + gpuRotate3f(-90.0, 0.0, 1.0, 0.0); + gpuRotate3f(90.0, 0.0, 0.0, 1.0); + partial_doughnut(pos, 0.7f * cusize, 1.0f, 31, 33, 8, 64); - glPopMatrix(); + gpuPopMatrix(); postOrtho(ortho); } } /* restore */ - glLoadMatrixf(rv3d->viewmat); + gpuPopMatrix(); if (v3d->zbuf) glEnable(GL_DEPTH_TEST); + immUnbindProgram(); + gpuMatrixEnd(); } -static void drawsolidcube(float size) +static void drawsolidcube(unsigned int pos, float size) { const float cube[8][3] = { {-1.0, -1.0, -1.0}, @@ -1218,53 +1233,26 @@ static void drawsolidcube(float size) { 1.0, 1.0, 1.0}, { 1.0, 1.0, -1.0}, }; - float n[3] = {0.0f}; - - glPushMatrix(); - glScalef(size, size, size); - - glBegin(GL_QUADS); - n[0] = -1.0; - glNormal3fv(n); - glVertex3fv(cube[0]); glVertex3fv(cube[1]); glVertex3fv(cube[2]); glVertex3fv(cube[3]); - n[0] = 0; - glEnd(); - - glBegin(GL_QUADS); - n[1] = -1.0; - glNormal3fv(n); - glVertex3fv(cube[0]); glVertex3fv(cube[4]); glVertex3fv(cube[5]); glVertex3fv(cube[1]); - n[1] = 0; - glEnd(); - - glBegin(GL_QUADS); - n[0] = 1.0; - glNormal3fv(n); - glVertex3fv(cube[4]); glVertex3fv(cube[7]); glVertex3fv(cube[6]); glVertex3fv(cube[5]); - n[0] = 0; - glEnd(); - - glBegin(GL_QUADS); - n[1] = 1.0; - glNormal3fv(n); - glVertex3fv(cube[7]); glVertex3fv(cube[3]); glVertex3fv(cube[2]); glVertex3fv(cube[6]); - n[1] = 0; - glEnd(); - - glBegin(GL_QUADS); - n[2] = 1.0; - glNormal3fv(n); - glVertex3fv(cube[1]); glVertex3fv(cube[5]); glVertex3fv(cube[6]); glVertex3fv(cube[2]); - n[2] = 0; - glEnd(); - - glBegin(GL_QUADS); - n[2] = -1.0; - glNormal3fv(n); - glVertex3fv(cube[7]); glVertex3fv(cube[4]); glVertex3fv(cube[0]); glVertex3fv(cube[3]); - glEnd(); - - glPopMatrix(); + + gpuPushMatrix(); + gpuScaleUniform(size); + + immBegin(GL_TRIANGLES, 12 * 3); + immVertex3fv(pos, cube[0]); immVertex3fv(pos, cube[1]); immVertex3fv(pos, cube[2]); + immVertex3fv(pos, cube[0]); immVertex3fv(pos, cube[2]); immVertex3fv(pos, cube[3]); + immVertex3fv(pos, cube[0]); immVertex3fv(pos, cube[4]); immVertex3fv(pos, cube[5]); + immVertex3fv(pos, cube[0]); immVertex3fv(pos, cube[5]); immVertex3fv(pos, cube[1]); + immVertex3fv(pos, cube[4]); immVertex3fv(pos, cube[7]); immVertex3fv(pos, cube[6]); + immVertex3fv(pos, cube[4]); immVertex3fv(pos, cube[6]); immVertex3fv(pos, cube[5]); + immVertex3fv(pos, cube[7]); immVertex3fv(pos, cube[3]); immVertex3fv(pos, cube[2]); + immVertex3fv(pos, cube[7]); immVertex3fv(pos, cube[2]); immVertex3fv(pos, cube[6]); + immVertex3fv(pos, cube[1]); immVertex3fv(pos, cube[5]); immVertex3fv(pos, cube[6]); + immVertex3fv(pos, cube[1]); immVertex3fv(pos, cube[6]); immVertex3fv(pos, cube[2]); + immVertex3fv(pos, cube[7]); immVertex3fv(pos, cube[4]); immVertex3fv(pos, cube[0]); + immVertex3fv(pos, cube[7]); immVertex3fv(pos, cube[0]); immVertex3fv(pos, cube[3]); + immEnd(); + + gpuPopMatrix(); } @@ -1284,6 +1272,13 @@ static void draw_manipulator_scale( glDisable(GL_DEPTH_TEST); + const unsigned pos = add_attrib(immVertexFormat(), "pos", GL_FLOAT, 3, KEEP_FLOAT); + + immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR); + + gpuMatrixBegin3D_legacy(); + gpuPushMatrix(); + /* not in combo mode */ if ((combo & (V3D_MANIP_TRANSLATE | V3D_MANIP_ROTATE)) == 0) { float size, unitmat[4][4]; @@ -1293,11 +1288,11 @@ static void draw_manipulator_scale( if (is_picksel && shift == 0) GPU_select_load_id(MAN_SCALE_C); else manipulator_setcolor(v3d, 'C', colcode, 255); - glPushMatrix(); + gpuPushMatrix(); size = screen_aligned(rv3d, rv3d->twmat); unit_m4(unitmat); - drawcircball(GL_LINE_LOOP, unitmat[3], 0.2f * size, unitmat); - glPopMatrix(); + imm_drawcircball(unitmat[3], 0.2f * size, unitmat, pos); + gpuPopMatrix(); dz = 1.0; } @@ -1310,11 +1305,11 @@ static void draw_manipulator_scale( copy_m4_m4(matt, rv3d->twmat); // to copy the parts outside of [3][3] // XXX mul_m4_m3m4(matt, t->mat, rv3d->twmat); - glMultMatrixf(matt); + gpuMultMatrix3D(matt); glFrontFace(is_negative_m4(matt) ? GL_CW : GL_CCW); } else { - glMultMatrixf(rv3d->twmat); + gpuMultMatrix3D(rv3d->twmat); glFrontFace(is_negative_m4(rv3d->twmat) ? GL_CW : GL_CCW); } @@ -1323,36 +1318,36 @@ static void draw_manipulator_scale( /* in combo mode, this is always drawn as first type */ draw_manipulator_axes(v3d, rv3d, colcode, drawflags & MAN_SCALE_X, drawflags & MAN_SCALE_Y, drawflags & MAN_SCALE_Z, - axis_order, is_picksel); + axis_order, is_picksel, pos); for (i = 0; i < 3; i++) { switch (axis_order[i]) { case 0: /* X cube */ if (drawflags & MAN_SCALE_X) { - glTranslatef(dz, 0.0, 0.0); + gpuTranslate3f(dz, 0.0, 0.0); if (is_picksel) GPU_select_load_id(MAN_SCALE_X); else manipulator_setcolor(v3d, 'X', colcode, axisBlendAngle(rv3d->tw_idot[0])); - drawsolidcube(cusize); - glTranslatef(-dz, 0.0, 0.0); + drawsolidcube(pos, cusize); + gpuTranslate3f(-dz, 0.0, 0.0); } break; case 1: /* Y cube */ if (drawflags & MAN_SCALE_Y) { - glTranslatef(0.0, dz, 0.0); + gpuTranslate3f(0.0, dz, 0.0); if (is_picksel) GPU_select_load_id(MAN_SCALE_Y); else manipulator_setcolor(v3d, 'Y', colcode, axisBlendAngle(rv3d->tw_idot[1])); - drawsolidcube(cusize); - glTranslatef(0.0, -dz, 0.0); + drawsolidcube(pos, cusize); + gpuTranslate3f(0.0, -dz, 0.0); } break; case 2: /* Z cube */ if (drawflags & MAN_SCALE_Z) { - glTranslatef(0.0, 0.0, dz); + gpuTranslate3f(0.0, 0.0, dz); if (is_picksel) GPU_select_load_id(MAN_SCALE_Z); else manipulator_setcolor(v3d, 'Z', colcode, axisBlendAngle(rv3d->tw_idot[2])); - drawsolidcube(cusize); - glTranslatef(0.0, 0.0, -dz); + drawsolidcube(pos, cusize); + gpuTranslate3f(0.0, 0.0, -dz); } break; } @@ -1364,55 +1359,96 @@ static void draw_manipulator_scale( int shift = 0; // XXX if (shift) { - glTranslatef(0.0, -dz, 0.0); + gpuTranslate3f(0.0, -dz, 0.0); GPU_select_load_id(MAN_SCALE_C); /* TODO: set glPointSize before drawing center point */ - glBegin(GL_POINTS); - glVertex3f(0.0, 0.0, 0.0); - glEnd(); + immBegin(GL_POINTS, 1); + immVertex3f(0.0, 0.0, 0.0); + immEnd(); } } #endif /* restore */ - glLoadMatrixf(rv3d->viewmat); + gpuPopMatrix(); if (v3d->zbuf) glEnable(GL_DEPTH_TEST); glFrontFace(GL_CCW); -} + gpuMatrixEnd(); + immUnbindProgram(); +} -static void draw_cone(GLUquadricObj *qobj, float len, float width) +#define NSEGMENTS 8 +static void draw_cone(unsigned int pos, float len, float width) { - glTranslatef(0.0, 0.0, -0.5f * len); - gluCylinder(qobj, width, 0.0, len, 8, 1); - gluQuadricOrientation(qobj, GLU_INSIDE); - gluDisk(qobj, 0.0, width, 8, 1); - gluQuadricOrientation(qobj, GLU_OUTSIDE); - glTranslatef(0.0, 0.0, 0.5f * len); + /* a ring of vertices in the XY plane */ + float p[NSEGMENTS][2]; + for (int i = 0; i < NSEGMENTS; ++i) { + float angle = 2 * M_PI * ((float)i / (float)NSEGMENTS); + p[i][0] = width * cosf(angle); + p[i][1] = width * sinf(angle); + } + + float zbase = -0.5f * len; + float ztop = 0.5f * len; + + /* cone sides */ + immBegin(GL_TRIANGLE_FAN, NSEGMENTS + 2); + immVertex3f(pos, 0, 0, ztop); + for (int i = 0; i < NSEGMENTS; ++i) + immVertex3f(pos, p[i][0], p[i][1], zbase); + immVertex3f(pos, p[0][0], p[0][1], zbase); + immEnd(); + + /* end cap */ + immBegin(GL_TRIANGLE_FAN, NSEGMENTS); + for (int i = NSEGMENTS - 1; i >= 0; --i) + immVertex3f(pos, p[i][0], p[i][1], zbase); + immEnd(); } -static void draw_cylinder(GLUquadricObj *qobj, float len, float width) +static void draw_cylinder(unsigned int pos, float len, float width) { - width *= 0.8f; // just for beauty - glTranslatef(0.0, 0.0, -0.5f * len); - gluCylinder(qobj, width, width, len, 8, 1); - gluQuadricOrientation(qobj, GLU_INSIDE); - gluDisk(qobj, 0.0, width, 8, 1); - gluQuadricOrientation(qobj, GLU_OUTSIDE); - glTranslatef(0.0, 0.0, len); - gluDisk(qobj, 0.0, width, 8, 1); - glTranslatef(0.0, 0.0, -0.5f * len); -} + /* a ring of vertices in the XY plane */ + float p[NSEGMENTS][2]; + for (int i = 0; i < NSEGMENTS; ++i) { + float angle = 2 * M_PI * ((float)i / (float)NSEGMENTS); + p[i][0] = width * cosf(angle); + p[i][1] = width * sinf(angle); + } + + float zbase = -0.5f * len; + float ztop = 0.5f * len; + /* cylinder sides */ + immBegin(GL_TRIANGLE_STRIP, (NSEGMENTS + 1) * 2); + for (int i = 0; i < NSEGMENTS; ++i) { + immVertex3f(pos, p[i][0], p[i][1], zbase); + immVertex3f(pos, p[i][0], p[i][1], ztop); + } + immVertex3f(pos, p[0][0], p[0][1], zbase); + immVertex3f(pos, p[0][0], p[0][1], ztop); + immEnd(); + + /* end caps */ + immBegin(GL_TRIANGLE_FAN, NSEGMENTS); + for (int i = NSEGMENTS - 1; i >= 0; --i) + immVertex3f(pos, p[i][0], p[i][1], zbase); + immEnd(); + immBegin(GL_TRIANGLE_FAN, NSEGMENTS); + for (int i = 0; i < NSEGMENTS; ++i) + immVertex3f(pos, p[i][0], p[i][1], ztop); + immEnd(); +} +#undef NSEGMENTS static void draw_manipulator_translate( View3D *v3d, RegionView3D *rv3d, int drawflags, int combo, int colcode, const bool UNUSED(is_moving), const bool is_picksel) { - GLUquadricObj *qobj; float cylen = 0.01f * (float)U.tw_handlesize; float cywid = 0.25f * cylen, dz, size; float unitmat[4][4]; @@ -1425,21 +1461,28 @@ static void draw_manipulator_translate( manipulator_axis_order(rv3d, axis_order); - // XXX if (moving) glTranslate3fv(t->vec); + // XXX if (moving) gpuTranslate3fv(t->vec); glDisable(GL_DEPTH_TEST); + const unsigned pos = add_attrib(immVertexFormat(), "pos", GL_FLOAT, 3, KEEP_FLOAT); + + immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR); + + gpuMatrixBegin3D_legacy(); + gpuPushMatrix(); + /* center circle, do not add to selection when shift is pressed (planar constraint) */ if (is_picksel && shift == 0) GPU_select_load_id(MAN_TRANS_C); else manipulator_setcolor(v3d, 'C', colcode, 255); - glPushMatrix(); + gpuPushMatrix(); size = screen_aligned(rv3d, rv3d->twmat); unit_m4(unitmat); - drawcircball(GL_LINE_LOOP, unitmat[3], 0.2f * size, unitmat); - glPopMatrix(); + imm_drawcircball(unitmat[3], 0.2f * size, unitmat, pos); + gpuPopMatrix(); /* and now apply matrix, we move to local matrix drawing */ - glMultMatrixf(rv3d->twmat); + gpuMultMatrix3D(rv3d->twmat); /* axis */ GPU_select_load_id(-1); @@ -1448,66 +1491,63 @@ static void draw_manipulator_translate( if ((combo & V3D_MANIP_SCALE) == 0 || colcode == MAN_GHOST) { draw_manipulator_axes(v3d, rv3d, colcode, drawflags & MAN_TRANS_X, drawflags & MAN_TRANS_Y, drawflags & MAN_TRANS_Z, - axis_order, is_picksel); + axis_order, is_picksel, pos); } - /* offset in combo mode, for rotate a bit more */ if (combo & (V3D_MANIP_ROTATE)) dz = 1.0f + 2.0f * cylen; else if (combo & (V3D_MANIP_SCALE)) dz = 1.0f + 0.5f * cylen; else dz = 1.0f; - qobj = gluNewQuadric(); - gluQuadricDrawStyle(qobj, GLU_FILL); - for (i = 0; i < 3; i++) { switch (axis_order[i]) { case 0: /* Z Cone */ if (drawflags & MAN_TRANS_Z) { - glTranslatef(0.0, 0.0, dz); + gpuPushMatrix(); + gpuTranslate3f(0.0, 0.0, dz); if (is_picksel) GPU_select_load_id(MAN_TRANS_Z); else manipulator_setcolor(v3d, 'Z', colcode, axisBlendAngle(rv3d->tw_idot[2])); - draw_cone(qobj, cylen, cywid); - glTranslatef(0.0, 0.0, -dz); + draw_cone(pos, cylen, cywid); + gpuPopMatrix(); } break; case 1: /* X Cone */ if (drawflags & MAN_TRANS_X) { - glTranslatef(dz, 0.0, 0.0); + gpuPushMatrix(); + gpuTranslate3f(dz, 0.0, 0.0); if (is_picksel) GPU_select_load_id(MAN_TRANS_X); else manipulator_setcolor(v3d, 'X', colcode, axisBlendAngle(rv3d->tw_idot[0])); - glRotatef(90.0, 0.0, 1.0, 0.0); - draw_cone(qobj, cylen, cywid); - glRotatef(-90.0, 0.0, 1.0, 0.0); - glTranslatef(-dz, 0.0, 0.0); + gpuRotate3f(90.0, 0.0, 1.0, 0.0); + draw_cone(pos, cylen, cywid); + gpuPopMatrix(); } break; case 2: /* Y Cone */ if (drawflags & MAN_TRANS_Y) { - glTranslatef(0.0, dz, 0.0); + gpuPushMatrix(); + gpuTranslate3f(0.0, dz, 0.0); if (is_picksel) GPU_select_load_id(MAN_TRANS_Y); else manipulator_setcolor(v3d, 'Y', colcode, axisBlendAngle(rv3d->tw_idot[1])); - glRotatef(-90.0, 1.0, 0.0, 0.0); - draw_cone(qobj, cylen, cywid); - glRotatef(90.0, 1.0, 0.0, 0.0); - glTranslatef(0.0, -dz, 0.0); + gpuRotate3f(-90.0, 1.0, 0.0, 0.0); + draw_cone(pos, cylen, cywid); + gpuPopMatrix(); } break; } } - gluDeleteQuadric(qobj); - glLoadMatrixf(rv3d->viewmat); + gpuPopMatrix(); if (v3d->zbuf) glEnable(GL_DEPTH_TEST); + immUnbindProgram(); + gpuMatrixEnd(); } static void draw_manipulator_rotate_cyl( View3D *v3d, RegionView3D *rv3d, int drawflags, const int combo, const int colcode, const bool is_moving, const bool is_picksel) { - GLUquadricObj *qobj; float size; float cylen = 0.01f * (float)U.tw_handlesize; float cywid = 0.25f * cylen; @@ -1519,14 +1559,19 @@ static void draw_manipulator_rotate_cyl( manipulator_axis_order(rv3d, axis_order); + const unsigned pos = add_attrib(immVertexFormat(), "pos", GL_FLOAT, 3, KEEP_FLOAT); + + immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR); + + gpuMatrixBegin3D_legacy(); + gpuPushMatrix(); + /* prepare for screen aligned draw */ - glPushMatrix(); + gpuPushMatrix(); size = screen_aligned(rv3d, rv3d->twmat); glDisable(GL_DEPTH_TEST); - qobj = gluNewQuadric(); - /* Screen aligned view rot circle */ if (drawflags & MAN_ROT_V) { float unitmat[4][4]; @@ -1534,8 +1579,8 @@ static void draw_manipulator_rotate_cyl( unit_m4(unitmat); if (is_picksel) GPU_select_load_id(MAN_ROT_V); - UI_ThemeColor(TH_TRANSFORM); - drawcircball(GL_LINE_LOOP, unitmat[3], 1.2f * size, unitmat); + immUniformThemeColor(TH_TRANSFORM); + imm_drawcircball(unitmat[3], 1.2f * size, unitmat, pos); if (is_moving) { float vec[3]; @@ -1543,13 +1588,13 @@ static void draw_manipulator_rotate_cyl( vec[1] = 0; // XXX (float)(t->mouse.imval[1] - t->center2d[1]); vec[2] = 0.0f; normalize_v3_length(vec, 1.2f * size); - glBegin(GL_LINES); - glVertex3f(0.0, 0.0, 0.0); - glVertex3fv(vec); - glEnd(); + immBegin(GL_LINES, 2); + immVertex3f(pos, 0.0, 0.0, 0.0); + immVertex3fv(pos, vec); + immEnd(); } } - glPopMatrix(); + gpuPopMatrix(); /* apply the transform delta */ if (is_moving) { @@ -1558,10 +1603,10 @@ static void draw_manipulator_rotate_cyl( // XXX if (t->flag & T_USES_MANIPULATOR) { // XXX mul_m4_m3m4(matt, t->mat, rv3d->twmat); // XXX } - glMultMatrixf(matt); + gpuMultMatrix3D(matt); } else { - glMultMatrixf(rv3d->twmat); + gpuMultMatrix3D(rv3d->twmat); } glFrontFace(is_negative_m4(rv3d->twmat) ? GL_CW : GL_CCW); @@ -1573,56 +1618,54 @@ static void draw_manipulator_rotate_cyl( if ((combo & V3D_MANIP_SCALE) == 0) { draw_manipulator_axes(v3d, rv3d, colcode, drawflags & MAN_ROT_X, drawflags & MAN_ROT_Y, drawflags & MAN_ROT_Z, - axis_order, is_picksel); + axis_order, is_picksel, pos); } - - /* only has to be set when not in picking */ - gluQuadricDrawStyle(qobj, GLU_FILL); } for (i = 0; i < 3; i++) { switch (axis_order[i]) { case 0: /* X cylinder */ if (drawflags & MAN_ROT_X) { - glTranslatef(1.0, 0.0, 0.0); + gpuPushMatrix(); + gpuTranslate3f(1.0, 0.0, 0.0); if (is_picksel) GPU_select_load_id(MAN_ROT_X); - glRotatef(90.0, 0.0, 1.0, 0.0); + gpuRotate3f(90.0, 0.0, 1.0, 0.0); manipulator_setcolor(v3d, 'X', colcode, 255); - draw_cylinder(qobj, cylen, cywid); - glRotatef(-90.0, 0.0, 1.0, 0.0); - glTranslatef(-1.0, 0.0, 0.0); + draw_cylinder(pos, cylen, cywid); + gpuPopMatrix(); } break; case 1: /* Y cylinder */ if (drawflags & MAN_ROT_Y) { - glTranslatef(0.0, 1.0, 0.0); + gpuPushMatrix(); + gpuTranslate3f(0.0, 1.0, 0.0); if (is_picksel) GPU_select_load_id(MAN_ROT_Y); - glRotatef(-90.0, 1.0, 0.0, 0.0); + gpuRotate3f(-90.0, 1.0, 0.0, 0.0); manipulator_setcolor(v3d, 'Y', colcode, 255); - draw_cylinder(qobj, cylen, cywid); - glRotatef(90.0, 1.0, 0.0, 0.0); - glTranslatef(0.0, -1.0, 0.0); + draw_cylinder(pos, cylen, cywid); + gpuPopMatrix(); } break; case 2: /* Z cylinder */ if (drawflags & MAN_ROT_Z) { - glTranslatef(0.0, 0.0, 1.0); + gpuPushMatrix(); + gpuTranslate3f(0.0, 0.0, 1.0); if (is_picksel) GPU_select_load_id(MAN_ROT_Z); manipulator_setcolor(v3d, 'Z', colcode, 255); - draw_cylinder(qobj, cylen, cywid); - glTranslatef(0.0, 0.0, -1.0); + draw_cylinder(pos, cylen, cywid); + gpuPopMatrix(); } break; } } /* restore */ - - gluDeleteQuadric(qobj); - glLoadMatrixf(rv3d->viewmat); + gpuPopMatrix(); if (v3d->zbuf) glEnable(GL_DEPTH_TEST); + gpuMatrixEnd(); + immUnbindProgram(); } @@ -1636,6 +1679,7 @@ void BIF_draw_manipulator(const bContext *C) ScrArea *sa = CTX_wm_area(C); ARegion *ar = CTX_wm_region(C); Scene *scene = CTX_data_scene(C); + SceneLayer *sl = CTX_data_scene_layer(C); View3D *v3d = sa->spacedata.first; RegionView3D *rv3d = ar->regiondata; int totsel; @@ -1660,7 +1704,7 @@ void BIF_draw_manipulator(const bContext *C) case V3D_AROUND_ACTIVE: { bGPdata *gpd = CTX_data_gpencil_data(C); - Object *ob = OBACT; + Object *ob = OBACT_NEW; if (((v3d->around == V3D_AROUND_ACTIVE) && (scene->obedit == NULL)) && ((gpd == NULL) || !(gpd->flag & GP_DATA_STROKE_EDITMODE)) && diff --git a/source/blender/editors/transform/transform_orientations.c b/source/blender/editors/transform/transform_orientations.c index 058af768885..67f1dc6e44d 100644 --- a/source/blender/editors/transform/transform_orientations.c +++ b/source/blender/editors/transform/transform_orientations.c @@ -586,10 +586,10 @@ static unsigned int bm_mesh_faces_select_get_n(BMesh *bm, BMVert **elems, const int getTransformOrientation_ex(const bContext *C, float normal[3], float plane[3], const short around) { - Scene *scene = CTX_data_scene(C); + SceneLayer *sl = CTX_data_scene_layer(C); Object *obedit = CTX_data_edit_object(C); Base *base; - Object *ob = OBACT; + Object *ob = OBACT_NEW; int result = ORIENTATION_NONE; const bool activeOnly = (around == V3D_AROUND_ACTIVE); @@ -1016,16 +1016,16 @@ int getTransformOrientation_ex(const bContext *C, float normal[3], float plane[3 } else { /* we need the one selected object, if its not active */ - View3D *v3d = CTX_wm_view3d(C); - ob = OBACT; - if (ob && (ob->flag & SELECT)) { + base = BASACT_NEW; + ob = OBACT_NEW; + if (base && ((base->flag & BASE_SELECTED) != 0)) { /* pass */ } else { /* first selected */ ob = NULL; - for (base = scene->base.first; base; base = base->next) { - if (TESTBASELIB(v3d, base)) { + for (base = sl->object_bases.first; base; base = base->next) { + if (TESTBASELIB_NEW(base)) { ob = base->object; break; } diff --git a/source/blender/editors/transform/transform_snap.c b/source/blender/editors/transform/transform_snap.c index 318d2718969..bd640463da2 100644 --- a/source/blender/editors/transform/transform_snap.c +++ b/source/blender/editors/transform/transform_snap.c @@ -49,7 +49,7 @@ #include "BLI_blenlib.h" #include "BLI_utildefines.h" -#include "BIF_gl.h" +#include "GPU_immediate.h" #include "BKE_DerivedMesh.h" #include "BKE_global.h" @@ -163,36 +163,42 @@ void drawSnapping(const struct bContext *C, TransInfo *t) size = 2.5f * UI_GetThemeValuef(TH_VERTEX_SIZE); invert_m4_m4(imat, rv3d->viewmat); - + + unsigned pos = add_attrib(immVertexFormat(), "pos", GL_FLOAT, 3, KEEP_FLOAT); + + immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR); + for (p = t->tsnap.points.first; p; p = p->next) { if (p == t->tsnap.selectedPoint) { - glColor4ubv(selectedCol); + immUniformColor4ubv(selectedCol); } else { - glColor4ubv(col); + immUniformColor4ubv(col); } - drawcircball(GL_LINE_LOOP, p->co, ED_view3d_pixel_size(rv3d, p->co) * size * 0.75f, imat); + imm_drawcircball(p->co, ED_view3d_pixel_size(rv3d, p->co) * size * 0.75f, imat, pos); } if (t->tsnap.status & POINT_INIT) { - glColor4ubv(activeCol); + immUniformColor4ubv(activeCol); - drawcircball(GL_LINE_LOOP, t->tsnap.snapPoint, ED_view3d_pixel_size(rv3d, t->tsnap.snapPoint) * size, imat); + imm_drawcircball(t->tsnap.snapPoint, ED_view3d_pixel_size(rv3d, t->tsnap.snapPoint) * size, imat, pos); } /* draw normal if needed */ if (usingSnappingNormal(t) && validSnappingNormal(t)) { - glColor4ubv(activeCol); + immUniformColor4ubv(activeCol); - glBegin(GL_LINES); - glVertex3f(t->tsnap.snapPoint[0], t->tsnap.snapPoint[1], t->tsnap.snapPoint[2]); - glVertex3f(t->tsnap.snapPoint[0] + t->tsnap.snapNormal[0], - t->tsnap.snapPoint[1] + t->tsnap.snapNormal[1], - t->tsnap.snapPoint[2] + t->tsnap.snapNormal[2]); - glEnd(); + immBegin(GL_LINES, 2); + immVertex3f(pos, t->tsnap.snapPoint[0], t->tsnap.snapPoint[1], t->tsnap.snapPoint[2]); + immVertex3f(pos, t->tsnap.snapPoint[0] + t->tsnap.snapNormal[0], + t->tsnap.snapPoint[1] + t->tsnap.snapNormal[1], + t->tsnap.snapPoint[2] + t->tsnap.snapNormal[2]); + immEnd(); } - + + immUnbindProgram(); + if (v3d->zbuf) glEnable(GL_DEPTH_TEST); } @@ -241,23 +247,29 @@ void drawSnapping(const struct bContext *C, TransInfo *t) glEnable(GL_BLEND); + unsigned pos = add_attrib(immVertexFormat(), "pos", GL_FLOAT, 2, KEEP_FLOAT); + + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + for (p = t->tsnap.points.first; p; p = p->next) { if (p == t->tsnap.selectedPoint) { - glColor4ubv(selectedCol); + immUniformColor4ubv(selectedCol); } else { - glColor4ubv(col); + immUniformColor4ubv(col); } - ED_node_draw_snap(&ar->v2d, p->co, size, 0); + ED_node_draw_snap(&ar->v2d, p->co, size, 0, pos); } if (t->tsnap.status & POINT_INIT) { - glColor4ubv(activeCol); + immUniformColor4ubv(activeCol); - ED_node_draw_snap(&ar->v2d, t->tsnap.snapPoint, size, t->tsnap.snapNodeBorder); + ED_node_draw_snap(&ar->v2d, t->tsnap.snapPoint, size, t->tsnap.snapNodeBorder, pos); } - + + immUnbindProgram(); + glDisable(GL_BLEND); } } @@ -520,7 +532,7 @@ static void initSnappingMode(TransInfo *t) ToolSettings *ts = t->settings; Object *obedit = t->obedit; Scene *scene = t->scene; - Base *base_act = scene->basact; + BaseLegacy *base_act = scene->basact; if (t->spacetype == SPACE_NODE) { /* force project off when not supported */ diff --git a/source/blender/editors/transform/transform_snap_object.c b/source/blender/editors/transform/transform_snap_object.c index 53f6b37c22e..03e0b544657 100644 --- a/source/blender/editors/transform/transform_snap_object.c +++ b/source/blender/editors/transform/transform_snap_object.c @@ -1745,7 +1745,7 @@ static bool snapObjectsRay( * * To solve that problem, we do it first as an exception. * */ - Base *base_act = sctx->scene->basact; + BaseLegacy *base_act = sctx->scene->basact; if (base_act && base_act->object && base_act->object->mode & OB_MODE_PARTICLE_EDIT) { Object *ob = base_act->object; @@ -1766,11 +1766,11 @@ static bool snapObjectsRay( ignore_object_active = true; break; } - for (Base *base = sctx->scene->base.first; base != NULL; base = base->next) { + for (BaseLegacy *base = sctx->scene->base.first; base != NULL; base = base->next) { if ((BASE_VISIBLE_BGMODE(sctx->v3d_data.v3d, sctx->scene, base)) && - (base->flag & (BA_HAS_RECALC_OB | BA_HAS_RECALC_DATA)) == 0 && + (base->flag_legacy & (BA_HAS_RECALC_OB | BA_HAS_RECALC_DATA)) == 0 && - !((ignore_object_selected && (base->flag & (SELECT | BA_WAS_SEL))) || + !((ignore_object_selected && (base->flag_legacy & (SELECT | BA_WAS_SEL))) || (ignore_object_active && base == base_act))) { Object *ob = base->object; diff --git a/source/blender/editors/util/ed_util.c b/source/blender/editors/util/ed_util.c index 1f1a778cac7..482523e56be 100644 --- a/source/blender/editors/util/ed_util.c +++ b/source/blender/editors/util/ed_util.c @@ -70,6 +70,8 @@ #include "ED_space_api.h" #include "ED_util.h" +#include "GPU_immediate.h" + #include "UI_interface.h" #include "UI_resources.h" @@ -312,15 +314,23 @@ void ED_region_draw_mouse_line_cb(const bContext *C, ARegion *ar, void *arg_info { wmWindow *win = CTX_wm_window(C); const float *mval_src = (float *)arg_info; - const int mval_dst[2] = {win->eventstate->x - ar->winrct.xmin, - win->eventstate->y - ar->winrct.ymin}; + const float mval_dst[2] = {win->eventstate->x - ar->winrct.xmin, + win->eventstate->y - ar->winrct.ymin}; - UI_ThemeColor(TH_VIEW_OVERLAY); setlinestyle(3); - glBegin(GL_LINES); - glVertex2iv(mval_dst); - glVertex2fv(mval_src); - glEnd(); + + VertexFormat *format = immVertexFormat(); + unsigned pos = add_attrib(format, "pos", GL_FLOAT, 2, KEEP_FLOAT); + + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + immUniformThemeColor(TH_VIEW_OVERLAY); + + immBegin(GL_LINES, 2); + immVertex2fv(pos, mval_dst); + immVertex2fv(pos, mval_src); + immEnd(); + immUnbindProgram(); + setlinestyle(0); } diff --git a/source/blender/editors/uvedit/uvedit_draw.c b/source/blender/editors/uvedit/uvedit_draw.c index 5c5e84ee5f0..32e7bb44375 100644 --- a/source/blender/editors/uvedit/uvedit_draw.c +++ b/source/blender/editors/uvedit/uvedit_draw.c @@ -55,6 +55,8 @@ #include "BIF_gl.h" #include "BIF_glutil.h" +#include "GPU_immediate.h" + #include "ED_image.h" #include "ED_mesh.h" #include "ED_uvedit.h" @@ -70,7 +72,7 @@ /* use editmesh tessface */ #define USE_EDBM_LOOPTRIS -static void draw_uvs_lineloop_bmface(BMFace *efa, const int cd_loop_uv_offset); +static void draw_uvs_lineloop_bmface(BMFace *efa, const int cd_loop_uv_offset, unsigned int pos); void ED_image_draw_cursor(ARegion *ar, const float cursor[2]) { @@ -81,35 +83,67 @@ void ED_image_draw_cursor(ARegion *ar, const float cursor[2]) mul_v2_fl(zoom, 256.0f * UI_DPI_FAC); x_fac = zoom[0]; y_fac = zoom[1]; - - cpack(0xFFFFFF); + glTranslate2fv(cursor); - fdrawline(-0.05f * x_fac, 0, 0, 0.05f * y_fac); - fdrawline(0, 0.05f * y_fac, 0.05f * x_fac, 0.0f); - fdrawline(0.05f * x_fac, 0.0f, 0.0f, -0.05f * y_fac); - fdrawline(0.0f, -0.05f * y_fac, -0.05f * x_fac, 0.0f); - setlinestyle(4); - cpack(0xFF); - fdrawline(-0.05f * x_fac, 0.0f, 0.0f, 0.05f * y_fac); - fdrawline(0.0f, 0.05f * y_fac, 0.05f * x_fac, 0.0f); - fdrawline(0.05f * x_fac, 0.0f, 0.0f, -0.05f * y_fac); - fdrawline(0.0f, -0.05f * y_fac, -0.05f * x_fac, 0.0f); + unsigned int pos = add_attrib(immVertexFormat(), "pos", GL_FLOAT, 2, KEEP_FLOAT); + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); - setlinestyle(0.0f); - cpack(0x0); - fdrawline(-0.020f * x_fac, 0.0f, -0.1f * x_fac, 0.0f); - fdrawline(0.1f * x_fac, 0.0f, 0.020f * x_fac, 0.0f); - fdrawline(0.0f, -0.020f * y_fac, 0.0f, -0.1f * y_fac); - fdrawline(0.0f, 0.1f * y_fac, 0.0f, 0.020f * y_fac); + imm_cpack(0xFFFFFF); + + immBegin(GL_LINE_LOOP, 4); + immVertex2f(pos, -0.05f * x_fac, 0.0f); + immVertex2f(pos, 0.0f, 0.05f * y_fac); + immVertex2f(pos, 0.05f * x_fac, 0.0f); + immVertex2f(pos, 0.0f, -0.05f * y_fac); + immEnd(); + + setlinestyle(4); + imm_cpack(0xFF); + + /* drawing individual segments, because the stipple pattern + * gets messed up when drawing a continuous loop */ + immBegin(GL_LINES, 8); + immVertex2f(pos, -0.05f * x_fac, 0.0f); + immVertex2f(pos, 0.0f, 0.05f * y_fac); + immVertex2f(pos, 0.0f, 0.05f * y_fac); + immVertex2f(pos, 0.05f * x_fac, 0.0f); + immVertex2f(pos, 0.05f * x_fac, 0.0f); + immVertex2f(pos, 0.0f, -0.05f * y_fac); + immVertex2f(pos, 0.0f, -0.05f * y_fac); + immVertex2f(pos, -0.05f * x_fac, 0.0f); + immEnd(); + + setlinestyle(0); + imm_cpack(0x0); + + immBegin(GL_LINES, 8); + immVertex2f(pos, -0.020f * x_fac, 0.0f); + immVertex2f(pos, -0.1f * x_fac, 0.0f); + immVertex2f(pos, 0.1f * x_fac, 0.0f); + immVertex2f(pos, 0.020f * x_fac, 0.0f); + immVertex2f(pos, 0.0f, -0.020f * y_fac); + immVertex2f(pos, 0.0f, -0.1f * y_fac); + immVertex2f(pos, 0.0f, 0.1f * y_fac); + immVertex2f(pos, 0.0f, 0.020f * y_fac); + immEnd(); setlinestyle(1); - cpack(0xFFFFFF); - fdrawline(-0.020f * x_fac, 0.0f, -0.1f * x_fac, 0.0f); - fdrawline(0.1f * x_fac, 0.0f, 0.020f * x_fac, 0.0f); - fdrawline(0.0f, -0.020f * y_fac, 0.0f, -0.1f * y_fac); - fdrawline(0.0f, 0.1f * y_fac, 0.0f, 0.020f * y_fac); + imm_cpack(0xFFFFFF); + + immBegin(GL_LINES, 8); + immVertex2f(pos, -0.020f * x_fac, 0.0f); + immVertex2f(pos, -0.1f * x_fac, 0.0f); + immVertex2f(pos, 0.1f * x_fac, 0.0f); + immVertex2f(pos, 0.020f * x_fac, 0.0f); + immVertex2f(pos, 0.0f, -0.020f * y_fac); + immVertex2f(pos, 0.0f, -0.1f * y_fac); + immVertex2f(pos, 0.0f, 0.1f * y_fac); + immVertex2f(pos, 0.0f, 0.020f * y_fac); + immEnd(); + + immUnbindProgram(); glTranslatef(-cursor[0], -cursor[1], 0.0); setlinestyle(0); @@ -141,12 +175,18 @@ static void draw_uvs_shadow(Object *obedit) const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV); + unsigned int pos = add_attrib(immVertexFormat(), "pos", GL_FLOAT, 2, KEEP_FLOAT); + + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + /* draws the mesh when painting */ - UI_ThemeColor(TH_UV_SHADOW); + immUniformThemeColor(TH_UV_SHADOW); BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) { - draw_uvs_lineloop_bmface(efa, cd_loop_uv_offset); + draw_uvs_lineloop_bmface(efa, cd_loop_uv_offset, pos); } + + immUnbindProgram(); } static int draw_uvs_dm_shadow(DerivedMesh *dm) @@ -212,19 +252,27 @@ static void draw_uvs_stretch(SpaceImage *sima, Scene *scene, BMEditMesh *em, MTe BM_elem_flag_disable(efa, BM_ELEM_TAG); } } - + + unsigned int pos = add_attrib(immVertexFormat(), "pos", GL_FLOAT, 2, KEEP_FLOAT); + + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + if (totarea < FLT_EPSILON || totuvarea < FLT_EPSILON) { col[0] = 1.0; col[1] = col[2] = 0.0; - glColor3fv(col); + + immUniformColor3fv(col); + BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) { if (BM_elem_flag_test(efa, BM_ELEM_TAG)) { - glBegin(GL_POLYGON); + immBegin(GL_TRIANGLE_FAN, efa->len); + BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); - glVertex2fv(luv->uv); + immVertex2fv(pos, luv->uv); } - glEnd(); + + immEnd(); } } } @@ -254,18 +302,23 @@ static void draw_uvs_stretch(SpaceImage *sima, Scene *scene, BMEditMesh *em, MTe areadiff = 1.0f - (area / uvarea); weight_to_rgb(col, areadiff); - glColor3fv(col); + immUniformColor3fv(col); /* TODO: USE_EDBM_LOOPTRIS */ - glBegin(GL_POLYGON); + immBegin(GL_TRIANGLE_FAN, efa->len); + BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); - glVertex2fv(luv->uv); + immVertex2fv(pos, luv->uv); } - glEnd(); + + immEnd(); } } } + + immUnbindProgram(); + break; } case SI_UVDT_STRETCH_ANGLE: @@ -278,7 +331,13 @@ static void draw_uvs_stretch(SpaceImage *sima, Scene *scene, BMEditMesh *em, MTe BLI_buffer_declare_static(vec2f, auv_buf, BLI_BUFFER_NOP, BM_DEFAULT_NGON_STACK_SIZE); col[3] = 0.5f; /* hard coded alpha, not that nice */ - + + VertexFormat *format = immVertexFormat(); + unsigned int pos = add_attrib(format, "pos", GL_FLOAT, 2, KEEP_FLOAT); + unsigned int color = add_attrib(format, "color", GL_FLOAT, 3, KEEP_FLOAT); + + immBindBuiltinProgram(GPU_SHADER_2D_SMOOTH_COLOR); + BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) { tf = BM_ELEM_CD_GET_VOID_P(efa, cd_poly_tex_offset); @@ -320,15 +379,15 @@ static void draw_uvs_stretch(SpaceImage *sima, Scene *scene, BMEditMesh *em, MTe } /* TODO: USE_EDBM_LOOPTRIS */ - glBegin(GL_POLYGON); + immBegin(GL_TRIANGLE_FAN, efa->len); BM_ITER_ELEM_INDEX (l, &liter, efa, BM_LOOPS_OF_FACE, i) { luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); a = fabsf(uvang[i] - ang[i]) / (float)M_PI; weight_to_rgb(col, 1.0f - pow2f(1.0f - a)); - glColor3fv(col); - glVertex2fv(luv->uv); + immAttrib3fv(color, col); + immVertex2fv(pos, luv->uv); } - glEnd(); + immEnd(); } else { if (tf == activetf) @@ -337,6 +396,8 @@ static void draw_uvs_stretch(SpaceImage *sima, Scene *scene, BMEditMesh *em, MTe } } + immUnbindProgram(); + BLI_buffer_free(&uvang_buf); BLI_buffer_free(&ang_buf); BLI_buffer_free(&av_buf); @@ -350,34 +411,38 @@ static void draw_uvs_stretch(SpaceImage *sima, Scene *scene, BMEditMesh *em, MTe BLI_buffer_free(&tf_uvorig_buf); } -static void draw_uvs_lineloop_bmface(BMFace *efa, const int cd_loop_uv_offset) +static void draw_uvs_lineloop_bmface(BMFace *efa, const int cd_loop_uv_offset, unsigned int pos) { BMIter liter; BMLoop *l; MLoopUV *luv; - glBegin(GL_LINE_LOOP); + immBegin(GL_LINE_LOOP, efa->len); + BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); - glVertex2fv(luv->uv); + immVertex2fv(pos, luv->uv); } - glEnd(); + + immEnd(); } -static void draw_uvs_lineloop_mpoly(Mesh *me, MPoly *mpoly) +static void draw_uvs_lineloop_mpoly(Mesh *me, MPoly *mpoly, unsigned int pos) { MLoopUV *mloopuv; int i; - glBegin(GL_LINE_LOOP); + immBegin(GL_LINE_LOOP, mpoly->totloop); + mloopuv = &me->mloopuv[mpoly->loopstart]; for (i = mpoly->totloop; i != 0; i--, mloopuv++) { - glVertex2fv(mloopuv->uv); + immVertex2fv(pos, mloopuv->uv); } - glEnd(); + + immEnd(); } -static void draw_uvs_other_mesh_texface(Object *ob, const Image *curimage, const int other_uv_filter) +static void draw_uvs_other_mesh_texface(Object *ob, const Image *curimage, const int other_uv_filter, unsigned int pos) { Mesh *me = ob->data; MPoly *mpoly = me->mpoly; @@ -398,10 +463,10 @@ static void draw_uvs_other_mesh_texface(Object *ob, const Image *curimage, const } } - draw_uvs_lineloop_mpoly(me, mpoly); + draw_uvs_lineloop_mpoly(me, mpoly, pos); } } -static void draw_uvs_other_mesh_new_shading(Object *ob, const Image *curimage, const int other_uv_filter) +static void draw_uvs_other_mesh_new_shading(Object *ob, const Image *curimage, const int other_uv_filter, unsigned int pos) { Mesh *me = ob->data; MPoly *mpoly = me->mpoly; @@ -453,41 +518,43 @@ static void draw_uvs_other_mesh_new_shading(Object *ob, const Image *curimage, c } } - draw_uvs_lineloop_mpoly(me, mpoly); + draw_uvs_lineloop_mpoly(me, mpoly, pos); } } static void draw_uvs_other_mesh(Object *ob, const Image *curimage, const bool new_shading_nodes, - const int other_uv_filter) + const int other_uv_filter, unsigned int pos) { if (new_shading_nodes) { - draw_uvs_other_mesh_new_shading(ob, curimage, other_uv_filter); + draw_uvs_other_mesh_new_shading(ob, curimage, other_uv_filter, pos); } else { - draw_uvs_other_mesh_texface(ob, curimage, other_uv_filter); + draw_uvs_other_mesh_texface(ob, curimage, other_uv_filter, pos); } } -static void draw_uvs_other(Scene *scene, Object *obedit, const Image *curimage, const bool new_shading_nodes, +static void draw_uvs_other(SceneLayer *sl, Object *obedit, const Image *curimage, const bool new_shading_nodes, const int other_uv_filter) { - Base *base; + unsigned int pos = add_attrib(immVertexFormat(), "pos", GL_FLOAT, 2, KEEP_FLOAT); - UI_ThemeColor(TH_UV_OTHERS); + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); - for (base = scene->base.first; base; base = base->next) { - Object *ob = base->object; + immUniformThemeColor(TH_UV_OTHERS); - if (!(base->flag & SELECT)) continue; - if (!(base->lay & scene->lay)) continue; - if (ob->restrictflag & OB_RESTRICT_VIEW) continue; - - if ((ob->type == OB_MESH) && (ob != obedit) && ((Mesh *)ob->data)->mloopuv) { - draw_uvs_other_mesh(ob, curimage, new_shading_nodes, other_uv_filter); + for (Base *base = sl->object_bases.first; base; base = base->next) { + if (((base->flag & BASE_SELECTED) != 0) && + ((base->flag & BASE_VISIBLED) != 0)) + { + Object *ob = base->object; + if ((ob->type == OB_MESH) && (ob != obedit) && ((Mesh *)ob->data)->mloopuv) { + draw_uvs_other_mesh(ob, curimage, new_shading_nodes, other_uv_filter, pos); + } } } + immUnbindProgram(); } -static void draw_uvs_texpaint(SpaceImage *sima, Scene *scene, Object *ob) +static void draw_uvs_texpaint(SpaceImage *sima, Scene *scene, SceneLayer *sl, Object *ob) { const bool new_shading_nodes = BKE_scene_use_new_shading_nodes(scene); Image *curimage = ED_space_image(sima); @@ -495,11 +562,9 @@ static void draw_uvs_texpaint(SpaceImage *sima, Scene *scene, Object *ob) Material *ma; if (sima->flag & SI_DRAW_OTHER) { - draw_uvs_other(scene, ob, curimage, new_shading_nodes, sima->other_uv_filter); + draw_uvs_other(sl, ob, curimage, new_shading_nodes, sima->other_uv_filter); } - UI_ThemeColor(TH_UV_SHADOW); - ma = give_current_material(ob, ob->actcol); if (me->mtpoly) { @@ -512,24 +577,34 @@ static void draw_uvs_texpaint(SpaceImage *sima, Scene *scene, Object *ob) mloopuv = me->mloopuv; } + unsigned int pos = add_attrib(immVertexFormat(), "pos", GL_FLOAT, 2, KEEP_FLOAT); + + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + + immUniformThemeColor(TH_UV_SHADOW); + mloopuv_base = mloopuv; for (a = me->totpoly; a > 0; a--, mpoly++) { if ((scene->toolsettings->uv_flag & UV_SHOW_SAME_IMAGE) && mpoly->mat_nr != ob->actcol - 1) continue; - glBegin(GL_LINE_LOOP); + + immBegin(GL_LINE_LOOP, mpoly->totloop); mloopuv = mloopuv_base + mpoly->loopstart; for (b = 0; b < mpoly->totloop; b++, mloopuv++) { - glVertex2fv(mloopuv->uv); + immVertex2fv(pos, mloopuv->uv); } - glEnd(); + + immEnd(); } + + immUnbindProgram(); } } #ifdef USE_EDBM_LOOPTRIS -static void draw_uvs_looptri(BMEditMesh *em, unsigned int *r_loop_index, const int cd_loop_uv_offset) +static void draw_uvs_looptri(BMEditMesh *em, unsigned int *r_loop_index, const int cd_loop_uv_offset, unsigned int pos) { unsigned int i = *r_loop_index; BMFace *f = em->looptris[i][0]->f; @@ -537,7 +612,7 @@ static void draw_uvs_looptri(BMEditMesh *em, unsigned int *r_loop_index, const i unsigned int j; for (j = 0; j < 3; j++) { MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(em->looptris[i][j], cd_loop_uv_offset); - glVertex2fv(luv->uv); + immVertex2fv(pos, luv->uv); } i++; } while (i != em->tottri && (f == em->looptris[i][0]->f)); @@ -546,7 +621,7 @@ static void draw_uvs_looptri(BMEditMesh *em, unsigned int *r_loop_index, const i #endif /* draws uv's in the image space */ -static void draw_uvs(SpaceImage *sima, Scene *scene, Object *obedit) +static void draw_uvs(SpaceImage *sima, Scene *scene, SceneLayer *sl, Object *obedit) { const bool new_shading_nodes = BKE_scene_use_new_shading_nodes(scene); ToolSettings *ts; @@ -570,6 +645,8 @@ static void draw_uvs(SpaceImage *sima, Scene *scene, Object *obedit) const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV); const int cd_poly_tex_offset = CustomData_get_offset(&bm->pdata, CD_MTEXPOLY); + unsigned int pos; + activetf = EDBM_mtexpoly_active_get(em, &efa_act, false, false); /* will be set to NULL if hidden */ #ifndef USE_EDBM_LOOPTRIS activef = BM_mesh_active_face_get(bm, false, false); @@ -598,7 +675,7 @@ static void draw_uvs(SpaceImage *sima, Scene *scene, Object *obedit) curimage = (activetf) ? activetf->tpage : ima; } - draw_uvs_other(scene, obedit, curimage, new_shading_nodes, sima->other_uv_filter); + draw_uvs_other(sl, obedit, curimage, new_shading_nodes, sima->other_uv_filter); } /* 1. draw shadow mesh */ @@ -622,7 +699,7 @@ static void draw_uvs(SpaceImage *sima, Scene *scene, Object *obedit) finaldm->release(finaldm); } } - + /* 2. draw colored faces */ if (sima->flag & SI_DRAW_STRETCH) { @@ -638,6 +715,11 @@ static void draw_uvs(SpaceImage *sima, Scene *scene, Object *obedit) #ifdef USE_EDBM_LOOPTRIS { unsigned int i; + + pos = add_attrib(immVertexFormat(), "pos", GL_FLOAT, 2, KEEP_FLOAT); + + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + for (i = 0; i < em->tottri; i++) { efa = em->looptris[i][0]->f; tf = BM_ELEM_CD_GET_VOID_P(efa, cd_poly_tex_offset); @@ -647,26 +729,22 @@ static void draw_uvs(SpaceImage *sima, Scene *scene, Object *obedit) if (tf == activetf) { /* only once */ - GPU_basic_shader_bind(GPU_SHADER_STIPPLE | GPU_SHADER_USE_COLOR); - GPU_basic_shader_stipple(GPU_SHADER_STIPPLE_QUARTTONE); - UI_ThemeColor4(TH_EDITMESH_ACTIVE); + immUniformThemeColor(TH_EDITMESH_ACTIVE); } else { - glColor4ubv((GLubyte *)(is_select ? col2 : col1)); + immUniformColor4ubv(is_select ? col2 : col1); } - glBegin(GL_TRIANGLES); - draw_uvs_looptri(em, &i, cd_loop_uv_offset); - glEnd(); - - if (tf == activetf) { - GPU_basic_shader_bind(GPU_SHADER_USE_COLOR); - } + immBegin(GL_TRIANGLES, (em->looptris[i][0]->f->len - 2) * 3); + draw_uvs_looptri(em, &i, cd_loop_uv_offset, pos); + immEnd(); } else { BM_elem_flag_disable(efa, BM_ELEM_TAG); } } + + immUnbindProgram(); } #else BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) { @@ -751,104 +829,152 @@ static void draw_uvs(SpaceImage *sima, Scene *scene, Object *obedit) switch (sima->dt_uv) { case SI_UVDT_DASH: + pos = add_attrib(immVertexFormat(), "pos", GL_FLOAT, 2, KEEP_FLOAT); + + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) { if (!BM_elem_flag_test(efa, BM_ELEM_TAG)) continue; tf = BM_ELEM_CD_GET_VOID_P(efa, cd_poly_tex_offset); if (tf) { - cpack(0x111111); + imm_cpack(0x111111); - draw_uvs_lineloop_bmface(efa, cd_loop_uv_offset); + draw_uvs_lineloop_bmface(efa, cd_loop_uv_offset, pos); setlinestyle(2); - cpack(0x909090); + imm_cpack(0x909090); - draw_uvs_lineloop_bmface(efa, cd_loop_uv_offset); + draw_uvs_lineloop_bmface(efa, cd_loop_uv_offset, pos); setlinestyle(0); } } + + immUnbindProgram(); + break; case SI_UVDT_BLACK: /* black/white */ - case SI_UVDT_WHITE: - if (sima->dt_uv == SI_UVDT_WHITE) glColor3f(1.0f, 1.0f, 1.0f); - else glColor3f(0.0f, 0.0f, 0.0f); + case SI_UVDT_WHITE: + pos = add_attrib(immVertexFormat(), "pos", GL_FLOAT, 2, KEEP_FLOAT); + + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + + if (sima->dt_uv == SI_UVDT_WHITE) { + immUniformColor3f(1.0f, 1.0f, 1.0f); + } + else { + immUniformColor3f(0.0f, 0.0f, 0.0f); + } BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) { if (!BM_elem_flag_test(efa, BM_ELEM_TAG)) continue; - draw_uvs_lineloop_bmface(efa, cd_loop_uv_offset); + draw_uvs_lineloop_bmface(efa, cd_loop_uv_offset, pos); } + + immUnbindProgram(); + break; case SI_UVDT_OUTLINE: + pos = add_attrib(immVertexFormat(), "pos", GL_FLOAT, 2, KEEP_FLOAT); + + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + glLineWidth(3); - cpack(0x0); - + imm_cpack(0x0); + BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) { if (!BM_elem_flag_test(efa, BM_ELEM_TAG)) continue; - draw_uvs_lineloop_bmface(efa, cd_loop_uv_offset); + draw_uvs_lineloop_bmface(efa, cd_loop_uv_offset, pos); } - + + immUnbindProgram(); + glLineWidth(1); UI_GetThemeColor4ubv(TH_WIRE_EDIT, col2); - glColor4ubv((unsigned char *)col2); if (me->drawflag & ME_DRAWEDGES) { - int sel, lastsel = -1; + int sel; UI_GetThemeColor4ubv(TH_EDGE_SELECT, col1); + VertexFormat *format = immVertexFormat(); + pos = add_attrib(format, "pos", GL_FLOAT, 2, KEEP_FLOAT); + unsigned int color = add_attrib(format, "color", GL_UNSIGNED_BYTE, 4, NORMALIZE_INT_TO_FLOAT); + if (interpedges) { - GPU_basic_shader_bind(GPU_SHADER_USE_COLOR); + immBindBuiltinProgram(GPU_SHADER_2D_SMOOTH_COLOR); + BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) { if (!BM_elem_flag_test(efa, BM_ELEM_TAG)) continue; - glBegin(GL_LINE_LOOP); + immBegin(GL_LINE_LOOP, efa->len); + BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { sel = uvedit_uv_select_test(scene, l, cd_loop_uv_offset); - glColor4ubv(sel ? (GLubyte *)col1 : (GLubyte *)col2); + immAttrib4ubv(color, sel ? (GLubyte *)col1 : (GLubyte *)col2); luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); - glVertex2fv(luv->uv); + immVertex2fv(pos, luv->uv); } - glEnd(); + + immEnd(); } + + immUnbindProgram(); } else { + immBindBuiltinProgram(GPU_SHADER_2D_FLAT_COLOR); + BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) { + int lastsel = -1; + if (!BM_elem_flag_test(efa, BM_ELEM_TAG)) continue; - glBegin(GL_LINES); + immBegin(GL_LINES, efa->len * 2); + BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { sel = uvedit_edge_select_test(scene, l, cd_loop_uv_offset); if (sel != lastsel) { - glColor4ubv(sel ? (GLubyte *)col1 : (GLubyte *)col2); + immAttrib4ubv(color, sel ? (GLubyte *)col1 : (GLubyte *)col2); lastsel = sel; } + luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); - glVertex2fv(luv->uv); + immVertex2fv(pos, luv->uv); luv = BM_ELEM_CD_GET_VOID_P(l->next, cd_loop_uv_offset); - glVertex2fv(luv->uv); + immVertex2fv(pos, luv->uv); } - glEnd(); + + immEnd(); } + + immUnbindProgram(); } } else { + pos = add_attrib(immVertexFormat(), "pos", GL_FLOAT, 2, KEEP_FLOAT); + + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + immUniformColor4ubv(col2); + /* no nice edges */ BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) { if (!BM_elem_flag_test(efa, BM_ELEM_TAG)) continue; - draw_uvs_lineloop_bmface(efa, cd_loop_uv_offset); + draw_uvs_lineloop_bmface(efa, cd_loop_uv_offset, pos); } + + immUnbindProgram(); } - + break; } @@ -861,50 +987,80 @@ static void draw_uvs(SpaceImage *sima, Scene *scene, Object *obedit) if (drawfaces) { float cent[2]; - + bool col_set = false; + + VertexFormat *format = immVertexFormat(); + pos = add_attrib(format, "pos", GL_FLOAT, 2, KEEP_FLOAT); + unsigned int color = add_attrib(format, "color", GL_UNSIGNED_BYTE, 3, NORMALIZE_INT_TO_FLOAT); + + immBindBuiltinProgram(GPU_SHADER_2D_FLAT_COLOR); + pointsize = UI_GetThemeValuef(TH_FACEDOT_SIZE); glPointSize(pointsize); - glBegin(GL_POINTS); + immBeginAtMost(GL_POINTS, bm->totface); /* unselected faces */ - UI_ThemeColor(TH_WIRE); BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) { if (!BM_elem_flag_test(efa, BM_ELEM_TAG)) continue; if (!uvedit_face_select_test(scene, efa, cd_loop_uv_offset)) { + /* Only set color for the first face */ + if (!col_set) { + UI_GetThemeColor3ubv(TH_WIRE, col1); + immAttrib3ubv(color, col1); + + col_set = true; + } + uv_poly_center(efa, cent, cd_loop_uv_offset); - glVertex2fv(cent); + immVertex2fv(pos, cent); } } + col_set = false; + /* selected faces */ - UI_ThemeColor(TH_FACE_DOT); BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) { if (!BM_elem_flag_test(efa, BM_ELEM_TAG)) continue; if (uvedit_face_select_test(scene, efa, cd_loop_uv_offset)) { + /* Only set color for the first face */ + if (!col_set) { + UI_GetThemeColor3ubv(TH_FACE_DOT, col1); + immAttrib3ubv(color, col1); + + col_set = true; + } + uv_poly_center(efa, cent, cd_loop_uv_offset); - glVertex2fv(cent); + immVertex2fv(pos, cent); } } - glEnd(); + immEnd(); + + immUnbindProgram(); } /* 6. draw uv vertices */ if (drawfaces != 2) { /* 2 means Mesh Face Mode */ + pos = add_attrib(immVertexFormat(), "pos", GL_FLOAT, 2, KEEP_FLOAT); + + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + /* unselected uvs */ - UI_ThemeColor(TH_VERTEX); + immUniformThemeColor(TH_VERTEX); pointsize = UI_GetThemeValuef(TH_VERTEX_SIZE); glPointSize(pointsize); - - glBegin(GL_POINTS); + + immBeginAtMost(GL_POINTS, bm->totloop); + BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) { if (!BM_elem_flag_test(efa, BM_ELEM_TAG)) continue; @@ -912,17 +1068,19 @@ static void draw_uvs(SpaceImage *sima, Scene *scene, Object *obedit) BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); if (!uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) - glVertex2fv(luv->uv); + immVertex2fv(pos, luv->uv); } } - glEnd(); + + immEnd(); /* pinned uvs */ /* give odd pointsizes odd pin pointsizes */ glPointSize(pointsize * 2 + (((int)pointsize % 2) ? (-1) : 0)); - cpack(0xFF); + imm_cpack(0xFF); - glBegin(GL_POINTS); + immBeginAtMost(GL_POINTS, bm->totloop); + BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) { if (!BM_elem_flag_test(efa, BM_ELEM_TAG)) continue; @@ -931,16 +1089,18 @@ static void draw_uvs(SpaceImage *sima, Scene *scene, Object *obedit) luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); if (luv->flag & MLOOPUV_PINNED) - glVertex2fv(luv->uv); + immVertex2fv(pos, luv->uv); } } - glEnd(); + + immEnd(); /* selected uvs */ - UI_ThemeColor(TH_VERTEX_SELECT); + immUniformThemeColor(TH_VERTEX_SELECT); glPointSize(pointsize); - glBegin(GL_POINTS); + immBeginAtMost(GL_POINTS, bm->totloop); + BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) { if (!BM_elem_flag_test(efa, BM_ELEM_TAG)) continue; @@ -949,10 +1109,13 @@ static void draw_uvs(SpaceImage *sima, Scene *scene, Object *obedit) luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); if (uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) - glVertex2fv(luv->uv); + immVertex2fv(pos, luv->uv); } } - glEnd(); + + immEnd(); + + immUnbindProgram(); } } @@ -973,7 +1136,7 @@ static void draw_uv_shadows_get(SpaceImage *sima, Object *ob, Object *obedit, bo *show_texpaint = (ob && ob->type == OB_MESH && ob->mode == OB_MODE_TEXTURE_PAINT); } -void ED_uvedit_draw_main(SpaceImage *sima, ARegion *ar, Scene *scene, Object *obedit, Object *obact) +void ED_uvedit_draw_main(SpaceImage *sima, ARegion *ar, Scene *scene, SceneLayer *sl, Object *obedit, Object *obact) { ToolSettings *toolsettings = scene->toolsettings; bool show_uvedit, show_uvshadow, show_texpaint_uvshadow; @@ -985,9 +1148,9 @@ void ED_uvedit_draw_main(SpaceImage *sima, ARegion *ar, Scene *scene, Object *ob if (show_uvshadow) draw_uvs_shadow(obedit); else if (show_uvedit) - draw_uvs(sima, scene, obedit); + draw_uvs(sima, scene, sl, obedit); else - draw_uvs_texpaint(sima, scene, obact); + draw_uvs_texpaint(sima, scene, sl, obact); if (show_uvedit && !(toolsettings->use_uv_sculpt)) ED_image_draw_cursor(ar, sima->cursor); diff --git a/source/blender/editors/uvedit/uvedit_smart_stitch.c b/source/blender/editors/uvedit/uvedit_smart_stitch.c index 50aec737c8e..014aa65efb5 100644 --- a/source/blender/editors/uvedit/uvedit_smart_stitch.c +++ b/source/blender/editors/uvedit/uvedit_smart_stitch.c @@ -63,6 +63,8 @@ #include "ED_screen.h" #include "ED_space_api.h" +#include "GPU_batch.h" + #include "RNA_access.h" #include "RNA_define.h" @@ -1538,63 +1540,118 @@ static void stitch_calculate_edge_normal(BMEditMesh *em, UvEdge *edge, float *no normalize_v2(normal); } +static void stitch_draw_vbo(VertexBuffer *vbo, int type, const float col[4]) +{ + Batch *batch = Batch_create(type, vbo, NULL); + Batch_set_builtin_program(batch, GPU_SHADER_2D_UNIFORM_COLOR); + Batch_Uniform4fv(batch, "color", col); + Batch_draw(batch); + Batch_discard_all(batch); +} + +/* TODO make things pretier : store batches inside StitchPreviewer instead of the bare verts pos */ static void stitch_draw(const bContext *UNUSED(C), ARegion *UNUSED(ar), void *arg) { - int i, index = 0; + int j, index = 0; + unsigned int num_line = 0, num_tri, tri_idx = 0, line_idx = 0; StitchState *state = (StitchState *)arg; StitchPreviewer *stitch_preview = state->stitch_preview; + VertexBuffer *vbo, *vbo_line; + float col[4]; - glPushClientAttrib(GL_CLIENT_VERTEX_ARRAY_BIT); - glEnableClientState(GL_VERTEX_ARRAY); + static VertexFormat format = { 0 }; + static unsigned pos_id; + if (format.attrib_ct == 0) { + pos_id = add_attrib(&format, "pos", GL_FLOAT, 2, KEEP_FLOAT); + } glEnable(GL_BLEND); - UI_ThemeColor4(TH_STITCH_PREVIEW_ACTIVE); - glVertexPointer(2, GL_FLOAT, 0, stitch_preview->static_tris); - glDrawArrays(GL_TRIANGLES, 0, stitch_preview->num_static_tris * 3); - - glVertexPointer(2, GL_FLOAT, 0, stitch_preview->preview_polys); - for (i = 0; i < stitch_preview->num_polys; i++) { - glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); - UI_ThemeColor4(TH_STITCH_PREVIEW_FACE); - glDrawArrays(GL_POLYGON, index, stitch_preview->uvs_per_polygon[i]); - glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); - UI_ThemeColor4(TH_STITCH_PREVIEW_EDGE); - glDrawArrays(GL_POLYGON, index, stitch_preview->uvs_per_polygon[i]); -#if 0 - glPolygonMode(GL_FRONT_AND_BACK, GL_POINT); - UI_ThemeColor4(TH_STITCH_PREVIEW_VERT); - glDrawArrays(GL_POLYGON, index, stitch_preview->uvs_per_polygon[i]); -#endif - - index += stitch_preview->uvs_per_polygon[i]; + /* Static Tris */ + UI_GetThemeColor4fv(TH_STITCH_PREVIEW_ACTIVE, col); + vbo = VertexBuffer_create_with_format(&format); + VertexBuffer_allocate_data(vbo, stitch_preview->num_static_tris * 3); + for (int i = 0; i < stitch_preview->num_static_tris * 3; i++) + setAttrib(vbo, pos_id, i, &stitch_preview->static_tris[i*2]); + stitch_draw_vbo(vbo, GL_TRIANGLES, col); + + + /* Preview Polys */ + for (int i = 0; i < stitch_preview->num_polys; i++) + num_line += stitch_preview->uvs_per_polygon[i]; + + num_tri = num_line - 2 * stitch_preview->num_polys; + + /* we need to convert the polys into triangles / lines */ + vbo = VertexBuffer_create_with_format(&format); + vbo_line = VertexBuffer_create_with_format(&format); + + VertexBuffer_allocate_data(vbo, num_tri * 3); + VertexBuffer_allocate_data(vbo_line, num_line * 2); + + for (int i = 0; i < stitch_preview->num_polys; i++) { + BLI_assert(stitch_preview->uvs_per_polygon[i] >= 3); + + /* Start line */ + setAttrib(vbo_line, pos_id, line_idx++, &stitch_preview->preview_polys[index]); + setAttrib(vbo_line, pos_id, line_idx++, &stitch_preview->preview_polys[index + 2]); + + for (j = 1; j < stitch_preview->uvs_per_polygon[i] - 1; ++j) { + setAttrib(vbo, pos_id, tri_idx++, &stitch_preview->preview_polys[index]); + setAttrib(vbo, pos_id, tri_idx++, &stitch_preview->preview_polys[index + (j+0)*2]); + setAttrib(vbo, pos_id, tri_idx++, &stitch_preview->preview_polys[index + (j+1)*2]); + + setAttrib(vbo_line, pos_id, line_idx++, &stitch_preview->preview_polys[index + (j+0)*2]); + setAttrib(vbo_line, pos_id, line_idx++, &stitch_preview->preview_polys[index + (j+1)*2]); + } + + /* Closing line */ + setAttrib(vbo_line, pos_id, line_idx++, &stitch_preview->preview_polys[index]); + setAttrib(vbo_line, pos_id, line_idx++, &stitch_preview->preview_polys[index + j*2]); /* j = uvs_per_polygon[i] - 1*/ + + index += stitch_preview->uvs_per_polygon[i] * 2; } + UI_GetThemeColor4fv(TH_STITCH_PREVIEW_FACE, col); + stitch_draw_vbo(vbo, GL_TRIANGLES, col); + UI_GetThemeColor4fv(TH_STITCH_PREVIEW_EDGE, col); + stitch_draw_vbo(vbo_line, GL_LINES, col); + glDisable(GL_BLEND); - /* draw vert preview */ + + /* draw stitch vert/lines preview */ if (state->mode == STITCH_VERT) { glPointSize(UI_GetThemeValuef(TH_VERTEX_SIZE) * 2.0f); - UI_ThemeColor4(TH_STITCH_PREVIEW_STITCHABLE); - glVertexPointer(2, GL_FLOAT, 0, stitch_preview->preview_stitchable); - glDrawArrays(GL_POINTS, 0, stitch_preview->num_stitchable); + UI_GetThemeColor4fv(TH_STITCH_PREVIEW_STITCHABLE, col); + vbo = VertexBuffer_create_with_format(&format); + VertexBuffer_allocate_data(vbo, stitch_preview->num_stitchable); + for (int i = 0; i < stitch_preview->num_stitchable; i++) + setAttrib(vbo, pos_id, i, &stitch_preview->preview_stitchable[i*2]); + stitch_draw_vbo(vbo, GL_POINTS, col); - UI_ThemeColor4(TH_STITCH_PREVIEW_UNSTITCHABLE); - glVertexPointer(2, GL_FLOAT, 0, stitch_preview->preview_unstitchable); - glDrawArrays(GL_POINTS, 0, stitch_preview->num_unstitchable); + UI_GetThemeColor4fv(TH_STITCH_PREVIEW_UNSTITCHABLE, col); + vbo = VertexBuffer_create_with_format(&format); + VertexBuffer_allocate_data(vbo, stitch_preview->num_unstitchable); + for (int i = 0; i < stitch_preview->num_unstitchable; i++) + setAttrib(vbo, pos_id, i, &stitch_preview->preview_unstitchable[i*2]); + stitch_draw_vbo(vbo, GL_POINTS, col); } else { - UI_ThemeColor4(TH_STITCH_PREVIEW_STITCHABLE); - glVertexPointer(2, GL_FLOAT, 0, stitch_preview->preview_stitchable); - glDrawArrays(GL_LINES, 0, 2 * stitch_preview->num_stitchable); - - UI_ThemeColor4(TH_STITCH_PREVIEW_UNSTITCHABLE); - glVertexPointer(2, GL_FLOAT, 0, stitch_preview->preview_unstitchable); - glDrawArrays(GL_LINES, 0, 2 * stitch_preview->num_unstitchable); + UI_GetThemeColor4fv(TH_STITCH_PREVIEW_STITCHABLE, col); + vbo = VertexBuffer_create_with_format(&format); + VertexBuffer_allocate_data(vbo, stitch_preview->num_stitchable * 2); + for (int i = 0; i < stitch_preview->num_stitchable * 2; i++) + setAttrib(vbo, pos_id, i, &stitch_preview->preview_stitchable[i*2]); + stitch_draw_vbo(vbo, GL_LINES, col); + + UI_GetThemeColor4fv(TH_STITCH_PREVIEW_UNSTITCHABLE, col); + vbo = VertexBuffer_create_with_format(&format); + VertexBuffer_allocate_data(vbo, stitch_preview->num_unstitchable * 2); + for (int i = 0; i < stitch_preview->num_unstitchable * 2; i++) + setAttrib(vbo, pos_id, i, &stitch_preview->preview_unstitchable[i*2]); + stitch_draw_vbo(vbo, GL_LINES, col); } - - glPopClientAttrib(); - glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); } static UvEdge *uv_edge_get(BMLoop *l, StitchState *state) diff --git a/source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.cpp b/source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.cpp index f63cf771120..0e03ab84a47 100644 --- a/source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.cpp +++ b/source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.cpp @@ -127,7 +127,7 @@ BlenderStrokeRenderer::BlenderStrokeRenderer(Render *re, int render_count) : Str BKE_scene_set_background(freestyle_bmain, freestyle_scene); // Camera - Object *object_camera = BKE_object_add(freestyle_bmain, freestyle_scene, OB_CAMERA, NULL); + Object *object_camera = BKE_object_add(freestyle_bmain, freestyle_scene, (SceneLayer *)freestyle_scene->render_layers.first, OB_CAMERA, NULL); DAG_relations_tag_update(freestyle_bmain); Camera *camera = (Camera *)object_camera->data; @@ -166,7 +166,7 @@ BlenderStrokeRenderer::~BlenderStrokeRenderer() // compositor has finished. // release objects and data blocks - for (Base *b = (Base *)freestyle_scene->base.first; b; b = b->next) { + for (BaseLegacy *b = (BaseLegacy *)freestyle_scene->base.first; b; b = b->next) { Object *ob = b->object; void *data = ob->data; char *name = ob->id.name; @@ -674,7 +674,7 @@ int BlenderStrokeRenderer::get_stroke_count() const void BlenderStrokeRenderer::GenerateStrokeMesh(StrokeGroup *group, bool hasTex) { #if 0 - Object *object_mesh = BKE_object_add(freestyle_bmain, freestyle_scene, OB_MESH); + Object *object_mesh = BKE_object_add(freestyle_bmain, freestyle_scene, (SceneLayer *)freestyle_scene->render_layers.first, OB_MESH); DAG_relations_tag_update(freestyle_bmain); #else Object *object_mesh = NewMesh(); @@ -922,7 +922,7 @@ void BlenderStrokeRenderer::GenerateStrokeMesh(StrokeGroup *group, bool hasTex) Object *BlenderStrokeRenderer::NewMesh() const { Object *ob; - Base *base; + BaseLegacy *base; char name[MAX_ID_NAME]; unsigned int mesh_id = get_stroke_mesh_id(); diff --git a/source/blender/gpu/CMakeLists.txt b/source/blender/gpu/CMakeLists.txt index 8885209ce01..98c7331e8dc 100644 --- a/source/blender/gpu/CMakeLists.txt +++ b/source/blender/gpu/CMakeLists.txt @@ -31,6 +31,9 @@ set(INC ../imbuf ../makesdna ../makesrna + ../draw + + ../editors/include # For node muting stuff... ../nodes @@ -47,6 +50,7 @@ set(INC_SYS set(SRC intern/gpu_basic_shader.c + intern/gpu_batch.c intern/gpu_buffers.c intern/gpu_codegen.c intern/gpu_compositing.c @@ -54,11 +58,33 @@ set(SRC intern/gpu_draw.c intern/gpu_extensions.c intern/gpu_framebuffer.c + intern/gpu_immediate.c intern/gpu_init_exit.c intern/gpu_material.c + intern/gpu_matrix.c intern/gpu_select.c intern/gpu_shader.c intern/gpu_texture.c + intern/gpu_uniformbuffer.c + intern/gpu_viewport.c + + gawain/attrib_binding.c + gawain/attrib_binding.h + gawain/batch.c + gawain/batch.h + gawain/buffer_id.h + gawain/buffer_id.cpp + gawain/common.h + gawain/element.c + gawain/element.h + gawain/immediate.c + gawain/immediate.h + gawain/imm_util.c + gawain/imm_util.h + gawain/vertex_buffer.c + gawain/vertex_buffer.h + gawain/vertex_format.c + gawain/vertex_format.h shaders/gpu_shader_fx_lib.glsl shaders/gpu_shader_fx_ssao_frag.glsl @@ -83,6 +109,7 @@ set(SRC shaders/gpu_shader_smoke_vert.glsl GPU_basic_shader.h + GPU_batch.h GPU_buffers.h GPU_compositing.h GPU_debug.h @@ -90,15 +117,82 @@ set(SRC GPU_extensions.h GPU_framebuffer.h GPU_glew.h + GPU_immediate.h GPU_init_exit.h GPU_material.h + GPU_matrix.h GPU_select.h GPU_shader.h GPU_texture.h + GPU_uniformbuffer.h + GPU_viewport.h + intern/gpu_codegen.h intern/gpu_private.h ) +data_to_c_simple(shaders/gpu_shader_depth_only_frag.glsl SRC) +data_to_c_simple(shaders/gpu_shader_uniform_color_frag.glsl SRC) +data_to_c_simple(shaders/gpu_shader_checker_frag.glsl SRC) +data_to_c_simple(shaders/gpu_shader_diag_stripes_frag.glsl SRC) +data_to_c_simple(shaders/gpu_shader_simple_lighting_frag.glsl SRC) +data_to_c_simple(shaders/gpu_shader_flat_color_frag.glsl SRC) +data_to_c_simple(shaders/gpu_shader_flat_color_alpha_test_0_frag.glsl SRC) +data_to_c_simple(shaders/gpu_shader_2D_vert.glsl SRC) +data_to_c_simple(shaders/gpu_shader_2D_flat_color_vert.glsl SRC) +data_to_c_simple(shaders/gpu_shader_2D_smooth_color_vert.glsl SRC) +data_to_c_simple(shaders/gpu_shader_2D_smooth_color_frag.glsl SRC) +data_to_c_simple(shaders/gpu_shader_2D_image_vert.glsl SRC) +data_to_c_simple(shaders/gpu_shader_image_mask_uniform_color_frag.glsl SRC) +data_to_c_simple(shaders/gpu_shader_image_modulate_alpha_frag.glsl SRC) +data_to_c_simple(shaders/gpu_shader_image_color_frag.glsl SRC) +data_to_c_simple(shaders/gpu_shader_image_rect_modulate_alpha_frag.glsl SRC) +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_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_passthrough_vert.glsl SRC) + +data_to_c_simple(shaders/gpu_shader_instance_vert.glsl SRC) +data_to_c_simple(shaders/gpu_shader_instance_variying_size_variying_color_vert.glsl SRC) +data_to_c_simple(shaders/gpu_shader_instance_objectspace_variying_color_vert.glsl SRC) +data_to_c_simple(shaders/gpu_shader_instance_screenspace_variying_color_vert.glsl SRC) +data_to_c_simple(shaders/gpu_shader_instance_screen_aligned_axis_name_vert.glsl SRC) + +data_to_c_simple(shaders/gpu_shader_3D_groundline_geom.glsl SRC) +data_to_c_simple(shaders/gpu_shader_3D_groundpoint_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) +data_to_c_simple(shaders/gpu_shader_point_varying_color_outline_smooth_frag.glsl SRC) +data_to_c_simple(shaders/gpu_shader_point_varying_color_frag.glsl SRC) +data_to_c_simple(shaders/gpu_shader_3D_point_fixed_size_varying_color_vert.glsl SRC) +data_to_c_simple(shaders/gpu_shader_3D_point_varying_size_vert.glsl SRC) +data_to_c_simple(shaders/gpu_shader_3D_point_varying_size_varying_color_vert.glsl SRC) +data_to_c_simple(shaders/gpu_shader_3D_point_uniform_size_smooth_vert.glsl SRC) +data_to_c_simple(shaders/gpu_shader_3D_point_uniform_size_outline_smooth_vert.glsl SRC) +data_to_c_simple(shaders/gpu_shader_2D_point_varying_size_varying_color_vert.glsl SRC) +data_to_c_simple(shaders/gpu_shader_2D_point_uniform_size_smooth_vert.glsl SRC) +data_to_c_simple(shaders/gpu_shader_2D_point_uniform_size_outline_smooth_vert.glsl SRC) +data_to_c_simple(shaders/gpu_shader_2D_point_uniform_size_varying_color_outline_smooth_vert.glsl SRC) + +data_to_c_simple(shaders/gpu_shader_edges_front_back_persp_vert.glsl SRC) +data_to_c_simple(shaders/gpu_shader_edges_front_back_persp_geom.glsl SRC) +data_to_c_simple(shaders/gpu_shader_edges_front_back_persp_legacy_vert.glsl SRC) +data_to_c_simple(shaders/gpu_shader_edges_front_back_ortho_vert.glsl SRC) +data_to_c_simple(shaders/gpu_shader_edges_overlay_vert.glsl SRC) +data_to_c_simple(shaders/gpu_shader_edges_overlay_geom.glsl SRC) +data_to_c_simple(shaders/gpu_shader_edges_overlay_simple_geom.glsl SRC) +data_to_c_simple(shaders/gpu_shader_edges_overlay_frag.glsl SRC) +data_to_c_simple(shaders/gpu_shader_text_vert.glsl SRC) +data_to_c_simple(shaders/gpu_shader_text_frag.glsl SRC) +data_to_c_simple(shaders/gpu_shader_keyframe_diamond_vert.glsl SRC) +data_to_c_simple(shaders/gpu_shader_keyframe_diamond_frag.glsl SRC) + data_to_c_simple(shaders/gpu_shader_geometry.glsl SRC) data_to_c_simple(shaders/gpu_shader_fire_frag.glsl SRC) data_to_c_simple(shaders/gpu_shader_smoke_frag.glsl SRC) diff --git a/source/blender/gpu/GPU_basic_shader.h b/source/blender/gpu/GPU_basic_shader.h index d9bf3d1ced3..bfdf4ab6bbd 100644 --- a/source/blender/gpu/GPU_basic_shader.h +++ b/source/blender/gpu/GPU_basic_shader.h @@ -64,12 +64,6 @@ typedef enum GPUBasicShaderStipple { GPU_SHADER_STIPPLE_HEXAGON = 3, GPU_SHADER_STIPPLE_DIAG_STRIPES = 4, GPU_SHADER_STIPPLE_DIAG_STRIPES_SWAP = 5, - GPU_SHADER_STIPPLE_S3D_INTERLACE_ROW = 6, - GPU_SHADER_STIPPLE_S3D_INTERLACE_ROW_SWAP = 7, - GPU_SHADER_STIPPLE_S3D_INTERLACE_COLUMN = 8, - GPU_SHADER_STIPPLE_S3D_INTERLACE_COLUMN_SWAP = 9, - GPU_SHADER_STIPPLE_S3D_INTERLACE_CHECKER = 10, - GPU_SHADER_STIPPLE_S3D_INTERLACE_CHECKER_SWAP = 11 } GPUBasicShaderStipple; void GPU_basic_shaders_init(void); diff --git a/source/blender/gpu/GPU_batch.h b/source/blender/gpu/GPU_batch.h new file mode 100644 index 00000000000..066bc9eeba7 --- /dev/null +++ b/source/blender/gpu/GPU_batch.h @@ -0,0 +1,43 @@ +/* + * ***** 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) 2016 Blender Foundation. + * All rights reserved. + * + * + * Contributor(s): Mike Erwin + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/* Batched geometry rendering is powered by the Gawain library. + * This file contains any additions or modifications specific to Blender. + */ + +#pragma once + +#include "gawain/batch.h" +#include "GPU_shader.h" + +/* Extend Batch_set_program to use Blender’s library of built-in shader programs. */ +void Batch_set_builtin_program(Batch*, GPUBuiltinShader); + +/* Replacement for gluSphere */ +Batch *Batch_get_sphere(int lod); + +void gpu_batch_init(void); +void gpu_batch_exit(void); diff --git a/source/blender/gpu/GPU_debug.h b/source/blender/gpu/GPU_debug.h index 61b2bc591ce..921deaaa6d6 100644 --- a/source/blender/gpu/GPU_debug.h +++ b/source/blender/gpu/GPU_debug.h @@ -41,24 +41,9 @@ extern "C" { /* prints something if debug mode is active only */ void GPU_print_error_debug(const char *str); -/* replacement for gluErrorString */ -const char *gpuErrorString(GLenum err); - /* prints current OpenGL state */ void GPU_state_print(void); -void GPU_assert_no_gl_errors(const char *file, int line, const char *str); - -# define GPU_ASSERT_NO_GL_ERRORS(str) GPU_assert_no_gl_errors(__FILE__, __LINE__, (str)) - -# define GPU_CHECK_ERRORS_AROUND(glProcCall) \ - ( \ - GPU_ASSERT_NO_GL_ERRORS("Pre: " #glProcCall), \ - (glProcCall), \ - GPU_ASSERT_NO_GL_ERRORS("Post: " #glProcCall) \ - ) - - /* inserts a debug marker message for the debug context messaging system */ void GPU_string_marker(const char *str); diff --git a/source/blender/gpu/GPU_draw.h b/source/blender/gpu/GPU_draw.h index 90b65af87c8..91d436557f0 100644 --- a/source/blender/gpu/GPU_draw.h +++ b/source/blender/gpu/GPU_draw.h @@ -59,6 +59,13 @@ struct DupliObject; void GPU_state_init(void); +/* Programmable point size + * - shaders set their own point size when enabled + * - use glPointSize when disabled */ + +void GPU_enable_program_point_size(void); +void GPU_disable_program_point_size(void); + /* Material drawing * - first the state is initialized by a particular object and * it's materials 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 2719b8fa6a8..15617832c9b 100644 --- a/source/blender/gpu/GPU_framebuffer.h +++ b/source/blender/gpu/GPU_framebuffer.h @@ -50,8 +50,9 @@ struct GPUTexture; void GPU_texture_bind_as_framebuffer(struct GPUTexture *tex); GPUFrameBuffer *GPU_framebuffer_create(void); -int GPU_framebuffer_texture_attach(GPUFrameBuffer *fb, struct GPUTexture *tex, int slot, char err_out[256]); +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); @@ -66,6 +67,10 @@ void GPU_framebuffer_blur( GPUFrameBuffer *fb, struct GPUTexture *tex, GPUFrameBuffer *blurfb, struct GPUTexture *blurtex); +void GPU_framebuffer_blit( + GPUFrameBuffer *fb_read, int read_slot, + GPUFrameBuffer *fb_write, int write_slot, bool use_depth); + /* GPU OffScreen * - wrapper around framebuffer and texture for simple offscreen drawing * - changes size if graphics card can't support it */ diff --git a/source/blender/gpu/GPU_immediate.h b/source/blender/gpu/GPU_immediate.h new file mode 100644 index 00000000000..4a0840e22c0 --- /dev/null +++ b/source/blender/gpu/GPU_immediate.h @@ -0,0 +1,50 @@ +/* + * ***** 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) 2016 Blender Foundation. + * All rights reserved. + * + * + * Contributor(s): Mike Erwin + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/* Immediate mode rendering is powered by the Gawain library. + * This file contains any additions or modifications specific to Blender. + */ + +#pragma once + +#include "gawain/immediate.h" +#include "gawain/imm_util.h" +#include "GPU_shader.h" + +/* Extend immBindProgram to use Blender’s library of built-in shader programs. + * Use immUnbindProgram() when done. */ +void immBindBuiltinProgram(GPUBuiltinShader shader_id); + +/* + * Extend immUniformColor to take Blender's themes + */ +void immUniformThemeColor(int color_id); +void immUniformThemeColorShade(int color_id, int offset); +void immUniformThemeColorShadeAlpha(int color_id, int color_offset, int alpha_offset); +void immUniformThemeColorBlendShade(int color_id1, int color_id2, float fac, int offset); +void immUniformThemeColorBlend(int color_id1, int color_id2, float fac); +void immThemeColorShadeAlpha(int colorid, int coloffset, int alphaoffset); + diff --git a/source/blender/gpu/GPU_matrix.h b/source/blender/gpu/GPU_matrix.h new file mode 100644 index 00000000000..2bf52c954a0 --- /dev/null +++ b/source/blender/gpu/GPU_matrix.h @@ -0,0 +1,151 @@ +#ifndef _GPU_MATRIX_H_ +#define _GPU_MATRIX_H_ + +/* + * ***** 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) 2012 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): Alexandr Kuznetsov, Jason Wilkins, Mike Erwin + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file source/blender/gpu/GPU_matrix.h + * \ingroup gpu + */ + +#include "GPU_glew.h" +#include <stdbool.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/* For now we support the legacy matrix stack in gpuGetMatrix functions. + * Will remove this after switching to core profile, which can happen after + * we convert all code to use the API in this file. */ +#define SUPPORT_LEGACY_MATRIX 1 + + +void gpuMatrixInit(void); /* called by system -- make private? */ + + +/* MatrixMode is conceptually different from GL_MATRIX_MODE */ + +typedef enum { + MATRIX_MODE_INACTIVE, + MATRIX_MODE_2D, + MATRIX_MODE_3D +} MatrixMode; + +MatrixMode gpuMatrixMode(void); + +void gpuMatrixBegin2D(void); +void gpuMatrixBegin3D(void); +void gpuMatrixEnd(void); +/* TODO: gpuMatrixResume2D & gpuMatrixResume3D to switch modes but not reset stack */ + + +/* ModelView Matrix (2D or 3D) */ + +void gpuPushMatrix(void); /* TODO: PushCopy vs PushIdentity? */ +void gpuPopMatrix(void); + +void gpuLoadIdentity(void); + +void gpuScaleUniform(float factor); + + +/* 3D ModelView Matrix */ + +void gpuLoadMatrix3D(const float m[4][4]); +void gpuMultMatrix3D(const float m[4][4]); +//const float *gpuGetMatrix3D(float m[4][4]); + +void gpuTranslate3f(float x, float y, float z); +void gpuTranslate3fv(const float vec[3]); +void gpuScale3f(float x, float y, float z); +void gpuScale3fv(const float vec[3]); +void gpuRotate3f(float deg, float x, float y, float z); /* axis of rotation should be a unit vector */ +void gpuRotate3fv(float deg, const float axis[3]); /* axis of rotation should be a unit vector */ +void gpuRotateAxis(float deg, char axis); /* TODO: enum for axis? */ + +void gpuLookAt(float eyeX, float eyeY, float eyeZ, float centerX, float centerY, float centerZ, float upX, float upY, float upZ); +/* TODO: variant that takes eye[3], center[3], up[3] */ + + +/* 2D ModelView Matrix */ + +void gpuLoadMatrix2D(const float m[3][3]); +void gpuMultMatrix2D(const float m[3][3]); + +void gpuTranslate2f(float x, float y); +void gpuTranslate2fv(const float vec[2]); +void gpuScale2f(float x, float y); +void gpuScale2fv(const float vec[2]); +void gpuRotate2D(float deg); + + +/* 3D Projection Matrix */ + +void gpuOrtho(float left, float right, float bottom, float top, float near, float far); +void gpuFrustum(float left, float right, float bottom, float top, float near, float far); +void gpuPerspective(float fovy, float aspect, float near, float far); + +/* pass vector through current transform (world --> screen) */ +void gpuProject(const float obj[3], const float model[4][4], const float proj[4][4], const GLint view[4], float win[3]); + +/* pass vector through inverse transform (world <-- screen) */ +bool gpuUnProject(const float win[3], const float model[4][4], const float proj[4][4], const GLint view[4], float obj[3]); + + +/* 2D Projection Matrix */ + +void gpuOrtho2D(float left, float right, float bottom, float top); + + +/* functions to get matrix values */ +const float *gpuGetModelViewMatrix3D(float m[4][4]); +const float *gpuGetProjectionMatrix3D(float m[4][4]); +const float *gpuGetModelViewProjectionMatrix3D(float m[4][4]); + +const float *gpuGetNormalMatrix(float m[3][3]); +const float *gpuGetNormalMatrixInverse(float m[3][3]); + + +#if SUPPORT_LEGACY_MATRIX +/* copy top matrix from each legacy stack into new fresh stack */ +void gpuMatrixBegin3D_legacy(void); + +/* call after using glScale, glTranslate, etc. between draw calls */ +void gpuMatrixUpdate_legacy(void); +#endif + + +/* set uniform values for currently bound shader */ +void gpuBindMatrices(GLuint program); +bool gpuMatricesDirty(void); /* since last bind */ + +#ifdef __cplusplus +} +#endif + +#endif /* GPU_MATRIX_H */ diff --git a/source/blender/gpu/GPU_shader.h b/source/blender/gpu/GPU_shader.h index 5b94db6e120..9fe7c7a1c14 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); @@ -85,13 +89,78 @@ int GPU_shader_get_attribute(GPUShader *shader, const char *name); /* Builtin/Non-generated shaders */ typedef enum GPUBuiltinShader { - GPU_SHADER_VSM_STORE = 0, - GPU_SHADER_SEP_GAUSSIAN_BLUR = 1, - GPU_SHADER_SMOKE = 2, - GPU_SHADER_SMOKE_FIRE = 3, - GPU_SHADER_SMOKE_COBA = 4, + GPU_SHADER_VSM_STORE, + GPU_SHADER_SEP_GAUSSIAN_BLUR, + GPU_SHADER_SMOKE, + GPU_SHADER_SMOKE_FIRE, + GPU_SHADER_SMOKE_COBA, + + /* specialized drawing */ + GPU_SHADER_TEXT, + GPU_SHADER_EDGES_FRONT_BACK_PERSP, + GPU_SHADER_EDGES_FRONT_BACK_ORTHO, + GPU_SHADER_EDGES_OVERLAY_SIMPLE, + GPU_SHADER_EDGES_OVERLAY, + GPU_SHADER_KEYFRAME_DIAMOND, + GPU_SHADER_SIMPLE_LIGHTING, + /* for simple 2D drawing */ + GPU_SHADER_2D_UNIFORM_COLOR, + GPU_SHADER_2D_FLAT_COLOR, + GPU_SHADER_2D_SMOOTH_COLOR, + GPU_SHADER_2D_IMAGE_COLOR, + GPU_SHADER_2D_CHECKER, + GPU_SHADER_2D_DIAG_STRIPES, + /* 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, + /* basic image drawing */ + GPU_SHADER_2D_IMAGE_MASK_UNIFORM_COLOR, + GPU_SHADER_3D_IMAGE_MODULATE_ALPHA, + GPU_SHADER_3D_IMAGE_RECT_MODULATE_ALPHA, + GPU_SHADER_3D_IMAGE_DEPTH, + /* stereo 3d */ + GPU_SHADER_2D_IMAGE_INTERLACE, + /* points */ + GPU_SHADER_2D_POINT_FIXED_SIZE_UNIFORM_COLOR, + GPU_SHADER_2D_POINT_UNIFORM_SIZE_UNIFORM_COLOR_SMOOTH, + GPU_SHADER_2D_POINT_UNIFORM_SIZE_UNIFORM_COLOR_OUTLINE_SMOOTH, + GPU_SHADER_2D_POINT_UNIFORM_SIZE_VARYING_COLOR_OUTLINE_SMOOTH, + GPU_SHADER_2D_POINT_VARYING_SIZE_VARYING_COLOR, + GPU_SHADER_3D_POINT_FIXED_SIZE_UNIFORM_COLOR, + GPU_SHADER_3D_POINT_FIXED_SIZE_VARYING_COLOR, + GPU_SHADER_3D_POINT_UNIFORM_SIZE_UNIFORM_COLOR_SMOOTH, + 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_SCREENSPACE_VARIYING_COLOR, + /* bone drawing */ + GPU_SHADER_3D_OBJECTSPACE_VARIYING_COLOR, + GPU_SHADER_3D_OBJECTSPACE_SIMPLE_LIGHTING_VARIYING_COLOR, + /* axis name */ + GPU_SHADER_3D_INSTANCE_SCREEN_ALIGNED_AXIS, + /* instance */ + GPU_SHADER_INSTANCE_UNIFORM_COLOR, + GPU_SHADER_INSTANCE_VARIYING_COLOR_VARIYING_SIZE, + + GPU_NUM_BUILTIN_SHADERS /* (not an actual shader) */ } GPUBuiltinShader; +/* Keep these in sync with: + * gpu_shader_image_interlace_frag.glsl + * gpu_shader_image_rect_interlace_frag.glsl + **/ +typedef enum GPUInterlaceShader { + GPU_SHADER_INTERLACE_ROW = 0, + GPU_SHADER_INTERLACE_COLUMN = 1, + GPU_SHADER_INTERLACE_CHECKER = 2, +} GPUInterlaceShader; + GPUShader *GPU_shader_get_builtin_shader(GPUBuiltinShader shader); GPUShader *GPU_shader_get_builtin_fx_shader(int effects, bool persp); diff --git a/source/blender/gpu/GPU_texture.h b/source/blender/gpu/GPU_texture.h index 756fe79151b..a8df80cd626 100644 --- a/source/blender/gpu/GPU_texture.h +++ b/source/blender/gpu/GPU_texture.h @@ -55,25 +55,112 @@ typedef struct GPUTexture GPUTexture; * - if created with from_blender, will not free the texture */ -typedef enum GPUHDRType { - GPU_HDR_NONE = 0, - GPU_HDR_HALF_FLOAT = 1, - GPU_HDR_FULL_FLOAT = (1 << 1), -} GPUHDRType; +/* Wrapper to supported OpenGL/Vulkan texture internal storage + * If you need a type just uncomment it. Be aware that some formats + * are not supported by renderbuffers. All of the following formats + * are part of the OpenGL 3.3 core + * specification. */ +typedef enum GPUTextureFormat { + /* Formats texture & renderbuffer */ + GPU_RGBA16F, + GPU_RGBA8, + GPU_RG32F, + GPU_RG16F, + GPU_R8, +#if 0 + GPU_RGBA32F, + GPU_RGBA32I, + GPU_RGBA32UI, + GPU_RGBA16, + GPU_RGBA16I, + GPU_RGBA16UI, + GPU_RGBA8I, + GPU_RGBA8UI, + GPU_RG32I, + GPU_RG32UI, + GPU_RG16, + GPU_RG16I, + GPU_RG16UI, + GPU_RG8, + GPU_RG8I, + GPU_RG8UI, + GPU_R32F, + GPU_R32I, + GPU_R32UI, + GPU_R16F, + GPU_R16I, + GPU_R16UI, + GPU_R16, + GPU_R8I, + GPU_R8UI, +#endif + + /* Special formats texture & renderbuffer */ +#if 0 + GPU_R11F_G11F_B10F, + GPU_RGB10_A2, + GPU_RGB10_A2UI, + GPU_DEPTH32F_STENCIL8, + GPU_DEPTH24_STENCIL8, +#endif + + /* Texture only format */ +#if 0 + GPU_RGBA16_SNORM, + GPU_RGBA8_SNORM, + GPU_RGB32F, + GPU_RGB32I, + GPU_RGB32UI, + GPU_RGB16_SNORM, + GPU_RGB16F, + GPU_RGB16I, + GPU_RGB16UI, + GPU_RGB16, + GPU_RGB8_SNORM, + GPU_RGB8, + GPU_RGB8I, + GPU_RGB8UI, + GPU_RG16_SNORM, + GPU_RG8_SNORM, + GPU_R16_SNORM, + GPU_R8_SNORM, +#endif + + /* Special formats texture only */ +#if 0 + GPU_SRGB8_A8, + GPU_SRGB8, + GPU_RGB9_E5, + GPU_COMPRESSED_RG_RGTC2, + GPU_COMPRESSED_SIGNED_RG_RGTC2, + GPU_COMPRESSED_RED_RGTC1, + GPU_COMPRESSED_SIGNED_RED_RGTC1, +#endif + + /* Depth Formats */ + GPU_DEPTH_COMPONENT32F, + GPU_DEPTH_COMPONENT24, + GPU_DEPTH_COMPONENT16, +} GPUTextureFormat; GPUTexture *GPU_texture_create_1D(int w, const float *pixels, char err_out[256]); -GPUTexture *GPU_texture_create_2D(int w, int h, const float *pixels, GPUHDRType hdr, char err_out[256]); -GPUTexture *GPU_texture_create_3D(int w, int h, int depth, int channels, const float *fpixels); +GPUTexture *GPU_texture_create_1D_custom( + int w, int channels, GPUTextureFormat data_type, const float *pixels, char err_out[256]); +GPUTexture *GPU_texture_create_2D(int w, int h, const float *pixels, char err_out[256]); +GPUTexture *GPU_texture_create_2D_custom( + int w, int h, int channels, GPUTextureFormat data_type, const float *pixels, char err_out[256]); +GPUTexture *GPU_texture_create_2D_multisample(int w, int h, const float *pixels, int samples, char err_out[256]); +GPUTexture *GPU_texture_create_2D_array(int w, int h, int d, const float *pixels, char err_out[256]); +GPUTexture *GPU_texture_create_3D(int w, int h, int d, const float *pixels, char err_out[256]); +GPUTexture *GPU_texture_create_3D_custom( + int w, int h, int d, int channels, GPUTextureFormat data_type, const float *pixels, char err_out[256]); GPUTexture *GPU_texture_create_depth(int w, int h, char err_out[256]); -GPUTexture *GPU_texture_create_vsm_shadow_map(int size, char err_out[256]); -GPUTexture *GPU_texture_create_2D_procedural(int w, int h, const float *pixels, bool repeat, char err_out[256]); -GPUTexture *GPU_texture_create_1D_procedural(int w, const float *pixels, char err_out[256]); -GPUTexture *GPU_texture_create_2D_multisample( - int w, int h, const float *pixels, GPUHDRType hdr, int samples, char err_out[256]); GPUTexture *GPU_texture_create_depth_multisample(int w, int h, int samples, char err_out[256]); + GPUTexture *GPU_texture_from_blender( struct Image *ima, struct ImageUser *iuser, int textarget, bool is_data, double time, int mipmap); GPUTexture *GPU_texture_from_preview(struct PreviewImage *prv, int mipmap); + void GPU_invalid_tex_init(void); void GPU_invalid_tex_bind(int mode); void GPU_invalid_tex_free(void); @@ -81,12 +168,13 @@ void GPU_invalid_tex_free(void); void GPU_texture_free(GPUTexture *tex); void GPU_texture_ref(GPUTexture *tex); - void GPU_texture_bind(GPUTexture *tex, int number); void GPU_texture_unbind(GPUTexture *tex); int GPU_texture_bound_number(GPUTexture *tex); -void GPU_texture_filter_mode(GPUTexture *tex, bool compare, bool use_filter); +void GPU_texture_compare_mode(GPUTexture *tex, bool use_compare); +void GPU_texture_filter_mode(GPUTexture *tex, bool use_filter); +void GPU_texture_wrap_mode(GPUTexture *tex, bool use_repeat); struct GPUFrameBuffer *GPU_texture_framebuffer(GPUTexture *tex); int GPU_texture_framebuffer_attachment(GPUTexture *tex); diff --git a/source/blender/gpu/GPU_uniformbuffer.h b/source/blender/gpu/GPU_uniformbuffer.h new file mode 100644 index 00000000000..bcb6e1077b7 --- /dev/null +++ b/source/blender/gpu/GPU_uniformbuffer.h @@ -0,0 +1,44 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2005 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): Clement Foucault. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file GPU_uniformbuffer.h + * \ingroup gpu + */ + +typedef struct GPUUniformBuffer GPUUniformBuffer; + +GPUUniformBuffer *GPU_uniformbuffer_create(int size, const void *data, char err_out[256]); +void GPU_uniformbuffer_free(GPUUniformBuffer *ubo); + +void GPU_uniformbuffer_update(GPUUniformBuffer *ubo, const void *data); + +void GPU_uniformbuffer_bind(GPUUniformBuffer *ubo, int number); +#if 0 +void GPU_uniformbuffer_unbind(GPUUniformBuffer *ubo); +#endif + +int GPU_uniformbuffer_bindpoint(GPUUniformBuffer *ubo); diff --git a/source/blender/gpu/GPU_viewport.h b/source/blender/gpu/GPU_viewport.h new file mode 100644 index 00000000000..f0e991fdac2 --- /dev/null +++ b/source/blender/gpu/GPU_viewport.h @@ -0,0 +1,98 @@ +/* + * ***** 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): + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file GPU_viewport.h + * \ingroup gpu + */ + +#ifndef __GPU_VIEWPORT_H__ +#define __GPU_VIEWPORT_H__ + +#include <stdbool.h> + +#include "DNA_vec_types.h" + +#include "GPU_framebuffer.h" +#include "GPU_texture.h" + +typedef struct GPUViewport GPUViewport; + +#define MAX_BUFFERS 8 +#define MAX_TEXTURES 16 +#define MAX_PASSES 16 +#define MAX_STORAGE 2 /* extend if needed */ + +/* 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_PASSES]; +} PassList; + +typedef struct StorageList { + void *storage[MAX_STORAGE]; /* custom structs from the engine */ +} StorageList; + +/* 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, const char *engine, int mode); +void GPU_viewport_unbind(GPUViewport *viewport); +void GPU_viewport_free(GPUViewport *viewport); + +void GPU_viewport_get_engine_data(GPUViewport *viewport, FramebufferList **fbs, TextureList **txs, PassList **pss, StorageList **str); +void GPU_viewport_get_mode_data(GPUViewport *viewport, FramebufferList **fbs, TextureList **txs, PassList **pss, StorageList **str); + +/* 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); +void GPU_viewport_debug_depth_store(GPUViewport *viewport, const int x, const int y); +void GPU_viewport_debug_depth_draw(GPUViewport *viewport, const float znear, const float zfar); +bool GPU_viewport_debug_depth_is_valid(GPUViewport *viewport); +int GPU_viewport_debug_depth_width(const GPUViewport *viewport); +int GPU_viewport_debug_depth_height(const GPUViewport *viewport); + +#endif // __GPU_VIEWPORT_H__ diff --git a/source/blender/gpu/gawain/attrib_binding.c b/source/blender/gpu/gawain/attrib_binding.c new file mode 100644 index 00000000000..bb42aaf66eb --- /dev/null +++ b/source/blender/gpu/gawain/attrib_binding.c @@ -0,0 +1,69 @@ + +// Gawain vertex attribute binding +// +// This code is part of the Gawain library, with modifications +// specific to integration with Blender. +// +// Copyright 2016 Mike Erwin +// +// This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of +// the MPL was not distributed with this file, You can obtain one at https://mozilla.org/MPL/2.0/. + +#include "attrib_binding.h" + +#if MAX_VERTEX_ATTRIBS != 16 + #error "attrib binding code assumes MAX_VERTEX_ATTRIBS = 16" +#endif + +void clear_AttribBinding(AttribBinding* binding) + { + binding->loc_bits = 0; + binding->enabled_bits = 0; + } + +unsigned read_attrib_location(const AttribBinding* binding, unsigned a_idx) + { +#if TRUST_NO_ONE + assert(a_idx < MAX_VERTEX_ATTRIBS); + assert(binding->enabled_bits & (1 << a_idx)); +#endif + + return (binding->loc_bits >> (4 * a_idx)) & 0xF; + } + +static void write_attrib_location(AttribBinding* binding, unsigned a_idx, unsigned location) + { +#if TRUST_NO_ONE + assert(a_idx < MAX_VERTEX_ATTRIBS); + assert(location < MAX_VERTEX_ATTRIBS); +#endif + + const unsigned shift = 4 * a_idx; + const uint64_t mask = ((uint64_t)0xF) << shift; + // overwrite this attrib's previous location + binding->loc_bits = (binding->loc_bits & ~mask) | (location << shift); + // mark this attrib as enabled + binding->enabled_bits |= 1 << a_idx; + } + +void get_attrib_locations(const VertexFormat* format, AttribBinding* binding, GLuint program) + { +#if TRUST_NO_ONE + assert(glIsProgram(program)); +#endif + + clear_AttribBinding(binding); + + for (unsigned a_idx = 0; a_idx < format->attrib_ct; ++a_idx) + { + const Attrib* a = format->attribs + a_idx; + GLint loc = glGetAttribLocation(program, a->name); + +#if TRUST_NO_ONE + assert(loc != -1); + // TODO: make this a recoverable runtime error? indicates mismatch between vertex format and program +#endif + + write_attrib_location(binding, a_idx, loc); + } + } diff --git a/source/blender/gpu/gawain/attrib_binding.h b/source/blender/gpu/gawain/attrib_binding.h new file mode 100644 index 00000000000..9e2431ca379 --- /dev/null +++ b/source/blender/gpu/gawain/attrib_binding.h @@ -0,0 +1,24 @@ + +// Gawain vertex attribute binding +// +// This code is part of the Gawain library, with modifications +// specific to integration with Blender. +// +// Copyright 2016 Mike Erwin +// +// This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of +// the MPL was not distributed with this file, You can obtain one at https://mozilla.org/MPL/2.0/. + +#pragma once + +#include "vertex_format.h" + +typedef struct { + uint64_t loc_bits; // store 4 bits for each of the 16 attribs + uint16_t enabled_bits; // 1 bit for each attrib +} AttribBinding; + +void clear_AttribBinding(AttribBinding*); + +void get_attrib_locations(const VertexFormat*, AttribBinding*, GLuint program); +unsigned read_attrib_location(const AttribBinding*, unsigned a_idx); diff --git a/source/blender/gpu/gawain/batch.c b/source/blender/gpu/gawain/batch.c new file mode 100644 index 00000000000..81e694cc9b8 --- /dev/null +++ b/source/blender/gpu/gawain/batch.c @@ -0,0 +1,338 @@ + +// Gawain geometry batch +// +// This code is part of the Gawain library, with modifications +// specific to integration with Blender. +// +// Copyright 2016 Mike Erwin +// +// This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of +// the MPL was not distributed with this file, You can obtain one at https://mozilla.org/MPL/2.0/. + +#include "batch.h" +#include "buffer_id.h" +#include <stdlib.h> + +// necessary functions from matrix API +extern void gpuBindMatrices(GLuint program); +extern bool gpuMatricesDirty(void); // how best to use this here? + +Batch* Batch_create(PrimitiveType prim_type, VertexBuffer* verts, ElementList* elem) + { + Batch* batch = calloc(1, sizeof(Batch)); + + Batch_init(batch, prim_type, verts, elem); + + return batch; + } + +void Batch_init(Batch* batch, PrimitiveType prim_type, VertexBuffer* verts, ElementList* elem) + { +#if TRUST_NO_ONE + assert(verts != NULL); + assert(prim_type == PRIM_POINTS || prim_type == PRIM_LINES || prim_type == PRIM_TRIANGLES); + // we will allow other primitive types in a future update +#endif + + batch->verts = verts; + batch->elem = elem; + batch->prim_type = prim_type; + batch->phase = READY_TO_DRAW; + } + +void Batch_discard(Batch* batch) + { + if (batch->vao_id) + vao_id_free(batch->vao_id); + + free(batch); + } + +void Batch_discard_all(Batch* batch) + { + VertexBuffer_discard(batch->verts); + if (batch->elem) + ElementList_discard(batch->elem); + Batch_discard(batch); + } + +void Batch_set_program(Batch* batch, GLuint program) + { +#if TRUST_NO_ONE + assert(glIsProgram(program)); +#endif + + batch->program = program; + batch->program_dirty = true; + + Batch_use_program(batch); // hack! to make Batch_Uniform* simpler + } + +static void Batch_update_program_bindings(Batch* batch) + { + const VertexFormat* format = &batch->verts->format; + + const unsigned attrib_ct = format->attrib_ct; + const unsigned stride = format->stride; + + // disable all as a precaution + // why are we not using prev_attrib_enabled_bits?? see immediate.c + for (unsigned a_idx = 0; a_idx < MAX_VERTEX_ATTRIBS; ++a_idx) + glDisableVertexAttribArray(a_idx); + + VertexBuffer_use(batch->verts); + + for (unsigned a_idx = 0; a_idx < attrib_ct; ++a_idx) + { + const Attrib* a = format->attribs + a_idx; + + const GLvoid* pointer = (const GLubyte*)0 + a->offset; + + const GLint loc = glGetAttribLocation(batch->program, a->name); + + if (loc == -1) continue; + + glEnableVertexAttribArray(loc); + + switch (a->fetch_mode) + { + case KEEP_FLOAT: + case CONVERT_INT_TO_FLOAT: + glVertexAttribPointer(loc, a->comp_ct, a->comp_type, GL_FALSE, stride, pointer); + break; + case NORMALIZE_INT_TO_FLOAT: + glVertexAttribPointer(loc, a->comp_ct, a->comp_type, GL_TRUE, stride, pointer); + break; + case KEEP_INT: + glVertexAttribIPointer(loc, a->comp_ct, a->comp_type, stride, pointer); + } + } + + batch->program_dirty = false; + } + +void Batch_use_program(Batch* batch) + { + // NOTE: use_program & done_using_program are fragile, depend on staying in sync with + // the GL context's active program. use_program doesn't mark other programs as "not used". + // TODO: make not fragile (somehow) + + if (!batch->program_in_use) + { + glUseProgram(batch->program); + batch->program_in_use = true; + } + } + +void Batch_done_using_program(Batch* batch) + { + if (batch->program_in_use) + { + glUseProgram(0); + batch->program_in_use = false; + } + } + +void Batch_Uniform1b(Batch* batch, const char* name, bool value) + { + int loc = glGetUniformLocation(batch->program, name); + +#if TRUST_NO_ONE + assert(loc != -1); +#endif + + glUniform1i(loc, value ? GL_TRUE : GL_FALSE); + } + +void Batch_Uniform2f(Batch* batch, const char* name, float x, float y) + { + int loc = glGetUniformLocation(batch->program, name); + +#if TRUST_NO_ONE + assert(loc != -1); +#endif + + glUniform2f(loc, x, y); + } + +void Batch_Uniform4f(Batch* batch, const char* name, float x, float y, float z, float w) + { + int loc = glGetUniformLocation(batch->program, name); + +#if TRUST_NO_ONE + assert(loc != -1); +#endif + + glUniform4f(loc, x, y, z, w); + } + +void Batch_Uniform1f(Batch* batch, const char* name, float x) + { + int loc = glGetUniformLocation(batch->program, name); + +#if TRUST_NO_ONE + assert(loc != -1); +#endif + + glUniform1f(loc, x); + } + +void Batch_Uniform3fv(Batch* batch, const char* name, const float data[3]) + { + int loc = glGetUniformLocation(batch->program, name); + +#if TRUST_NO_ONE + assert(loc != -1); +#endif + + glUniform3fv(loc, 1, data); + } + +void Batch_Uniform4fv(Batch* batch, const char* name, const float data[4]) + { + int loc = glGetUniformLocation(batch->program, name); + +#if TRUST_NO_ONE + assert(loc != -1); +#endif + + glUniform4fv(loc, 1, data); + } + +static void Batch_prime(Batch* batch) + { + batch->vao_id = vao_id_alloc(); + glBindVertexArray(batch->vao_id); + + VertexBuffer_use(batch->verts); + + if (batch->elem) + ElementList_use(batch->elem); + + // vertex attribs and element list remain bound to this VAO + } + +void Batch_draw(Batch* batch) + { +#if TRUST_NO_ONE + assert(batch->phase == READY_TO_DRAW); + assert(glIsProgram(batch->program)); +#endif + + 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(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, + int attrib_nbr, int attrib_stride, int attrib_size[16], int attrib_loc[16]) +{ + if (batch->vao_id) + glBindVertexArray(batch->vao_id); + else + Batch_prime(batch); + + if (batch->program_dirty) + Batch_update_program_bindings(batch); + + glBindBuffer(GL_ARRAY_BUFFER, instance_vbo); + int ptr_ofs = 0; + for (int i = 0; i < attrib_nbr; ++i) { + int size = attrib_size[i]; + int loc = attrib_loc[i]; + int atr_ofs = 0; + + while (size > 0) { + glEnableVertexAttribArray(loc + atr_ofs); + glVertexAttribPointer(loc + atr_ofs, (size > 4) ? 4 : size, GL_FLOAT, GL_FALSE, + sizeof(float) * attrib_stride, (GLvoid*)(sizeof(float) * ptr_ofs)); + glVertexAttribDivisor(loc + atr_ofs, 1); + atr_ofs++; + ptr_ofs += (size > 4) ? 4 : size; + size -= 4; + } + } + glBindBuffer(GL_ARRAY_BUFFER, 0); + + // 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 new file mode 100644 index 00000000000..660ed9eb762 --- /dev/null +++ b/source/blender/gpu/gawain/batch.h @@ -0,0 +1,104 @@ + +// Gawain geometry batch +// +// This code is part of the Gawain library, with modifications +// specific to integration with Blender. +// +// Copyright 2016 Mike Erwin +// +// This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of +// the MPL was not distributed with this file, You can obtain one at https://mozilla.org/MPL/2.0/. + +#pragma once + +#include "vertex_buffer.h" +#include "element.h" + +typedef enum { + READY_TO_FORMAT, + READY_TO_BUILD, + BUILDING, + READY_TO_DRAW +} BatchPhase; + +typedef struct Batch{ + // geometry + VertexBuffer* verts; + ElementList* elem; // NULL if element list not needed + PrimitiveType prim_type; + + // book-keeping + GLuint vao_id; // remembers all geometry state (vertex attrib bindings & element buffer) + BatchPhase phase; + bool program_dirty; + bool program_in_use; + + // state + GLuint program; +} Batch; + +Batch* Batch_create(PrimitiveType, VertexBuffer*, ElementList*); +void Batch_init(Batch*, PrimitiveType, VertexBuffer*, ElementList*); + +void Batch_discard(Batch*); // verts & elem are not discarded +void Batch_discard_all(Batch*); // including verts & elem + +void Batch_set_program(Batch*, GLuint program); +// Entire batch draws with one shader program, but can be redrawn later with another program. +// Vertex shader's inputs must be compatible with the batch's vertex format. + +void Batch_use_program(Batch*); // call before Batch_Uniform (temp hack?) +void Batch_done_using_program(Batch*); + +void Batch_Uniform1b(Batch*, const char* name, bool value); +void Batch_Uniform1f(Batch*, const char* name, float value); +void Batch_Uniform2f(Batch*, const char* name, float x, float y); +void Batch_Uniform4f(Batch*, const char* name, float x, float y, float z, float w); +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*); + + +// clement : temp stuff +void Batch_draw_stupid(Batch*); +void Batch_draw_stupid_instanced(Batch*, unsigned int instance_vbo, int instance_count, + int attrib_nbr, int attrib_stride, int attrib_loc[16], int attrib_size[16]); + + + + + + +#if 0 // future plans + +// Can multiple batches share a VertexBuffer? Use ref count? + + +// We often need a batch with its own data, to be created and discarded together. +// WithOwn variants reduce number of system allocations. + +typedef struct { + Batch batch; + VertexBuffer verts; // link batch.verts to this +} BatchWithOwnVertexBuffer; + +typedef struct { + Batch batch; + ElementList elem; // link batch.elem to this +} BatchWithOwnElementList; + +typedef struct { + Batch batch; + ElementList elem; // link batch.elem to this + VertexBuffer verts; // link batch.verts to this +} BatchWithOwnVertexBufferAndElementList; + +Batch* create_BatchWithOwnVertexBuffer(PrimitiveType, VertexFormat*, unsigned v_ct, ElementList*); +Batch* create_BatchWithOwnElementList(PrimitiveType, VertexBuffer*, unsigned prim_ct); +Batch* create_BatchWithOwnVertexBufferAndElementList(PrimitiveType, VertexFormat*, unsigned v_ct, unsigned prim_ct); +// verts: shared, own +// elem: none, shared, own +Batch* create_BatchInGeneral(PrimitiveType, VertexBufferStuff, ElementListStuff); + +#endif // future plans diff --git a/source/blender/gpu/gawain/buffer_id.cpp b/source/blender/gpu/gawain/buffer_id.cpp new file mode 100644 index 00000000000..450656c4ebf --- /dev/null +++ b/source/blender/gpu/gawain/buffer_id.cpp @@ -0,0 +1,115 @@ + +// Gawain buffer IDs +// +// This code is part of the Gawain library, with modifications +// specific to integration with Blender. +// +// Copyright 2016 Mike Erwin +// +// This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of +// the MPL was not distributed with this file, You can obtain one at https://mozilla.org/MPL/2.0/.#include "buffer_id.h" + +#include "buffer_id.h" +#include <mutex> +#include <vector> + +#define ORPHAN_DEBUG 0 + +#if ORPHAN_DEBUG + #include <cstdio> +#endif + +static std::vector<GLuint> orphaned_buffer_ids; +static std::vector<GLuint> orphaned_vao_ids; + +static std::mutex orphan_mutex; + +extern "C" { +extern int BLI_thread_is_main(void); // Blender-specific function +} + +static bool thread_is_main() + { + // "main" here means the GL context's thread + return BLI_thread_is_main(); + } + +GLuint buffer_id_alloc() + { +#if TRUST_NO_ONE + assert(thread_is_main()); +#endif + + // delete orphaned IDs + orphan_mutex.lock(); + if (!orphaned_buffer_ids.empty()) + { + const auto orphaned_buffer_ct = (unsigned)orphaned_buffer_ids.size(); +#if ORPHAN_DEBUG + printf("deleting %u orphaned VBO%s\n", orphaned_buffer_ct, orphaned_buffer_ct == 1 ? "" : "s"); +#endif + glDeleteBuffers(orphaned_buffer_ct, orphaned_buffer_ids.data()); + orphaned_buffer_ids.clear(); + } + orphan_mutex.unlock(); + + GLuint new_buffer_id = 0; + glGenBuffers(1, &new_buffer_id); + return new_buffer_id; + } + +void buffer_id_free(GLuint buffer_id) + { + if (thread_is_main()) + glDeleteBuffers(1, &buffer_id); + else + { + // add this ID to the orphaned list + orphan_mutex.lock(); +#if ORPHAN_DEBUG + printf("orphaning VBO %u\n", buffer_id); +#endif + orphaned_buffer_ids.emplace_back(buffer_id); + orphan_mutex.unlock(); + } + } + +GLuint vao_id_alloc() + { +#if TRUST_NO_ONE + assert(thread_is_main()); +#endif + + // delete orphaned IDs + orphan_mutex.lock(); + if (!orphaned_vao_ids.empty()) + { + const auto orphaned_vao_ct = (unsigned)orphaned_vao_ids.size(); +#if ORPHAN_DEBUG + printf("deleting %u orphaned VAO%s\n", orphaned_vao_ct, orphaned_vao_ct == 1 ? "" : "s"); +#endif + glDeleteVertexArrays(orphaned_vao_ct, orphaned_vao_ids.data()); + orphaned_vao_ids.clear(); + } + orphan_mutex.unlock(); + + GLuint new_vao_id = 0; + glGenVertexArrays(1, &new_vao_id); + return new_vao_id; + } + +void vao_id_free(GLuint vao_id) + { + if (thread_is_main()) + glDeleteVertexArrays(1, &vao_id); + else + { + // add this ID to the orphaned list + orphan_mutex.lock(); +#if ORPHAN_DEBUG + printf("orphaning VAO %u\n", vao_id); +#endif + orphaned_vao_ids.emplace_back(vao_id); + orphan_mutex.unlock(); + } + } diff --git a/source/blender/gpu/gawain/buffer_id.h b/source/blender/gpu/gawain/buffer_id.h new file mode 100644 index 00000000000..3f67458d060 --- /dev/null +++ b/source/blender/gpu/gawain/buffer_id.h @@ -0,0 +1,34 @@ + +// Gawain buffer IDs +// +// This code is part of the Gawain library, with modifications +// specific to integration with Blender. +// +// Copyright 2016 Mike Erwin +// +// This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of +// the MPL was not distributed with this file, You can obtain one at https://mozilla.org/MPL/2.0/. + +#pragma once + +// Manage GL buffer IDs in a thread-safe way +// Use these instead of glGenBuffers & its friends +// - alloc must be called from main thread +// - free can be called from any thread + +#ifdef __cplusplus +extern "C" { +#endif + +#include "common.h" + +GLuint buffer_id_alloc(void); +void buffer_id_free(GLuint buffer_id); + +GLuint vao_id_alloc(void); +void vao_id_free(GLuint vao_id); + + +#ifdef __cplusplus +} +#endif diff --git a/source/blender/gpu/gawain/common.h b/source/blender/gpu/gawain/common.h new file mode 100644 index 00000000000..90340b94e4d --- /dev/null +++ b/source/blender/gpu/gawain/common.h @@ -0,0 +1,58 @@ + +// Gawain common #defines and #includes +// +// This code is part of the Gawain library, with modifications +// specific to integration with Blender. +// +// Copyright 2016 Mike Erwin +// +// This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of +// the MPL was not distributed with this file, You can obtain one at https://mozilla.org/MPL/2.0/. + +#pragma once + +// #define TRUST_NO_ONE !defined(NDEBUG) +#define TRUST_NO_ONE 1 +// strict error checking, always enabled during early development + +#include <GL/glew.h> +#include <stdbool.h> +#include <stdint.h> + +#if TRUST_NO_ONE + #include <assert.h> +#endif + +#define PER_THREAD +// #define PER_THREAD __thread +// MSVC uses __declspec(thread) for C code + +#define APPLE_LEGACY (defined(__APPLE__) && defined(WITH_GL_PROFILE_COMPAT)) + +#if APPLE_LEGACY + #undef glGenVertexArrays + #define glGenVertexArrays glGenVertexArraysAPPLE + + #undef glDeleteVertexArrays + #define glDeleteVertexArrays glDeleteVertexArraysAPPLE + + #undef glBindVertexArray + #define glBindVertexArray glBindVertexArrayAPPLE +#endif + +typedef enum { + PRIM_POINTS = GL_POINTS, + PRIM_LINES = GL_LINES, + PRIM_TRIANGLES = GL_TRIANGLES, + +#ifdef WITH_GL_PROFILE_COMPAT + PRIM_QUADS = GL_QUADS, // legacy GL has this, modern GL & Vulkan do not +#endif + + PRIM_LINE_STRIP = GL_LINE_STRIP, + PRIM_LINE_LOOP = GL_LINE_LOOP, // GL has this, Vulkan does not + PRIM_TRIANGLE_STRIP = GL_TRIANGLE_STRIP, + PRIM_TRIANGLE_FAN = GL_TRIANGLE_FAN, + + PRIM_NONE = 0xF +} PrimitiveType; diff --git a/source/blender/gpu/gawain/element.c b/source/blender/gpu/gawain/element.c new file mode 100644 index 00000000000..3c3ca1c7626 --- /dev/null +++ b/source/blender/gpu/gawain/element.c @@ -0,0 +1,283 @@ + +// Gawain element list (AKA index buffer) +// +// This code is part of the Gawain library, with modifications +// specific to integration with Blender. +// +// Copyright 2016 Mike Erwin +// +// This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of +// the MPL was not distributed with this file, You can obtain one at https://mozilla.org/MPL/2.0/. + +#include "element.h" +#include "buffer_id.h" +#include <stdlib.h> + +#define KEEP_SINGLE_COPY 1 + +unsigned ElementList_size(const ElementList* elem) + { +#if TRACK_INDEX_RANGE + switch (elem->index_type) + { + case INDEX_U8: return elem->index_ct * sizeof(GLubyte); + case INDEX_U16: return elem->index_ct * sizeof(GLushort); + case INDEX_U32: return elem->index_ct * sizeof(GLuint); + default: + #if TRUST_NO_ONE + assert(false); + #endif + return 0; + } + +#else + return elem->index_ct * sizeof(GLuint); +#endif + } + +static void ElementList_prime(ElementList* elem) + { + elem->vbo_id = buffer_id_alloc(); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, elem->vbo_id); + // fill with delicious data & send to GPU the first time only + glBufferData(GL_ELEMENT_ARRAY_BUFFER, ElementList_size(elem), elem->data, GL_STATIC_DRAW); + +#if KEEP_SINGLE_COPY + // now that GL has a copy, discard original + free(elem->data); + elem->data = NULL; +#endif + } + +void ElementList_use(ElementList* elem) + { + if (elem->vbo_id) + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, elem->vbo_id); + else + ElementList_prime(elem); + } + +void ElementListBuilder_init(ElementListBuilder* builder, PrimitiveType prim_type, unsigned prim_ct, unsigned vertex_ct) + { + unsigned verts_per_prim = 0; + switch (prim_type) + { + case PRIM_POINTS: + verts_per_prim = 1; + break; + case PRIM_LINES: + verts_per_prim = 2; + break; + case PRIM_TRIANGLES: + verts_per_prim = 3; + break; + default: +#if TRUST_NO_ONE + assert(false); +#endif + return; + } + + builder->max_allowed_index = vertex_ct - 1; + builder->max_index_ct = prim_ct * verts_per_prim; + builder->index_ct = 0; // start empty + builder->prim_type = prim_type; + builder->data = calloc(builder->max_index_ct, sizeof(unsigned)); + } + +void add_generic_vertex(ElementListBuilder* builder, unsigned v) + { +#if TRUST_NO_ONE + assert(builder->data != NULL); + assert(builder->index_ct < builder->max_index_ct); + assert(v <= builder->max_allowed_index); +#endif + + builder->data[builder->index_ct++] = v; + } + +void add_point_vertex(ElementListBuilder* builder, unsigned v) + { +#if TRUST_NO_ONE + assert(builder->prim_type == PRIM_POINTS); +#endif + + add_generic_vertex(builder, v); + } + +void add_line_vertices(ElementListBuilder* builder, unsigned v1, unsigned v2) + { +#if TRUST_NO_ONE + assert(builder->prim_type == PRIM_LINES); + assert(v1 != v2); +#endif + + add_generic_vertex(builder, v1); + add_generic_vertex(builder, v2); + } + +void add_triangle_vertices(ElementListBuilder* builder, unsigned v1, unsigned v2, unsigned v3) + { +#if TRUST_NO_ONE + assert(builder->prim_type == PRIM_TRIANGLES); + assert(v1 != v2 && v2 != v3 && v3 != v1); +#endif + + add_generic_vertex(builder, v1); + add_generic_vertex(builder, v2); + add_generic_vertex(builder, v3); + } + +#if TRACK_INDEX_RANGE +// Everything remains 32 bit while building to keep things simple. +// Find min/max after, then convert to smallest index type possible. + +static unsigned index_range(const unsigned values[], unsigned value_ct, unsigned* min_out, unsigned* max_out) + { + unsigned min_value = values[0]; + unsigned max_value = values[0]; + for (unsigned i = 1; i < value_ct; ++i) + { + const unsigned value = values[i]; + if (value < min_value) + min_value = value; + else if (value > max_value) + max_value = value; + } + *min_out = min_value; + *max_out = max_value; + return max_value - min_value; + } + +static void squeeze_indices_byte(const unsigned values[], ElementList* elem) + { + const unsigned index_ct = elem->index_ct; + GLubyte* data = malloc(index_ct * sizeof(GLubyte)); + + if (elem->max_index > 0xFF) + { + const unsigned base = elem->min_index; + + elem->base_index = base; + elem->min_index = 0; + elem->max_index -= base; + + for (unsigned i = 0; i < index_ct; ++i) + data[i] = (GLubyte)(values[i] - base); + } + else + { + elem->base_index = 0; + + for (unsigned i = 0; i < index_ct; ++i) + data[i] = (GLubyte)(values[i]); + } + + elem->data = data; + } + +static void squeeze_indices_short(const unsigned values[], ElementList* elem) + { + const unsigned index_ct = elem->index_ct; + GLushort* data = malloc(index_ct * sizeof(GLushort)); + + if (elem->max_index > 0xFFFF) + { + const unsigned base = elem->min_index; + + elem->base_index = base; + elem->min_index = 0; + elem->max_index -= base; + + for (unsigned i = 0; i < index_ct; ++i) + data[i] = (GLushort)(values[i] - base); + } + else + { + elem->base_index = 0; + + for (unsigned i = 0; i < index_ct; ++i) + data[i] = (GLushort)(values[i]); + } + + elem->data = data; + } + +#endif // TRACK_INDEX_RANGE + +ElementList* ElementList_build(ElementListBuilder* builder) + { + ElementList* elem = calloc(1, sizeof(ElementList)); + ElementList_build_in_place(builder, elem); + return elem; + } + +void ElementList_build_in_place(ElementListBuilder* builder, ElementList* elem) + { +#if TRUST_NO_ONE + assert(builder->data != NULL); +#endif + + elem->index_ct = builder->index_ct; + +#if TRACK_INDEX_RANGE + const unsigned range = index_range(builder->data, builder->index_ct, &elem->min_index, &elem->max_index); + + if (range <= 0xFF) + { + elem->index_type = INDEX_U8; + squeeze_indices_byte(builder->data, elem); + } + else if (range <= 0xFFFF) + { + elem->index_type = INDEX_U16; + squeeze_indices_short(builder->data, elem); + } + else + { + elem->index_type = INDEX_U32; + elem->base_index = 0; + + if (builder->index_ct < builder->max_index_ct) + { + builder->data = realloc(builder->data, builder->index_ct * sizeof(unsigned)); + // TODO: realloc only if index_ct is much smaller than max_index_ct + } + + elem->data = builder->data; + } +#else + if (builder->index_ct < builder->max_index_ct) + { + builder->data = realloc(builder->data, builder->index_ct * sizeof(unsigned)); + // TODO: realloc only if index_ct is much smaller than max_index_ct + } + + elem->data = builder->data; +#endif + + // elem->data will never be *larger* than builder->data... how about converting + // in place to avoid extra allocation? + + elem->vbo_id = 0; + // TODO: create GL buffer object directly, based on an input flag + + // discard builder (one-time use) + if (builder->data != elem->data) + free(builder->data); + builder->data = NULL; + // other fields are safe to leave + } + +void ElementList_discard(ElementList* elem) + { + if (elem->vbo_id) + buffer_id_free(elem->vbo_id); +#if KEEP_SINGLE_COPY + else +#endif + if (elem->data) + free(elem->data); + + free(elem); + } diff --git a/source/blender/gpu/gawain/element.h b/source/blender/gpu/gawain/element.h new file mode 100644 index 00000000000..4e0d5fb0649 --- /dev/null +++ b/source/blender/gpu/gawain/element.h @@ -0,0 +1,64 @@ + +// Gawain element list (AKA index buffer) +// +// This code is part of the Gawain library, with modifications +// specific to integration with Blender. +// +// Copyright 2016 Mike Erwin +// +// This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of +// the MPL was not distributed with this file, You can obtain one at https://mozilla.org/MPL/2.0/. + +#pragma once + +#include "common.h" + +#define TRACK_INDEX_RANGE 1 + +typedef enum { + INDEX_U8 = GL_UNSIGNED_BYTE, // GL has this, Vulkan does not + INDEX_U16 = GL_UNSIGNED_SHORT, + INDEX_U32 = GL_UNSIGNED_INT +} IndexType; + +typedef struct { + unsigned index_ct; +#if TRACK_INDEX_RANGE + IndexType index_type; + unsigned min_index; + unsigned max_index; + unsigned base_index; +#endif + void* data; // NULL indicates data in VRAM (unmapped) or not yet allocated + GLuint vbo_id; // 0 indicates not yet sent to VRAM +} ElementList; + +void ElementList_use(ElementList*); +unsigned ElementList_size(const ElementList*); + +typedef struct { + unsigned max_allowed_index; + unsigned max_index_ct; + unsigned index_ct; + PrimitiveType prim_type; + unsigned* data; +} ElementListBuilder; + +// supported primitives: +// PRIM_POINTS +// PRIM_LINES +// PRIM_TRIANGLES + +void ElementListBuilder_init(ElementListBuilder*, PrimitiveType, unsigned prim_ct, unsigned vertex_ct); +//void ElementListBuilder_init_custom(ElementListBuilder*, PrimitiveType, unsigned index_ct, unsigned vertex_ct); + +void add_generic_vertex(ElementListBuilder*, unsigned v); + +void add_point_vertex(ElementListBuilder*, unsigned v); +void add_line_vertices(ElementListBuilder*, unsigned v1, unsigned v2); +void add_triangle_vertices(ElementListBuilder*, unsigned v1, unsigned v2, unsigned v3); + +ElementList* ElementList_build(ElementListBuilder*); +void ElementList_build_in_place(ElementListBuilder*, ElementList*); + +void ElementList_discard(ElementList*); diff --git a/source/blender/gpu/gawain/imm_util.c b/source/blender/gpu/gawain/imm_util.c new file mode 100644 index 00000000000..74caeb6fd3a --- /dev/null +++ b/source/blender/gpu/gawain/imm_util.c @@ -0,0 +1,46 @@ + +// Gawain immediate mode drawing utilities +// +// This code is part of the Gawain library, with modifications +// specific to integration with Blender. +// +// Copyright 2016 Mike Erwin +// +// This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of +// the MPL was not distributed with this file, You can obtain one at https://mozilla.org/MPL/2.0/. + +#include "imm_util.h" +#include "immediate.h" + + +void immRectf(unsigned pos, float x1, float y1, float x2, float y2) +{ + immBegin(PRIM_TRIANGLE_FAN, 4); + immVertex2f(pos, x1, y1); + immVertex2f(pos, x2, y1); + immVertex2f(pos, x2, y2); + immVertex2f(pos, x1, y2); + immEnd(); +} + +void immRecti(unsigned pos, int x1, int y1, int x2, int y2) +{ + immBegin(PRIM_TRIANGLE_FAN, 4); + immVertex2i(pos, x1, y1); + immVertex2i(pos, x2, y1); + immVertex2i(pos, x2, y2); + immVertex2i(pos, x1, y2); + immEnd(); +} + +#if 0 // more complete version in case we want that +void immRecti_complete(int x1, int y1, int x2, int y2, const float color[4]) +{ + VertexFormat *format = immVertexFormat(); + unsigned pos = add_attrib(format, "pos", COMP_I32, 2, CONVERT_INT_TO_FLOAT); + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + immUniformColor4fv(color); + immRecti(pos, x1, y1, x2, y2); + immUnbindProgram(); +} +#endif diff --git a/source/blender/gpu/gawain/imm_util.h b/source/blender/gpu/gawain/imm_util.h new file mode 100644 index 00000000000..730bd7c1a3c --- /dev/null +++ b/source/blender/gpu/gawain/imm_util.h @@ -0,0 +1,18 @@ + +// Gawain immediate mode drawing utilities +// +// This code is part of the Gawain library, with modifications +// specific to integration with Blender. +// +// Copyright 2016 Mike Erwin +// +// This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of +// the MPL was not distributed with this file, You can obtain one at https://mozilla.org/MPL/2.0/. + +#pragma once + + +// Draw 2D rectangles (replaces glRect functions) +// caller is reponsible for vertex format & shader +void immRectf(unsigned pos, float x1, float y1, float x2, float y2); +void immRecti(unsigned pos, int x1, int y1, int x2, int y2); diff --git a/source/blender/gpu/gawain/immediate.c b/source/blender/gpu/gawain/immediate.c new file mode 100644 index 00000000000..cda0e98ac29 --- /dev/null +++ b/source/blender/gpu/gawain/immediate.c @@ -0,0 +1,880 @@ + +// Gawain immediate mode work-alike +// +// This code is part of the Gawain library, with modifications +// specific to integration with Blender. +// +// Copyright 2016 Mike Erwin +// +// This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of +// the MPL was not distributed with this file, You can obtain one at https://mozilla.org/MPL/2.0/. + +#include "immediate.h" +#include "attrib_binding.h" +#include "buffer_id.h" +#include <string.h> + +// necessary functions from matrix API +extern void gpuBindMatrices(GLuint program); +extern bool gpuMatricesDirty(void); + +typedef struct { + // TODO: organize this struct by frequency of change (run-time) + +#if IMM_BATCH_COMBO + Batch* batch; +#endif + + // current draw call + GLubyte* buffer_data; + unsigned buffer_offset; + unsigned buffer_bytes_mapped; + unsigned vertex_ct; + bool strict_vertex_ct; + PrimitiveType prim_type; + + VertexFormat vertex_format; + + // current vertex + unsigned vertex_idx; + GLubyte* vertex_data; + uint16_t unassigned_attrib_bits; // which attributes of current vertex have not been given values? + + GLuint vbo_id; + GLuint vao_id; + + GLuint bound_program; + AttribBinding attrib_binding; + uint16_t prev_enabled_attrib_bits; // <-- only affects this VAO, so we're ok +} Immediate; + +// size of internal buffer -- make this adjustable? +#define IMM_BUFFER_SIZE (4 * 1024 * 1024) + +static PER_THREAD bool initialized = false; +static PER_THREAD Immediate imm; + +void immInit(void) + { +#if TRUST_NO_ONE + assert(!initialized); +#endif + + memset(&imm, 0, sizeof(Immediate)); + + imm.vbo_id = buffer_id_alloc(); + glBindBuffer(GL_ARRAY_BUFFER, imm.vbo_id); + glBufferData(GL_ARRAY_BUFFER, IMM_BUFFER_SIZE, NULL, GL_DYNAMIC_DRAW); + +#if APPLE_LEGACY + glBufferParameteriAPPLE(GL_ARRAY_BUFFER, GL_BUFFER_SERIALIZED_MODIFY_APPLE, GL_FALSE); + glBufferParameteriAPPLE(GL_ARRAY_BUFFER, GL_BUFFER_FLUSHING_UNMAP_APPLE, GL_FALSE); +#endif + + imm.prim_type = PRIM_NONE; + imm.strict_vertex_ct = true; + + glBindBuffer(GL_ARRAY_BUFFER, 0); + initialized = true; + + immActivate(); + } + +void immActivate(void) + { +#if TRUST_NO_ONE + assert(initialized); + assert(imm.prim_type == PRIM_NONE); // make sure we're not between a Begin/End pair + assert(imm.vao_id == 0); +#endif + + imm.vao_id = vao_id_alloc(); + } + +void immDeactivate(void) + { +#if TRUST_NO_ONE + assert(initialized); + assert(imm.prim_type == PRIM_NONE); // make sure we're not between a Begin/End pair + assert(imm.vao_id != 0); +#endif + + vao_id_free(imm.vao_id); + imm.vao_id = 0; + imm.prev_enabled_attrib_bits = 0; + } + +void immDestroy(void) + { + immDeactivate(); + buffer_id_free(imm.vbo_id); + initialized = false; + } + +VertexFormat* immVertexFormat(void) + { + VertexFormat_clear(&imm.vertex_format); + return &imm.vertex_format; + } + +void immBindProgram(GLuint program) + { +#if TRUST_NO_ONE + assert(imm.bound_program == 0); + assert(glIsProgram(program)); +#endif + + if (!imm.vertex_format.packed) + VertexFormat_pack(&imm.vertex_format); + + glUseProgram(program); + get_attrib_locations(&imm.vertex_format, &imm.attrib_binding, program); + imm.bound_program = program; + + gpuBindMatrices(program); + } + +void immUnbindProgram(void) + { +#if TRUST_NO_ONE + assert(imm.bound_program != 0); +#endif + + glUseProgram(0); + imm.bound_program = 0; + } + +static bool vertex_count_makes_sense_for_primitive(unsigned vertex_ct, PrimitiveType prim_type) + { + // does vertex_ct make sense for this primitive type? + if (vertex_ct == 0) + return false; + + switch (prim_type) + { + case PRIM_POINTS: + return true; + case PRIM_LINES: + return vertex_ct % 2 == 0; + case PRIM_LINE_STRIP: + case PRIM_LINE_LOOP: + return vertex_ct >= 2; + case PRIM_TRIANGLES: + return vertex_ct % 3 == 0; + case PRIM_TRIANGLE_STRIP: + case PRIM_TRIANGLE_FAN: + return vertex_ct >= 3; + #ifdef WITH_GL_PROFILE_COMPAT + case PRIM_QUADS: + return vertex_ct % 4 == 0; + #endif + default: + return false; + } + } + +void immBegin(PrimitiveType prim_type, unsigned vertex_ct) + { +#if TRUST_NO_ONE + assert(initialized); + assert(imm.prim_type == PRIM_NONE); // make sure we haven't already begun + assert(vertex_count_makes_sense_for_primitive(vertex_ct, prim_type)); +#endif + + imm.prim_type = prim_type; + imm.vertex_ct = vertex_ct; + imm.vertex_idx = 0; + imm.unassigned_attrib_bits = imm.attrib_binding.enabled_bits; + + // how many bytes do we need for this draw call? + const unsigned bytes_needed = vertex_buffer_size(&imm.vertex_format, vertex_ct); + +#if TRUST_NO_ONE + assert(bytes_needed <= IMM_BUFFER_SIZE); +#endif + + glBindBuffer(GL_ARRAY_BUFFER, imm.vbo_id); + + // does the current buffer have enough room? + const unsigned available_bytes = IMM_BUFFER_SIZE - imm.buffer_offset; + // ensure vertex data is aligned + const unsigned pre_padding = padding(imm.buffer_offset, imm.vertex_format.stride); // might waste a little space, but it's safe + if ((bytes_needed + pre_padding) <= available_bytes) + imm.buffer_offset += pre_padding; + else + { + // orphan this buffer & start with a fresh one +#if APPLE_LEGACY + glBufferData(GL_ARRAY_BUFFER, IMM_BUFFER_SIZE, NULL, GL_DYNAMIC_DRAW); +#else + if (GLEW_VERSION_4_3 || GLEW_ARB_invalidate_subdata) + glInvalidateBufferData(imm.vbo_id); + else + glMapBufferRange(GL_ARRAY_BUFFER, 0, IMM_BUFFER_SIZE, GL_MAP_INVALIDATE_BUFFER_BIT); +#endif + + imm.buffer_offset = 0; + } + +// printf("mapping %u to %u\n", imm.buffer_offset, imm.buffer_offset + bytes_needed - 1); + +#if APPLE_LEGACY + imm.buffer_data = glMapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY) + imm.buffer_offset; +#else + imm.buffer_data = glMapBufferRange(GL_ARRAY_BUFFER, imm.buffer_offset, bytes_needed, + GL_MAP_WRITE_BIT | GL_MAP_UNSYNCHRONIZED_BIT | (imm.strict_vertex_ct ? 0 : GL_MAP_FLUSH_EXPLICIT_BIT)); +#endif + +#if TRUST_NO_ONE + assert(imm.buffer_data != NULL); +#endif + + imm.buffer_bytes_mapped = bytes_needed; + imm.vertex_data = imm.buffer_data; + } + +void immBeginAtMost(PrimitiveType prim_type, unsigned vertex_ct) + { +#if TRUST_NO_ONE + assert(vertex_ct > 0); +#endif + + imm.strict_vertex_ct = false; + immBegin(prim_type, vertex_ct); + } + +#if IMM_BATCH_COMBO + +Batch* immBeginBatch(PrimitiveType prim_type, unsigned vertex_ct) + { +#if TRUST_NO_ONE + assert(initialized); + assert(imm.prim_type == PRIM_NONE); // make sure we haven't already begun + assert(vertex_count_makes_sense_for_primitive(vertex_ct, prim_type)); +#endif + + imm.prim_type = prim_type; + imm.vertex_ct = vertex_ct; + imm.vertex_idx = 0; + imm.unassigned_attrib_bits = imm.attrib_binding.enabled_bits; + + VertexBuffer* verts = VertexBuffer_create_with_format(&imm.vertex_format); + VertexBuffer_allocate_data(verts, vertex_ct); + + imm.buffer_bytes_mapped = VertexBuffer_size(verts); + imm.vertex_data = verts->data; + + imm.batch = Batch_create(prim_type, verts, NULL); + imm.batch->phase = BUILDING; + + Batch_set_program(imm.batch, imm.bound_program); + + return imm.batch; + } + +Batch* immBeginBatchAtMost(PrimitiveType prim_type, unsigned vertex_ct) + { + imm.strict_vertex_ct = false; + return immBeginBatch(prim_type, vertex_ct); + } + +#endif // IMM_BATCH_COMBO + +static void immDrawSetup(void) + { + // set up VAO -- can be done during Begin or End really + glBindVertexArray(imm.vao_id); + + // enable/disable vertex attribs as needed + if (imm.attrib_binding.enabled_bits != imm.prev_enabled_attrib_bits) + { + for (unsigned loc = 0; loc < MAX_VERTEX_ATTRIBS; ++loc) + { + bool is_enabled = imm.attrib_binding.enabled_bits & (1 << loc); + bool was_enabled = imm.prev_enabled_attrib_bits & (1 << loc); + + if (is_enabled && !was_enabled) + { +// printf("enabling attrib %u\n", loc); + glEnableVertexAttribArray(loc); + } + else if (was_enabled && !is_enabled) + { +// printf("disabling attrib %u\n", loc); + glDisableVertexAttribArray(loc); + } + } + + imm.prev_enabled_attrib_bits = imm.attrib_binding.enabled_bits; + } + + const unsigned stride = imm.vertex_format.stride; + + for (unsigned a_idx = 0; a_idx < imm.vertex_format.attrib_ct; ++a_idx) + { + const Attrib* a = imm.vertex_format.attribs + a_idx; + + const unsigned offset = imm.buffer_offset + a->offset; + const GLvoid* pointer = (const GLubyte*)0 + offset; + + const unsigned loc = read_attrib_location(&imm.attrib_binding, a_idx); + +// printf("specifying attrib %u '%s' with offset %u, stride %u\n", loc, a->name, offset, stride); + + switch (a->fetch_mode) + { + case KEEP_FLOAT: + case CONVERT_INT_TO_FLOAT: + glVertexAttribPointer(loc, a->comp_ct, a->comp_type, GL_FALSE, stride, pointer); + break; + case NORMALIZE_INT_TO_FLOAT: + glVertexAttribPointer(loc, a->comp_ct, a->comp_type, GL_TRUE, stride, pointer); + break; + case KEEP_INT: + glVertexAttribIPointer(loc, a->comp_ct, a->comp_type, stride, pointer); + } + } + + if (gpuMatricesDirty()) + gpuBindMatrices(imm.bound_program); + } + +void immEnd(void) + { +#if TRUST_NO_ONE + assert(imm.prim_type != PRIM_NONE); // make sure we're between a Begin/End pair +#endif + + unsigned buffer_bytes_used; + if (imm.strict_vertex_ct) + { +#if TRUST_NO_ONE + assert(imm.vertex_idx == imm.vertex_ct); // with all vertices defined +#endif + buffer_bytes_used = imm.buffer_bytes_mapped; + } + else + { +#if TRUST_NO_ONE + assert(imm.vertex_idx <= imm.vertex_ct); +#endif + // printf("used %u of %u verts,", imm.vertex_idx, imm.vertex_ct); + if (imm.vertex_idx == imm.vertex_ct) + { + buffer_bytes_used = imm.buffer_bytes_mapped; + } + else + { +#if TRUST_NO_ONE + assert(imm.vertex_idx == 0 || vertex_count_makes_sense_for_primitive(imm.vertex_idx, imm.prim_type)); +#endif + imm.vertex_ct = imm.vertex_idx; + buffer_bytes_used = vertex_buffer_size(&imm.vertex_format, imm.vertex_ct); + // unused buffer bytes are available to the next immBegin + // printf(" %u of %u bytes\n", buffer_bytes_used, imm.buffer_bytes_mapped); + } +#if !APPLE_LEGACY + // tell OpenGL what range was modified so it doesn't copy the whole mapped range + // printf("flushing %u to %u\n", imm.buffer_offset, imm.buffer_offset + buffer_bytes_used - 1); + glFlushMappedBufferRange(GL_ARRAY_BUFFER, 0, buffer_bytes_used); +#endif + } + +#if IMM_BATCH_COMBO + if (imm.batch) + { + if (buffer_bytes_used != imm.buffer_bytes_mapped) + { + VertexBuffer_resize_data(imm.batch->verts, imm.vertex_ct); + // TODO: resize only if vertex count is much smaller + } + + imm.batch->phase = READY_TO_DRAW; + imm.batch = NULL; // don't free, batch belongs to caller + } + else +#endif + { +#if APPLE_LEGACY + // tell OpenGL what range was modified so it doesn't copy the whole buffer + // printf("flushing %u to %u\n", imm.buffer_offset, imm.buffer_offset + buffer_bytes_used - 1); + glFlushMappedBufferRangeAPPLE(GL_ARRAY_BUFFER, imm.buffer_offset, buffer_bytes_used); +#endif + glUnmapBuffer(GL_ARRAY_BUFFER); + + if (imm.vertex_ct > 0) + { + immDrawSetup(); + glDrawArrays(imm.prim_type, 0, imm.vertex_ct); + } + + glBindBuffer(GL_ARRAY_BUFFER, 0); + glBindVertexArray(0); + + // prep for next immBegin + imm.buffer_offset += buffer_bytes_used; + } + + // prep for next immBegin + imm.prim_type = PRIM_NONE; + imm.strict_vertex_ct = true; + } + +static void setAttribValueBit(unsigned attrib_id) + { + uint16_t mask = 1 << attrib_id; + +#if TRUST_NO_ONE + assert(imm.unassigned_attrib_bits & mask); // not already set +#endif + + imm.unassigned_attrib_bits &= ~mask; + } + + +// --- generic attribute functions --- + +void immAttrib1f(unsigned attrib_id, float x) + { + Attrib* attrib = imm.vertex_format.attribs + attrib_id; + +#if TRUST_NO_ONE + assert(attrib_id < imm.vertex_format.attrib_ct); + assert(attrib->comp_type == COMP_F32); + assert(attrib->comp_ct == 1); + assert(imm.vertex_idx < imm.vertex_ct); + assert(imm.prim_type != PRIM_NONE); // make sure we're between a Begin/End pair +#endif + + setAttribValueBit(attrib_id); + + float* data = (float*)(imm.vertex_data + attrib->offset); +// printf("%s %td %p\n", __FUNCTION__, (GLubyte*)data - imm.buffer_data, data); + + data[0] = x; + } + +void immAttrib2f(unsigned attrib_id, float x, float y) + { + Attrib* attrib = imm.vertex_format.attribs + attrib_id; + +#if TRUST_NO_ONE + assert(attrib_id < imm.vertex_format.attrib_ct); + assert(attrib->comp_type == COMP_F32); + assert(attrib->comp_ct == 2); + assert(imm.vertex_idx < imm.vertex_ct); + assert(imm.prim_type != PRIM_NONE); // make sure we're between a Begin/End pair +#endif + + setAttribValueBit(attrib_id); + + float* data = (float*)(imm.vertex_data + attrib->offset); +// printf("%s %td %p\n", __FUNCTION__, (GLubyte*)data - imm.buffer_data, data); + + data[0] = x; + data[1] = y; + } + +void immAttrib3f(unsigned attrib_id, float x, float y, float z) + { + Attrib* attrib = imm.vertex_format.attribs + attrib_id; + +#if TRUST_NO_ONE + assert(attrib_id < imm.vertex_format.attrib_ct); + assert(attrib->comp_type == COMP_F32); + assert(attrib->comp_ct == 3); + assert(imm.vertex_idx < imm.vertex_ct); + assert(imm.prim_type != PRIM_NONE); // make sure we're between a Begin/End pair +#endif + + setAttribValueBit(attrib_id); + + float* data = (float*)(imm.vertex_data + attrib->offset); +// printf("%s %td %p\n", __FUNCTION__, (GLubyte*)data - imm.buffer_data, data); + + data[0] = x; + data[1] = y; + data[2] = z; + } + +void immAttrib4f(unsigned attrib_id, float x, float y, float z, float w) + { + Attrib* attrib = imm.vertex_format.attribs + attrib_id; + +#if TRUST_NO_ONE + assert(attrib_id < imm.vertex_format.attrib_ct); + assert(attrib->comp_type == COMP_F32); + assert(attrib->comp_ct == 4); + assert(imm.vertex_idx < imm.vertex_ct); + assert(imm.prim_type != PRIM_NONE); // make sure we're between a Begin/End pair +#endif + + setAttribValueBit(attrib_id); + + float* data = (float*)(imm.vertex_data + attrib->offset); +// printf("%s %td %p\n", __FUNCTION__, (GLubyte*)data - imm.buffer_data, data); + + data[0] = x; + data[1] = y; + data[2] = z; + data[3] = w; + } + +void immAttrib2i(unsigned attrib_id, int x, int y) + { + Attrib* attrib = imm.vertex_format.attribs + attrib_id; + +#if TRUST_NO_ONE + assert(attrib_id < imm.vertex_format.attrib_ct); + assert(attrib->comp_type == COMP_I32); + assert(attrib->comp_ct == 2); + assert(imm.vertex_idx < imm.vertex_ct); + assert(imm.prim_type != PRIM_NONE); // make sure we're between a Begin/End pair +#endif + + setAttribValueBit(attrib_id); + + int* data = (int*)(imm.vertex_data + attrib->offset); + + data[0] = x; + data[1] = y; + } + +void immAttrib2s(unsigned attrib_id, short x, short y) + { + Attrib* attrib = imm.vertex_format.attribs + attrib_id; + +#if TRUST_NO_ONE + assert(attrib_id < imm.vertex_format.attrib_ct); + assert(attrib->comp_type == COMP_I16); + assert(attrib->comp_ct == 2); + assert(imm.vertex_idx < imm.vertex_ct); + assert(imm.prim_type != PRIM_NONE); // make sure we're between a Begin/End pair +#endif + + setAttribValueBit(attrib_id); + + short* data = (short*)(imm.vertex_data + attrib->offset); + + data[0] = x; + data[1] = y; + } + +void immAttrib3fv(unsigned attrib_id, const float data[3]) + { + immAttrib3f(attrib_id, data[0], data[1], data[2]); + } + +void immAttrib4fv(unsigned attrib_id, const float data[4]) + { + immAttrib4f(attrib_id, data[0], data[1], data[2], data[3]); + } + +void immAttrib3ub(unsigned attrib_id, unsigned char r, unsigned char g, unsigned char b) + { + Attrib* attrib = imm.vertex_format.attribs + attrib_id; + +#if TRUST_NO_ONE + assert(attrib_id < imm.vertex_format.attrib_ct); + assert(attrib->comp_type == COMP_U8); + assert(attrib->comp_ct == 3); + assert(imm.vertex_idx < imm.vertex_ct); + assert(imm.prim_type != PRIM_NONE); // make sure we're between a Begin/End pair +#endif + + setAttribValueBit(attrib_id); + + GLubyte* data = imm.vertex_data + attrib->offset; +// printf("%s %td %p\n", __FUNCTION__, data - imm.buffer_data, data); + + data[0] = r; + data[1] = g; + data[2] = b; + } + +void immAttrib4ub(unsigned attrib_id, unsigned char r, unsigned char g, unsigned char b, unsigned char a) + { + Attrib* attrib = imm.vertex_format.attribs + attrib_id; + +#if TRUST_NO_ONE + assert(attrib_id < imm.vertex_format.attrib_ct); + assert(attrib->comp_type == COMP_U8); + assert(attrib->comp_ct == 4); + assert(imm.vertex_idx < imm.vertex_ct); + assert(imm.prim_type != PRIM_NONE); // make sure we're between a Begin/End pair +#endif + + setAttribValueBit(attrib_id); + + GLubyte* data = imm.vertex_data + attrib->offset; +// printf("%s %td %p\n", __FUNCTION__, data - imm.buffer_data, data); + + data[0] = r; + data[1] = g; + data[2] = b; + data[3] = a; + } + +void immAttrib3ubv(unsigned attrib_id, const unsigned char data[3]) + { + immAttrib3ub(attrib_id, data[0], data[1], data[2]); + } + +void immAttrib4ubv(unsigned attrib_id, const unsigned char data[4]) + { + immAttrib4ub(attrib_id, data[0], data[1], data[2], data[3]); + } + +void immSkipAttrib(unsigned attrib_id) + { +#if TRUST_NO_ONE + assert(attrib_id < imm.vertex_format.attrib_ct); + assert(imm.vertex_idx < imm.vertex_ct); + assert(imm.prim_type != PRIM_NONE); // make sure we're between a Begin/End pair +#endif + + setAttribValueBit(attrib_id); + } + +static void immEndVertex(void) // and move on to the next vertex + { +#if TRUST_NO_ONE + assert(imm.prim_type != PRIM_NONE); // make sure we're between a Begin/End pair + assert(imm.vertex_idx < imm.vertex_ct); +#endif + + // have all attribs been assigned values? + // if not, copy value from previous vertex + if (imm.unassigned_attrib_bits) + { +#if TRUST_NO_ONE + assert(imm.vertex_idx > 0); // first vertex must have all attribs specified +#endif + + for (unsigned a_idx = 0; a_idx < imm.vertex_format.attrib_ct; ++a_idx) + { + if ((imm.unassigned_attrib_bits >> a_idx) & 1) + { + const Attrib* a = imm.vertex_format.attribs + a_idx; + +// printf("copying %s from vertex %u to %u\n", a->name, imm.vertex_idx - 1, imm.vertex_idx); + + GLubyte* data = imm.vertex_data + a->offset; + memcpy(data, data - imm.vertex_format.stride, a->sz); + // TODO: consolidate copy of adjacent attributes + } + } + } + + imm.vertex_idx++; + imm.vertex_data += imm.vertex_format.stride; + imm.unassigned_attrib_bits = imm.attrib_binding.enabled_bits; + } + +void immVertex2f(unsigned attrib_id, float x, float y) + { + immAttrib2f(attrib_id, x, y); + immEndVertex(); + } + +void immVertex3f(unsigned attrib_id, float x, float y, float z) + { + immAttrib3f(attrib_id, x, y, z); + immEndVertex(); + } + +void immVertex2i(unsigned attrib_id, int x, int y) + { + immAttrib2i(attrib_id, x, y); + immEndVertex(); + } + +void immVertex2s(unsigned attrib_id, short x, short y) + { + immAttrib2s(attrib_id, x, y); + immEndVertex(); + } + +void immVertex2fv(unsigned attrib_id, const float data[2]) + { + immAttrib2f(attrib_id, data[0], data[1]); + immEndVertex(); + } + +void immVertex3fv(unsigned attrib_id, const float data[3]) + { + immAttrib3f(attrib_id, data[0], data[1], data[2]); + immEndVertex(); + } + +void immVertex2iv(unsigned attrib_id, const int data[2]) + { + immAttrib2i(attrib_id, data[0], data[1]); + immEndVertex(); + } + + +// --- generic uniform functions --- + +void immUniform1f(const char* name, float x) + { + int loc = glGetUniformLocation(imm.bound_program, name); + +#if TRUST_NO_ONE + assert(loc != -1); +#endif + + glUniform1f(loc, x); + } + +void immUniform2f(const char* name, float x, float y) +{ + int loc = glGetUniformLocation(imm.bound_program, name); + +#if TRUST_NO_ONE + assert(loc != -1); +#endif + + glUniform2f(loc, x, y); +} + +void immUniform2fv(const char* name, const float data[2]) +{ + int loc = glGetUniformLocation(imm.bound_program, name); + +#if TRUST_NO_ONE + assert(loc != -1); +#endif + + glUniform2fv(loc, 1, data); +} + +void immUniform3f(const char* name, float x, float y, float z) + { + int loc = glGetUniformLocation(imm.bound_program, name); + +#if TRUST_NO_ONE + assert(loc != -1); +#endif + + glUniform3f(loc, x, y, z); + } + +void immUniform3fv(const char* name, const float data[3]) + { + int loc = glGetUniformLocation(imm.bound_program, name); + +#if TRUST_NO_ONE + assert(loc != -1); +#endif + + glUniform3fv(loc, 1, data); + } + +void immUniformArray3fv(const char* name, const float *data, int count) + { + int loc = glGetUniformLocation(imm.bound_program, name); + +#if TRUST_NO_ONE + assert(loc != -1); + assert(count > 0); +#endif + + glUniform3fv(loc, count, data); + } + +void immUniform4f(const char* name, float x, float y, float z, float w) + { + int loc = glGetUniformLocation(imm.bound_program, name); + +#if TRUST_NO_ONE + assert(loc != -1); +#endif + + glUniform4f(loc, x, y, z, w); + } + +void immUniform4fv(const char* name, const float data[4]) + { + int loc = glGetUniformLocation(imm.bound_program, name); + +#if TRUST_NO_ONE + assert(loc != -1); +#endif + + glUniform4fv(loc, 1, data); + } + +void immUniformMatrix4fv(const char* name, const float data[4][4]) + { + int loc = glGetUniformLocation(imm.bound_program, name); + +#if TRUST_NO_ONE + assert(loc != -1); +#endif + + glUniformMatrix4fv(loc, 1, GL_FALSE, (float *)data); + } + +void immUniform1i(const char* name, int x) + { + int loc = glGetUniformLocation(imm.bound_program, name); + +#if TRUST_NO_ONE + assert(loc != -1); +#endif + + glUniform1i(loc, x); + } + + +// --- convenience functions for setting "uniform vec4 color" --- + +void immUniformColor4f(float r, float g, float b, float a) + { + immUniform4f("color", r, g, b, a); + } + +void immUniformColor4fv(const float rgba[4]) + { + immUniform4fv("color", rgba); + } + +void immUniformColor3f(float r, float g, float b) + { + immUniform4f("color", r, g, b, 1.0f); + } + +void immUniformColor3fv(const float rgb[3]) + { + immUniform4f("color", rgb[0], rgb[1], rgb[2], 1.0f); + } + +void immUniformColor3fvAlpha(const float rgb[3], float a) + { + immUniform4f("color", rgb[0], rgb[1], rgb[2], a); + } + +// TODO: v-- treat as sRGB? --v + +void immUniformColor3ub(unsigned char r, unsigned char g, unsigned char b) + { + const float scale = 1.0f / 255.0f; + immUniform4f("color", scale * r, scale * g, scale * b, 1.0f); + } + +void immUniformColor4ub(unsigned char r, unsigned char g, unsigned char b, unsigned char a) + { + const float scale = 1.0f / 255.0f; + immUniform4f("color", scale * r, scale * g, scale * b, scale * a); + } + +void immUniformColor3ubv(const unsigned char rgb[3]) + { + immUniformColor3ub(rgb[0], rgb[1], rgb[2]); + } + +void immUniformColor4ubv(const unsigned char rgba[4]) + { + immUniformColor4ub(rgba[0], rgba[1], rgba[2], rgba[3]); + } diff --git a/source/blender/gpu/gawain/immediate.h b/source/blender/gpu/gawain/immediate.h new file mode 100644 index 00000000000..1e5729e5cce --- /dev/null +++ b/source/blender/gpu/gawain/immediate.h @@ -0,0 +1,111 @@ + +// Gawain immediate mode work-alike +// +// This code is part of the Gawain library, with modifications +// specific to integration with Blender. +// +// Copyright 2016 Mike Erwin +// +// This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of +// the MPL was not distributed with this file, You can obtain one at https://mozilla.org/MPL/2.0/. + +#pragma once + +#include "vertex_format.h" + +#define IMM_BATCH_COMBO 1 + + +VertexFormat* immVertexFormat(void); // returns a cleared vertex format, ready for add_attrib + +void immBindProgram(GLuint program); // every immBegin must have a program bound first +void immUnbindProgram(void); // call after your last immEnd, or before binding another program + +void immBegin(PrimitiveType, unsigned vertex_ct); // must supply exactly vertex_ct vertices +void immBeginAtMost(PrimitiveType, unsigned max_vertex_ct); // can supply fewer vertices +void immEnd(void); // finishes and draws + +#if IMM_BATCH_COMBO +#include "batch.h" +// immBegin a batch, then use standard immFunctions as usual. +// immEnd will finalize the batch instead of drawing. +// Then you can draw it as many times as you like! Partially replaces the need for display lists. +Batch* immBeginBatch(PrimitiveType, unsigned vertex_ct); +Batch* immBeginBatchAtMost(PrimitiveType, unsigned vertex_ct); +#endif + + +// provide attribute values that can change per vertex +// first vertex after immBegin must have all its attributes specified +// skipped attributes will continue using the previous value for that attrib_id +void immAttrib1f(unsigned attrib_id, float x); +void immAttrib2f(unsigned attrib_id, float x, float y); +void immAttrib3f(unsigned attrib_id, float x, float y, float z); +void immAttrib4f(unsigned attrib_id, float x, float y, float z, float w); + +void immAttrib2i(unsigned attrib_id, int x, int y); + +void immAttrib2s(unsigned attrib_id, short x, short y); + +void immAttrib3fv(unsigned attrib_id, const float data[3]); +void immAttrib4fv(unsigned attrib_id, const float data[4]); + +void immAttrib3ub(unsigned attrib_id, unsigned char r, unsigned char g, unsigned char b); +void immAttrib4ub(unsigned attrib_id, unsigned char r, unsigned char g, unsigned char b, unsigned char a); + +void immAttrib3ubv(unsigned attrib_id, const unsigned char data[4]); +void immAttrib4ubv(unsigned attrib_id, const unsigned char data[4]); + +// explicitly skip an attribute +// this advanced option kills automatic value copying for this attrib_id +void immSkipAttrib(unsigned attrib_id); + + +// provide one last attribute value & end the current vertex +// this is most often used for 2D or 3D position (similar to glVertex) +void immVertex2f(unsigned attrib_id, float x, float y); +void immVertex3f(unsigned attrib_id, float x, float y, float z); + +void immVertex2i(unsigned attrib_id, int x, int y); + +void immVertex2s(unsigned attrib_id, short x, short y); + +void immVertex2fv(unsigned attrib_id, const float data[2]); +void immVertex3fv(unsigned attrib_id, const float data[3]); + +void immVertex2iv(unsigned attrib_id, const int data[2]); + + +// provide uniform values that don't change for the entire draw call +void immUniform1i(const char* name, int x); +void immUniform1f(const char* name, float x); +void immUniform2f(const char* name, float x, float y); +void immUniform2fv(const char* name, const float data[2]); +void immUniform3f(const char* name, float x, float y, float z); +void immUniform3fv(const char* name, const float data[3]); +void immUniformArray3fv(const char* name, const float *data, int count); +void immUniform4f(const char* name, float x, float y, float z, float w); +void immUniform4fv(const char* name, const float data[4]); +void immUniformMatrix4fv(const char* name, const float data[4][4]); + + +// convenience functions for setting "uniform vec4 color" +// the rgb functions have implicit alpha = 1.0 +void immUniformColor4f(float r, float g, float b, float a); +void immUniformColor4fv(const float rgba[4]); +void immUniformColor3f(float r, float g, float b); +void immUniformColor3fv(const float rgb[3]); +void immUniformColor3fvAlpha(const float rgb[3], float a); + +void immUniformColor3ub(unsigned char r, unsigned char g, unsigned char b); +void immUniformColor4ub(unsigned char r, unsigned char g, unsigned char b, unsigned char a); +void immUniformColor3ubv(const unsigned char rgb[3]); +void immUniformColor4ubv(const unsigned char rgba[4]); + + +// these are called by the system -- not part of drawing API + +void immInit(void); +void immActivate(void); +void immDeactivate(void); +void immDestroy(void); diff --git a/source/blender/gpu/gawain/vertex_buffer.c b/source/blender/gpu/gawain/vertex_buffer.c new file mode 100644 index 00000000000..827703403e3 --- /dev/null +++ b/source/blender/gpu/gawain/vertex_buffer.c @@ -0,0 +1,170 @@ + +// Gawain geometry batch +// +// This code is part of the Gawain library, with modifications +// specific to integration with Blender. +// +// Copyright 2016 Mike Erwin +// +// This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of +// the MPL was not distributed with this file, You can obtain one at https://mozilla.org/MPL/2.0/. + +#include "vertex_buffer.h" +#include "buffer_id.h" +#include <stdlib.h> +#include <string.h> + +#define KEEP_SINGLE_COPY 1 + +VertexBuffer* VertexBuffer_create(void) + { + VertexBuffer* verts = malloc(sizeof(VertexBuffer)); + VertexBuffer_init(verts); + return verts; + } + +VertexBuffer* VertexBuffer_create_with_format(const VertexFormat* format) + { + VertexBuffer* verts = VertexBuffer_create(); + VertexFormat_copy(&verts->format, format); + if (!format->packed) + VertexFormat_pack(&verts->format); + return verts; + + // this function might seem redundant, but there is potential for memory savings here... + // TODO: implement those memory savings + } + +void VertexBuffer_init(VertexBuffer* verts) + { + memset(verts, 0, sizeof(VertexBuffer)); + } + +void VertexBuffer_init_with_format(VertexBuffer* verts, const VertexFormat* format) + { + VertexBuffer_init(verts); + VertexFormat_copy(&verts->format, format); + if (!format->packed) + VertexFormat_pack(&verts->format); + } + +void VertexBuffer_discard(VertexBuffer* verts) + { + if (verts->vbo_id) + buffer_id_free(verts->vbo_id); +#if KEEP_SINGLE_COPY + else +#endif + if (verts->data) + free(verts->data); + + free(verts); + } + +unsigned VertexBuffer_size(const VertexBuffer* verts) + { + return vertex_buffer_size(&verts->format, verts->vertex_ct); + } + +void VertexBuffer_allocate_data(VertexBuffer* verts, unsigned v_ct) + { + VertexFormat* format = &verts->format; + if (!format->packed) + VertexFormat_pack(format); + + verts->vertex_ct = v_ct; + + // Data initially lives in main memory. Will be transferred to VRAM when we "prime" it. + verts->data = malloc(VertexBuffer_size(verts)); + } + +void VertexBuffer_resize_data(VertexBuffer* verts, unsigned v_ct) + { +#if TRUST_NO_ONE + assert(verts->vertex_ct != v_ct); // allow this? + assert(verts->data != NULL); // has already been allocated + assert(verts->vbo_id == 0); // has not been sent to VRAM +#endif + + verts->vertex_ct = v_ct; + verts->data = realloc(verts->data, VertexBuffer_size(verts)); + // TODO: skip realloc if v_ct < existing vertex count + // extra space will be reclaimed, and never sent to VRAM (see VertexBuffer_prime) + } + +void setAttrib(VertexBuffer* verts, unsigned a_idx, unsigned v_idx, const void* data) + { + const VertexFormat* format = &verts->format; + const Attrib* a = format->attribs + a_idx; + +#if TRUST_NO_ONE + assert(a_idx < format->attrib_ct); + assert(v_idx < verts->vertex_ct); + assert(verts->data != NULL); // data must be in main mem +#endif + + memcpy((GLubyte*)verts->data + a->offset + v_idx * format->stride, data, a->sz); + } + +void fillAttrib(VertexBuffer* verts, unsigned a_idx, const void* data) + { + const VertexFormat* format = &verts->format; + const Attrib* a = format->attribs + a_idx; + +#if TRUST_NO_ONE + assert(a_idx < format->attrib_ct); +#endif + + const unsigned stride = a->sz; // tightly packed input data + + fillAttribStride(verts, a_idx, stride, data); + } + +void fillAttribStride(VertexBuffer* verts, unsigned a_idx, unsigned stride, const void* data) + { + const VertexFormat* format = &verts->format; + const Attrib* a = format->attribs + a_idx; + +#if TRUST_NO_ONE + assert(a_idx < format->attrib_ct); + assert(verts->data != NULL); // data must be in main mem +#endif + + const unsigned vertex_ct = verts->vertex_ct; + + if (format->attrib_ct == 1 && stride == format->stride) + { + // we can copy it all at once + memcpy(verts->data, data, vertex_ct * a->sz); + } + else + { + // we must copy it per vertex + for (unsigned v = 0; v < vertex_ct; ++v) + memcpy((GLubyte*)verts->data + a->offset + v * format->stride, (const GLubyte*)data + v * stride, a->sz); + } + } + +static void VertexBuffer_prime(VertexBuffer* verts) + { + const VertexFormat* format = &verts->format; + + verts->vbo_id = buffer_id_alloc(); + glBindBuffer(GL_ARRAY_BUFFER, verts->vbo_id); + // fill with delicious data & send to GPU the first time only + glBufferData(GL_ARRAY_BUFFER, vertex_buffer_size(format, verts->vertex_ct), verts->data, GL_STATIC_DRAW); + +#if KEEP_SINGLE_COPY + // now that GL has a copy, discard original + free(verts->data); + verts->data = NULL; +#endif + } + +void VertexBuffer_use(VertexBuffer* verts) + { + if (verts->vbo_id) + glBindBuffer(GL_ARRAY_BUFFER, verts->vbo_id); + else + VertexBuffer_prime(verts); + } diff --git a/source/blender/gpu/gawain/vertex_buffer.h b/source/blender/gpu/gawain/vertex_buffer.h new file mode 100644 index 00000000000..6a72cfe6ff3 --- /dev/null +++ b/source/blender/gpu/gawain/vertex_buffer.h @@ -0,0 +1,64 @@ + +// Gawain geometry batch +// +// This code is part of the Gawain library, with modifications +// specific to integration with Blender. +// +// Copyright 2016 Mike Erwin +// +// This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of +// the MPL was not distributed with this file, You can obtain one at https://mozilla.org/MPL/2.0/. + +#pragma once + +#include "vertex_format.h" + +// How to create a VertexBuffer: +// 1) verts = create_VertexBuffer() or init_VertexBuffer(verts) +// 2) add_attrib(verts->format, ...) +// 3) allocate_vertex_data(verts, vertex_ct) <-- finalizes/packs vertex format +// 4) fillAttrib(verts, pos, application_pos_buffer) +// 5) prime_VertexBuffer(verts); + +// Is VertexBuffer always used as part of a Batch? + +typedef struct { + VertexFormat format; + unsigned vertex_ct; + GLubyte* data; // NULL indicates data in VRAM (unmapped) or not yet allocated + GLuint vbo_id; // 0 indicates not yet sent to VRAM +} VertexBuffer; + +VertexBuffer* VertexBuffer_create(void); +VertexBuffer* VertexBuffer_create_with_format(const VertexFormat*); + +void VertexBuffer_discard(VertexBuffer*); + +void VertexBuffer_init(VertexBuffer*); +void VertexBuffer_init_with_format(VertexBuffer*, const VertexFormat*); + +unsigned VertexBuffer_size(const VertexBuffer*); +void VertexBuffer_allocate_data(VertexBuffer*, unsigned v_ct); +void VertexBuffer_resize_data(VertexBuffer*, unsigned v_ct); + +// The most important setAttrib variant is the untyped one. Get it right first. +// It takes a void* so the app developer is responsible for matching their app data types +// to the vertex attribute's type and component count. They're in control of both, so this +// should not be a problem. + +void setAttrib(VertexBuffer*, unsigned a_idx, unsigned v_idx, const void* data); +void fillAttrib(VertexBuffer*, unsigned a_idx, const void* data); // tightly packed, non interleaved input data +void fillAttribStride(VertexBuffer*, unsigned a_idx, unsigned stride, const void* data); + +// TODO: decide whether to keep the functions below +// doesn't immediate mode satisfy these needs? + +// void setAttrib1f(unsigned a_idx, unsigned v_idx, float x); +// void setAttrib2f(unsigned a_idx, unsigned v_idx, float x, float y); +// void setAttrib3f(unsigned a_idx, unsigned v_idx, float x, float y, float z); +// void setAttrib4f(unsigned a_idx, unsigned v_idx, float x, float y, float z, float w); +// +// void setAttrib3ub(unsigned a_idx, unsigned v_idx, unsigned char r, unsigned char g, unsigned char b); +// void setAttrib4ub(unsigned a_idx, unsigned v_idx, unsigned char r, unsigned char g, unsigned char b, unsigned char a); + +void VertexBuffer_use(VertexBuffer*); diff --git a/source/blender/gpu/gawain/vertex_format.c b/source/blender/gpu/gawain/vertex_format.c new file mode 100644 index 00000000000..671b979a810 --- /dev/null +++ b/source/blender/gpu/gawain/vertex_format.c @@ -0,0 +1,246 @@ + +// Gawain vertex format +// +// This code is part of the Gawain library, with modifications +// specific to integration with Blender. +// +// Copyright 2016 Mike Erwin +// +// This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of +// the MPL was not distributed with this file, You can obtain one at https://mozilla.org/MPL/2.0/. + +#include "vertex_format.h" +#include <stdlib.h> +#include <string.h> + +#define PACK_DEBUG 0 + +#if PACK_DEBUG + #include <stdio.h> +#endif + +void VertexFormat_clear(VertexFormat* format) + { +#if TRUST_NO_ONE + memset(format, 0, sizeof(VertexFormat)); +#else + format->attrib_ct = 0; + format->packed = false; + format->name_offset = 0; +#endif + } + +void VertexFormat_copy(VertexFormat* dest, const VertexFormat* src) + { + // copy regular struct fields + memcpy(dest, src, sizeof(VertexFormat)); + } + +static unsigned comp_sz(VertexCompType type) + { +#if TRUST_NO_ONE + assert(type >= GL_BYTE && type <= GL_FLOAT); +#endif + + const GLubyte sizes[] = {1,1,2,2,4,4,4}; + return sizes[type - GL_BYTE]; + } + +static unsigned attrib_sz(const Attrib *a) + { +#if USE_10_10_10 + if (a->comp_type == COMP_I10) + return 4; // always packed as 10_10_10_2 +#endif + + return a->comp_ct * comp_sz(a->comp_type); + } + +static unsigned attrib_align(const Attrib *a) + { +#if USE_10_10_10 + if (a->comp_type == COMP_I10) + return 4; // always packed as 10_10_10_2 +#endif + + unsigned c = comp_sz(a->comp_type); + if (a->comp_ct == 3 && c <= 2) + return 4 * c; // AMD HW can't fetch these well, so pad it out (other vendors too?) + else + return c; // most fetches are ok if components are naturally aligned + } + +unsigned vertex_buffer_size(const VertexFormat* format, unsigned vertex_ct) + { +#if TRUST_NO_ONE + assert(format->packed && format->stride > 0); +#endif + + return format->stride * vertex_ct; + } + +static const char* copy_attrib_name(VertexFormat* format, const char* name) + { + // strncpy does 110% of what we need; let's do exactly 100% + char* name_copy = format->names + format->name_offset; + unsigned available = VERTEX_ATTRIB_NAMES_BUFFER_LEN - format->name_offset; + bool terminated = false; + + for (unsigned i = 0; i < available; ++i) + { + const char c = name[i]; + name_copy[i] = c; + if (c == '\0') + { + terminated = true; + format->name_offset += (i + 1); + break; + } + } + +#if TRUST_NO_ONE + assert(terminated); + assert(format->name_offset <= VERTEX_ATTRIB_NAMES_BUFFER_LEN); +#endif + + return name_copy; + } + +unsigned add_attrib(VertexFormat* format, const char* name, VertexCompType comp_type, unsigned comp_ct, VertexFetchMode fetch_mode) + { +#if TRUST_NO_ONE + assert(format->attrib_ct < MAX_VERTEX_ATTRIBS); // there's room for more + assert(!format->packed); // packed means frozen/locked + assert(comp_ct >= 1 && comp_ct <= 4); + switch (comp_type) + { + case COMP_F32: + // float type can only kept as float + assert(fetch_mode == KEEP_FLOAT); + break; + #if USE_10_10_10 + case COMP_I10: + assert(comp_ct == 3); // 10_10_10 format intended for normals (xyz) or colors (rgb) + assert(fetch_mode == NORMALIZE_INT_TO_FLOAT); + break; + #endif + default: + // integer types can be kept as int or converted/normalized to float + assert(fetch_mode != KEEP_FLOAT); + } +#endif + + const unsigned attrib_id = format->attrib_ct++; + Attrib* attrib = format->attribs + attrib_id; + + attrib->name = copy_attrib_name(format, name); + attrib->comp_type = comp_type; +#if USE_10_10_10 + attrib->comp_ct = (comp_type == COMP_I10) ? 4 : comp_ct; // system needs 10_10_10_2 to be 4 or BGRA +#else + attrib->comp_ct = comp_ct; +#endif + attrib->sz = attrib_sz(attrib); + attrib->offset = 0; // offsets & stride are calculated later (during pack) + attrib->fetch_mode = fetch_mode; + + return attrib_id; + } + +unsigned padding(unsigned offset, unsigned alignment) + { + const unsigned mod = offset % alignment; + return (mod == 0) ? 0 : (alignment - mod); + } + +#if PACK_DEBUG +static void show_pack(unsigned a_idx, unsigned sz, unsigned pad) + { + const char c = 'A' + a_idx; + for (unsigned i = 0; i < pad; ++i) + putchar('-'); + for (unsigned i = 0; i < sz; ++i) + putchar(c); + } +#endif + +void VertexFormat_pack(VertexFormat* format) + { + // for now, attributes are packed in the order they were added, + // making sure each attrib is naturally aligned (add padding where necessary) + + // later we can implement more efficient packing w/ reordering + // (keep attrib ID order, adjust their offsets to reorder in buffer) + + // TODO: + // realloc just enough to hold the final combo string. And just enough to + // hold used attribs, not all 16. + + Attrib* a0 = format->attribs + 0; + a0->offset = 0; + unsigned offset = a0->sz; + +#if PACK_DEBUG + show_pack(0, a0->sz, 0); +#endif + + for (unsigned a_idx = 1; a_idx < format->attrib_ct; ++a_idx) + { + Attrib* a = format->attribs + a_idx; + unsigned mid_padding = padding(offset, attrib_align(a)); + offset += mid_padding; + a->offset = offset; + offset += a->sz; + +#if PACK_DEBUG + show_pack(a_idx, a->sz, mid_padding); +#endif + } + + unsigned end_padding = padding(offset, attrib_align(a0)); + +#if PACK_DEBUG + show_pack(0, 0, end_padding); + putchar('\n'); +#endif + + format->stride = offset + end_padding; + format->packed = true; + } + + +#if USE_10_10_10 + +// OpenGL ES packs in a different order as desktop GL but component conversion is the same. +// Of the code here, only struct PackedNormal needs to change. + +#define SIGNED_INT_10_MAX 511 +#define SIGNED_INT_10_MIN -512 + +static int clampi(int x, int min_allowed, int max_allowed) + { +#if TRUST_NO_ONE + assert(min_allowed <= max_allowed); +#endif + + if (x < min_allowed) + return min_allowed; + else if (x > max_allowed) + return max_allowed; + else + return x; + } + +static int quantize(float x) + { + int qx = x * 511.0f; + return clampi(qx, SIGNED_INT_10_MIN, SIGNED_INT_10_MAX); + } + +PackedNormal convert_i10_v3(const float data[3]) + { + PackedNormal n = { .x = quantize(data[0]), .y = quantize(data[1]), .z = quantize(data[2]) }; + return n; + } + +#endif // USE_10_10_10 diff --git a/source/blender/gpu/gawain/vertex_format.h b/source/blender/gpu/gawain/vertex_format.h new file mode 100644 index 00000000000..66477b0cfc7 --- /dev/null +++ b/source/blender/gpu/gawain/vertex_format.h @@ -0,0 +1,87 @@ + +// Gawain vertex format +// +// This code is part of the Gawain library, with modifications +// specific to integration with Blender. +// +// Copyright 2016 Mike Erwin +// +// This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of +// the MPL was not distributed with this file, You can obtain one at https://mozilla.org/MPL/2.0/. + +#pragma once + +#include "common.h" + +#define MAX_VERTEX_ATTRIBS 16 +#define AVG_VERTEX_ATTRIB_NAME_LEN 5 +#define VERTEX_ATTRIB_NAMES_BUFFER_LEN ((AVG_VERTEX_ATTRIB_NAME_LEN + 1) * MAX_VERTEX_ATTRIBS) + +#define USE_10_10_10 defined(_WIN32) +// (GLEW_VERSION_3_3 || GLEW_ARB_vertex_type_2_10_10_10_rev) +// ^-- this is only guaranteed on Windows right now, will be true on all platforms soon + +typedef enum { + COMP_I8 = GL_BYTE, + COMP_U8 = GL_UNSIGNED_BYTE, + COMP_I16 = GL_SHORT, + COMP_U16 = GL_UNSIGNED_SHORT, + COMP_I32 = GL_INT, + COMP_U32 = GL_UNSIGNED_INT, + + COMP_F32 = GL_FLOAT, // TODO: drop the GL_ equivalence here, use a private lookup table + +#if USE_10_10_10 + COMP_I10 = GL_INT_2_10_10_10_REV +#endif +} VertexCompType; + +typedef enum { + KEEP_FLOAT, + KEEP_INT, + NORMALIZE_INT_TO_FLOAT, // 127 (ubyte) -> 0.5 (and so on for other int types) + CONVERT_INT_TO_FLOAT // 127 (any int type) -> 127.0 +} VertexFetchMode; + +typedef struct { + VertexCompType comp_type; + unsigned comp_ct; // 1 to 4 + unsigned sz; // size in bytes, 1 to 16 + unsigned offset; // from beginning of vertex, in bytes + VertexFetchMode fetch_mode; + const char* name; +} Attrib; + +typedef struct { + unsigned attrib_ct; // 0 to 16 (MAX_VERTEX_ATTRIBS) + unsigned stride; // stride in bytes, 1 to 256 + bool packed; + Attrib attribs[MAX_VERTEX_ATTRIBS]; // TODO: variable-size attribs array + char names[VERTEX_ATTRIB_NAMES_BUFFER_LEN]; + unsigned name_offset; +} VertexFormat; + +void VertexFormat_clear(VertexFormat*); +void VertexFormat_copy(VertexFormat* dest, const VertexFormat* src); + +unsigned add_attrib(VertexFormat*, const char* name, VertexCompType, unsigned comp_ct, VertexFetchMode); + +// format conversion + +#if USE_10_10_10 + +typedef struct { + int x : 10; + int y : 10; + int z : 10; + int w : 2; // ignored for our purposes +} PackedNormal; + +PackedNormal convert_i10_v3(const float data[3]); + +#endif // USE_10_10_10 + +// for internal use +void VertexFormat_pack(VertexFormat*); +unsigned padding(unsigned offset, unsigned alignment); +unsigned vertex_buffer_size(const VertexFormat*, unsigned vertex_ct); diff --git a/source/blender/gpu/intern/gpu_basic_shader.c b/source/blender/gpu/intern/gpu_basic_shader.c index a2b89239344..757982d1b30 100644 --- a/source/blender/gpu/intern/gpu_basic_shader.c +++ b/source/blender/gpu/intern/gpu_basic_shader.c @@ -140,114 +140,6 @@ const GLubyte stipple_checker_8px[128] = { 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255}; -const GLubyte stipple_interlace_row[128] = { - 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, - 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, - 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, - 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, - 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, - 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, - 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, - 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, - 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, - 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, - 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, - 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, - 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, - 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, - 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, - 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00}; - -const GLubyte stipple_interlace_row_swap[128] = { - 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, - 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, - 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, - 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, - 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, - 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, - 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, - 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, - 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, - 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, - 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, - 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, - 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, - 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, - 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, - 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff}; - -const GLubyte stipple_interlace_column[128] = { - 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, - 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, - 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, - 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, - 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, - 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, - 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, - 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, - 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, - 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, - 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, - 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, - 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, - 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, - 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, - 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55}; - -const GLubyte stipple_interlace_column_swap[128] = { - 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, - 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, - 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, - 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, - 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, - 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, - 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, - 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, - 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, - 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, - 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, - 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, - 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, - 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, - 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, - 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa}; - -const GLubyte stipple_interlace_checker[128] = { - 0x55, 0x55, 0x55, 0x55, 0xaa, 0xaa, 0xaa, 0xaa, - 0x55, 0x55, 0x55, 0x55, 0xaa, 0xaa, 0xaa, 0xaa, - 0x55, 0x55, 0x55, 0x55, 0xaa, 0xaa, 0xaa, 0xaa, - 0x55, 0x55, 0x55, 0x55, 0xaa, 0xaa, 0xaa, 0xaa, - 0x55, 0x55, 0x55, 0x55, 0xaa, 0xaa, 0xaa, 0xaa, - 0x55, 0x55, 0x55, 0x55, 0xaa, 0xaa, 0xaa, 0xaa, - 0x55, 0x55, 0x55, 0x55, 0xaa, 0xaa, 0xaa, 0xaa, - 0x55, 0x55, 0x55, 0x55, 0xaa, 0xaa, 0xaa, 0xaa, - 0x55, 0x55, 0x55, 0x55, 0xaa, 0xaa, 0xaa, 0xaa, - 0x55, 0x55, 0x55, 0x55, 0xaa, 0xaa, 0xaa, 0xaa, - 0x55, 0x55, 0x55, 0x55, 0xaa, 0xaa, 0xaa, 0xaa, - 0x55, 0x55, 0x55, 0x55, 0xaa, 0xaa, 0xaa, 0xaa, - 0x55, 0x55, 0x55, 0x55, 0xaa, 0xaa, 0xaa, 0xaa, - 0x55, 0x55, 0x55, 0x55, 0xaa, 0xaa, 0xaa, 0xaa, - 0x55, 0x55, 0x55, 0x55, 0xaa, 0xaa, 0xaa, 0xaa, - 0x55, 0x55, 0x55, 0x55, 0xaa, 0xaa, 0xaa, 0xaa}; - -const GLubyte stipple_interlace_checker_swap[128] = { - 0xaa, 0xaa, 0xaa, 0xaa, 0x55, 0x55, 0x55, 0x55, - 0xaa, 0xaa, 0xaa, 0xaa, 0x55, 0x55, 0x55, 0x55, - 0xaa, 0xaa, 0xaa, 0xaa, 0x55, 0x55, 0x55, 0x55, - 0xaa, 0xaa, 0xaa, 0xaa, 0x55, 0x55, 0x55, 0x55, - 0xaa, 0xaa, 0xaa, 0xaa, 0x55, 0x55, 0x55, 0x55, - 0xaa, 0xaa, 0xaa, 0xaa, 0x55, 0x55, 0x55, 0x55, - 0xaa, 0xaa, 0xaa, 0xaa, 0x55, 0x55, 0x55, 0x55, - 0xaa, 0xaa, 0xaa, 0xaa, 0x55, 0x55, 0x55, 0x55, - 0xaa, 0xaa, 0xaa, 0xaa, 0x55, 0x55, 0x55, 0x55, - 0xaa, 0xaa, 0xaa, 0xaa, 0x55, 0x55, 0x55, 0x55, - 0xaa, 0xaa, 0xaa, 0xaa, 0x55, 0x55, 0x55, 0x55, - 0xaa, 0xaa, 0xaa, 0xaa, 0x55, 0x55, 0x55, 0x55, - 0xaa, 0xaa, 0xaa, 0xaa, 0x55, 0x55, 0x55, 0x55, - 0xaa, 0xaa, 0xaa, 0xaa, 0x55, 0x55, 0x55, 0x55, - 0xaa, 0xaa, 0xaa, 0xaa, 0x55, 0x55, 0x55, 0x55, - 0xaa, 0xaa, 0xaa, 0xaa, 0x55, 0x55, 0x55, 0x55}; - const GLubyte stipple_hexagon[128] = { 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, @@ -269,7 +161,7 @@ const GLubyte stipple_hexagon[128] = { /* GLSL State */ -static bool USE_GLSL = false; +static bool USE_GLSL = true; /** * \note this isn't part of the basic shader API, @@ -422,23 +314,6 @@ void GPU_basic_shader_bind(int options) { if (USE_GLSL) { if (options) { - const int bound_options = GPU_MATERIAL_STATE.bound_options; - - /* texture options need to be set for basic shader too */ - if (options & GPU_SHADER_TEXTURE_2D) { - glEnable(GL_TEXTURE_2D); - } - else if (bound_options & GPU_SHADER_TEXTURE_2D) { - glDisable(GL_TEXTURE_2D); - } - - if (options & GPU_SHADER_TEXTURE_RECT) { - glEnable(GL_TEXTURE_RECTANGLE); - } - else if (bound_options & GPU_SHADER_TEXTURE_RECT) { - glDisable(GL_TEXTURE_RECTANGLE); - } - GPUShader *shader = gpu_basic_shader(options); if (shader) { @@ -668,24 +543,6 @@ void GPU_basic_shader_stipple(GPUBasicShaderStipple stipple_id) case GPU_SHADER_STIPPLE_DIAG_STRIPES: glPolygonStipple(stipple_diag_stripes_pos); return; - case GPU_SHADER_STIPPLE_S3D_INTERLACE_ROW: - glPolygonStipple(stipple_interlace_row); - return; - case GPU_SHADER_STIPPLE_S3D_INTERLACE_ROW_SWAP: - glPolygonStipple(stipple_interlace_row_swap); - return; - case GPU_SHADER_STIPPLE_S3D_INTERLACE_COLUMN: - glPolygonStipple(stipple_interlace_column); - return; - case GPU_SHADER_STIPPLE_S3D_INTERLACE_COLUMN_SWAP: - glPolygonStipple(stipple_interlace_column_swap); - return; - case GPU_SHADER_STIPPLE_S3D_INTERLACE_CHECKER: - glPolygonStipple(stipple_interlace_checker); - return; - case GPU_SHADER_STIPPLE_S3D_INTERLACE_CHECKER_SWAP: - glPolygonStipple(stipple_interlace_checker_swap); - return; default: glPolygonStipple(stipple_hexagon); return; diff --git a/source/blender/gpu/intern/gpu_batch.c b/source/blender/gpu/intern/gpu_batch.c new file mode 100644 index 00000000000..5e86f1e26ba --- /dev/null +++ b/source/blender/gpu/intern/gpu_batch.c @@ -0,0 +1,122 @@ +/* + * ***** 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) 2016 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): Mike Erwin + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#include "BLI_utildefines.h" +#include "BLI_math.h" + +#include "GPU_batch.h" +#include "gpu_shader_private.h" + +void Batch_set_builtin_program(Batch* batch, GPUBuiltinShader shader_id) +{ + GPUShader *shader = GPU_shader_get_builtin_shader(shader_id); + Batch_set_program(batch, shader->program); +} + +static Batch *sphere_high = NULL; +static Batch *sphere_med = NULL; +static Batch *sphere_low = NULL; + +static VertexBuffer *vbo; +static VertexFormat format = {0}; +static unsigned int pos_id, nor_id; +static unsigned int vert; + +static void batch_sphere_lat_lon_vert(float lat, float lon) +{ + float pos[3]; + pos[0] = sinf(lat) * cosf(lon); + pos[1] = cosf(lat); + pos[2] = sinf(lat) * sinf(lon); + + setAttrib(vbo, nor_id, vert, pos); + setAttrib(vbo, pos_id, vert++, pos); +} + +/* Replacement for gluSphere */ +static Batch *batch_sphere(int lat_res, int lon_res) +{ + const float lon_inc = 2 * M_PI / lon_res; + const float lat_inc = M_PI / lat_res; + float lon, lat; + + if (format.attrib_ct == 0) { + pos_id = add_attrib(&format, "pos", GL_FLOAT, 3, KEEP_FLOAT); + nor_id = add_attrib(&format, "nor", GL_FLOAT, 3, KEEP_FLOAT); + } + + vbo = VertexBuffer_create_with_format(&format); + VertexBuffer_allocate_data(vbo, (lat_res-1) * lon_res * 6); + vert = 0; + + lon = 0.0f; + for(int i = 0; i < lon_res; i++, lon += lon_inc) { + lat = 0.0f; + for(int j = 0; j < lat_res; j++, lat += lat_inc) { + if (j != lat_res - 1) { /* Pole */ + batch_sphere_lat_lon_vert(lat+lat_inc, lon+lon_inc); + batch_sphere_lat_lon_vert(lat+lat_inc, lon); + batch_sphere_lat_lon_vert(lat, lon); + } + + if (j != 0) { /* Pole */ + batch_sphere_lat_lon_vert(lat, lon+lon_inc); + batch_sphere_lat_lon_vert(lat+lat_inc, lon+lon_inc); + batch_sphere_lat_lon_vert(lat, lon); + } + } + } + + return Batch_create(GL_TRIANGLES, vbo, NULL); +} + +Batch *Batch_get_sphere(int lod) +{ + BLI_assert(lod >= 0 && lod <= 2); + + if (lod == 0) + return sphere_low; + else if (lod == 1) + return sphere_med; + else + return sphere_high; +} + +void gpu_batch_init(void) +{ + /* Hard coded resolution */ + sphere_low = batch_sphere(8, 16); + sphere_med = batch_sphere(16, 10); + sphere_high = batch_sphere(32, 24); +} + +void gpu_batch_exit(void) +{ + Batch_discard_all(sphere_low); + Batch_discard_all(sphere_med); + Batch_discard_all(sphere_high); +} diff --git a/source/blender/gpu/intern/gpu_codegen.c b/source/blender/gpu/intern/gpu_codegen.c index 211394e7932..4223ec54f74 100644 --- a/source/blender/gpu/intern/gpu_codegen.c +++ b/source/blender/gpu/intern/gpu_codegen.c @@ -1192,7 +1192,7 @@ static void gpu_node_input_link(GPUNode *node, GPUNodeLink *link, const GPUType #if 0 input->tex = GPU_texture_create_2D(link->texturesize, link->texturesize, link->ptr2, NULL); #endif - input->tex = GPU_texture_create_2D(link->texturesize, 1, link->ptr1, GPU_HDR_NONE, NULL); + input->tex = GPU_texture_create_2D(link->texturesize, 1, link->ptr1, NULL); input->textarget = GL_TEXTURE_2D; MEM_freeN(link->ptr1); diff --git a/source/blender/gpu/intern/gpu_compositing.c b/source/blender/gpu/intern/gpu_compositing.c index 964c2b5051e..528bdefc209 100644 --- a/source/blender/gpu/intern/gpu_compositing.c +++ b/source/blender/gpu/intern/gpu_compositing.c @@ -225,7 +225,13 @@ static GPUTexture * create_concentric_sample_texture(int side) } } - tex = GPU_texture_create_1D_procedural(side * side, texels, NULL); + tex = GPU_texture_create_1D_custom(side * side, 2, GPU_RG16F, (float *)texels, NULL); + + /* Set parameters */ + GPU_texture_bind(tex, 0); + GPU_texture_filter_mode(tex, false); + GPU_texture_unbind(tex); + MEM_freeN(texels); return tex; } @@ -247,7 +253,13 @@ static GPUTexture *create_spiral_sample_texture(int numsaples) texels[i][1] = r * sinf(phi); } - tex = GPU_texture_create_1D_procedural(numsaples, (float *)texels, NULL); + tex = GPU_texture_create_1D_custom(numsaples, 2, GPU_RG16F, (float *)texels, NULL); + + /* Set parameters */ + GPU_texture_bind(tex, 0); + GPU_texture_filter_mode(tex, false); + GPU_texture_unbind(tex); + MEM_freeN(texels); return tex; } @@ -358,6 +370,7 @@ void GPU_fx_compositor_destroy(GPUFX *fx) static GPUTexture * create_jitter_texture(void) { + GPUTexture *tex; float jitter[64 * 64][2]; int i; @@ -367,7 +380,15 @@ static GPUTexture * create_jitter_texture(void) normalize_v2(jitter[i]); } - return GPU_texture_create_2D_procedural(64, 64, &jitter[0][0], true, NULL); + tex = GPU_texture_create_2D_custom(64, 64, 2, GPU_RG16F, &jitter[0][0], NULL); + + /* Set parameters */ + GPU_texture_bind(tex, 0); + GPU_texture_filter_mode(tex, false); + GPU_texture_wrap_mode(tex, true); + GPU_texture_unbind(tex); + + return tex; } @@ -382,9 +403,6 @@ bool GPU_fx_compositor_initialize_passes( fx->effects = 0; - if (!GLEW_EXT_framebuffer_object) - return false; - if (!fx_settings) { cleanup_fx_gl_data(fx, true); return false; @@ -436,7 +454,7 @@ bool GPU_fx_compositor_initialize_passes( if (!fx->color_buffer || !fx->depth_buffer || w != fx->gbuffer_dim[0] || h != fx->gbuffer_dim[1]) { cleanup_fx_gl_data(fx, false); - if (!(fx->color_buffer = GPU_texture_create_2D(w, h, NULL, GPU_HDR_NONE, err_out))) { + if (!(fx->color_buffer = GPU_texture_create_2D(w, h, NULL, err_out))) { printf(".256%s\n", err_out); cleanup_fx_gl_data(fx, true); return false; @@ -488,38 +506,42 @@ bool GPU_fx_compositor_initialize_passes( { if (!(fx->dof_half_downsampled_near = GPU_texture_create_2D( - fx->dof_downsampled_w, fx->dof_downsampled_h, NULL, GPU_HDR_NONE, err_out))) + fx->dof_downsampled_w, fx->dof_downsampled_h, NULL, err_out))) { printf("%.256s\n", err_out); cleanup_fx_gl_data(fx, true); return false; } if (!(fx->dof_half_downsampled_far = GPU_texture_create_2D( - fx->dof_downsampled_w, fx->dof_downsampled_h, NULL, GPU_HDR_NONE, err_out))) + fx->dof_downsampled_w, fx->dof_downsampled_h, NULL, err_out))) { printf("%.256s\n", err_out); cleanup_fx_gl_data(fx, true); return false; } - if (!(fx->dof_nearfar_coc = GPU_texture_create_2D_procedural( - fx->dof_downsampled_w, fx->dof_downsampled_h, NULL, false, err_out))) + + if (!(fx->dof_nearfar_coc = GPU_texture_create_2D_custom( + fx->dof_downsampled_w, fx->dof_downsampled_h, 2, GPU_RG16F, NULL, err_out))) { printf("%.256s\n", err_out); cleanup_fx_gl_data(fx, true); return false; } + GPU_texture_bind(fx->dof_nearfar_coc, 0); + GPU_texture_filter_mode(fx->dof_nearfar_coc, false); + GPU_texture_wrap_mode(fx->dof_nearfar_coc, false); + GPU_texture_unbind(fx->dof_nearfar_coc); - - if (!(fx->dof_near_blur = GPU_texture_create_2D( - fx->dof_downsampled_w, fx->dof_downsampled_h, NULL, GPU_HDR_HALF_FLOAT, err_out))) + if (!(fx->dof_near_blur = GPU_texture_create_2D_custom( + fx->dof_downsampled_w, fx->dof_downsampled_h, 2, GPU_RGBA16F, NULL, err_out))) { printf("%.256s\n", err_out); cleanup_fx_gl_data(fx, true); return false; } - if (!(fx->dof_far_blur = GPU_texture_create_2D( - fx->dof_downsampled_w, fx->dof_downsampled_h, NULL, GPU_HDR_HALF_FLOAT, err_out))) + if (!(fx->dof_far_blur = GPU_texture_create_2D_custom( + fx->dof_downsampled_w, fx->dof_downsampled_h, 2, GPU_RGBA16F, NULL, err_out))) { printf("%.256s\n", err_out); cleanup_fx_gl_data(fx, true); @@ -534,21 +556,21 @@ bool GPU_fx_compositor_initialize_passes( if (!fx->dof_near_coc_buffer || !fx->dof_near_coc_blurred_buffer || !fx->dof_near_coc_final_buffer) { if (!(fx->dof_near_coc_buffer = GPU_texture_create_2D( - fx->dof_downsampled_w, fx->dof_downsampled_h, NULL, GPU_HDR_NONE, err_out))) + fx->dof_downsampled_w, fx->dof_downsampled_h, NULL, err_out))) { printf("%.256s\n", err_out); cleanup_fx_gl_data(fx, true); return false; } if (!(fx->dof_near_coc_blurred_buffer = GPU_texture_create_2D( - fx->dof_downsampled_w, fx->dof_downsampled_h, NULL, GPU_HDR_NONE, err_out))) + fx->dof_downsampled_w, fx->dof_downsampled_h, NULL, err_out))) { printf("%.256s\n", err_out); cleanup_fx_gl_data(fx, true); return false; } if (!(fx->dof_near_coc_final_buffer = GPU_texture_create_2D( - fx->dof_downsampled_w, fx->dof_downsampled_h, NULL, GPU_HDR_NONE, err_out))) + fx->dof_downsampled_w, fx->dof_downsampled_h, NULL, err_out))) { printf("%.256s\n", err_out); cleanup_fx_gl_data(fx, true); @@ -567,7 +589,7 @@ bool GPU_fx_compositor_initialize_passes( /* we need to pass data between shader stages, allocate an extra color buffer */ if (num_passes > 1) { if (!fx->color_buffer_sec) { - if (!(fx->color_buffer_sec = GPU_texture_create_2D(w, h, NULL, GPU_HDR_NONE, err_out))) { + if (!(fx->color_buffer_sec = GPU_texture_create_2D(w, h, NULL, err_out))) { printf(".256%s\n", err_out); cleanup_fx_gl_data(fx, true); return false; @@ -585,11 +607,8 @@ bool GPU_fx_compositor_initialize_passes( /* bind the buffers */ /* first depth buffer, because system assumes read/write buffers */ - if (!GPU_framebuffer_texture_attach(fx->gbuffer, fx->depth_buffer, 0, err_out)) - printf("%.256s\n", err_out); - - if (!GPU_framebuffer_texture_attach(fx->gbuffer, fx->color_buffer, 0, err_out)) - printf("%.256s\n", err_out); + GPU_framebuffer_texture_attach(fx->gbuffer, fx->depth_buffer, 0); + GPU_framebuffer_texture_attach(fx->gbuffer, fx->color_buffer, 0); if (!GPU_framebuffer_check_valid(fx->gbuffer, err_out)) printf("%.256s\n", err_out); @@ -634,7 +653,7 @@ static void gpu_fx_bind_render_target(int *passes_left, GPUFX *fx, struct GPUOff } else { /* bind the ping buffer to the color buffer */ - GPU_framebuffer_texture_attach(fx->gbuffer, target, 0, NULL); + GPU_framebuffer_texture_attach(fx->gbuffer, target, 0); } } @@ -663,8 +682,7 @@ void GPU_fx_compositor_setup_XRay_pass(GPUFX *fx, bool do_xray) GPU_framebuffer_texture_detach(fx->depth_buffer); /* first depth buffer, because system assumes read/write buffers */ - if (!GPU_framebuffer_texture_attach(fx->gbuffer, fx->depth_buffer_xray, 0, err_out)) - printf("%.256s\n", err_out); + GPU_framebuffer_texture_attach(fx->gbuffer, fx->depth_buffer_xray, 0); } @@ -674,7 +692,7 @@ void GPU_fx_compositor_XRay_resolve(GPUFX *fx) GPU_framebuffer_texture_detach(fx->depth_buffer_xray); /* attach regular framebuffer */ - GPU_framebuffer_texture_attach(fx->gbuffer, fx->depth_buffer, 0, NULL); + GPU_framebuffer_texture_attach(fx->gbuffer, fx->depth_buffer, 0); /* full screen quad where we will always write to depth buffer */ glPushAttrib(GL_DEPTH_BUFFER_BIT | GL_SCISSOR_BIT); @@ -699,14 +717,16 @@ void GPU_fx_compositor_XRay_resolve(GPUFX *fx) GPU_shader_bind(depth_resolve_shader); GPU_texture_bind(fx->depth_buffer_xray, 0); - GPU_texture_filter_mode(fx->depth_buffer_xray, false, true); + GPU_texture_compare_mode(fx->depth_buffer_xray, false); + GPU_texture_filter_mode(fx->depth_buffer_xray, true); GPU_shader_uniform_texture(depth_resolve_shader, interface->depth_uniform, fx->depth_buffer_xray); /* draw */ glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); /* disable bindings */ - GPU_texture_filter_mode(fx->depth_buffer_xray, true, false); + GPU_texture_compare_mode(fx->depth_buffer_xray, true); + GPU_texture_filter_mode(fx->depth_buffer_xray, false); GPU_texture_unbind(fx->depth_buffer_xray); GPU_shader_unbind(); @@ -821,7 +841,8 @@ bool GPU_fx_do_composite_pass( GPU_shader_uniform_texture(ssao_shader, interface->color_uniform, src); GPU_texture_bind(fx->depth_buffer, numslots++); - GPU_texture_filter_mode(fx->depth_buffer, false, true); + GPU_texture_compare_mode(fx->depth_buffer, false); + GPU_texture_filter_mode(fx->depth_buffer, true); GPU_shader_uniform_texture(ssao_shader, interface->depth_uniform, fx->depth_buffer); GPU_texture_bind(fx->jitter_buffer, numslots++); @@ -837,7 +858,8 @@ bool GPU_fx_do_composite_pass( /* disable bindings */ GPU_texture_unbind(src); - GPU_texture_filter_mode(fx->depth_buffer, true, false); + GPU_texture_compare_mode(fx->depth_buffer, true); + GPU_texture_filter_mode(fx->depth_buffer, false); GPU_texture_unbind(fx->depth_buffer); GPU_texture_unbind(fx->jitter_buffer); GPU_texture_unbind(fx->ssao_spiral_samples_tex); @@ -913,18 +935,19 @@ bool GPU_fx_do_composite_pass( GPU_shader_uniform_vector(dof_shader_pass1, interface->invrendertargetdim_uniform, 2, 1, invrendertargetdim); GPU_texture_bind(fx->depth_buffer, numslots++); - GPU_texture_filter_mode(fx->depth_buffer, false, false); + GPU_texture_compare_mode(fx->depth_buffer, false); + GPU_texture_filter_mode(fx->depth_buffer, false); GPU_shader_uniform_texture(dof_shader_pass1, interface->depth_uniform, fx->depth_buffer); GPU_texture_bind(src, numslots++); /* disable filtering for the texture so custom downsample can do the right thing */ - GPU_texture_filter_mode(src, false, false); + GPU_texture_filter_mode(src, false); GPU_shader_uniform_texture(dof_shader_pass2, interface->color_uniform, src); /* target is the downsampled coc buffer */ - GPU_framebuffer_texture_attach(fx->gbuffer, fx->dof_half_downsampled_near, 0, NULL); - GPU_framebuffer_texture_attach(fx->gbuffer, fx->dof_half_downsampled_far, 1, NULL); - GPU_framebuffer_texture_attach(fx->gbuffer, fx->dof_nearfar_coc, 2, NULL); + GPU_framebuffer_texture_attach(fx->gbuffer, fx->dof_half_downsampled_near, 0); + GPU_framebuffer_texture_attach(fx->gbuffer, fx->dof_half_downsampled_far, 1); + GPU_framebuffer_texture_attach(fx->gbuffer, fx->dof_nearfar_coc, 2); /* binding takes care of setting the viewport to the downsampled size */ GPU_framebuffer_slots_bind(fx->gbuffer, 0); @@ -932,9 +955,10 @@ bool GPU_fx_do_composite_pass( glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); /* disable bindings */ - GPU_texture_filter_mode(src, false, true); + GPU_texture_filter_mode(src, true); GPU_texture_unbind(src); - GPU_texture_filter_mode(fx->depth_buffer, true, false); + GPU_texture_compare_mode(fx->depth_buffer, true); + GPU_texture_filter_mode(fx->depth_buffer, false); GPU_texture_unbind(fx->depth_buffer); GPU_framebuffer_texture_detach(fx->dof_half_downsampled_near); @@ -965,10 +989,10 @@ bool GPU_fx_do_composite_pass( GPU_texture_bind(fx->dof_half_downsampled_far, numslots++); GPU_texture_bind(fx->dof_half_downsampled_near, numslots++); GPU_shader_uniform_texture(dof_shader_pass2, interface->color_uniform, fx->dof_half_downsampled_far); - GPU_texture_filter_mode(fx->dof_half_downsampled_far, false, false); + GPU_texture_filter_mode(fx->dof_half_downsampled_far, false); /* target is the downsampled coc buffer */ - GPU_framebuffer_texture_attach(fx->gbuffer, fx->dof_far_blur, 0, NULL); + GPU_framebuffer_texture_attach(fx->gbuffer, fx->dof_far_blur, 0); GPU_texture_bind_as_framebuffer(fx->dof_far_blur); glDisable(GL_DEPTH_TEST); @@ -985,14 +1009,14 @@ bool GPU_fx_do_composite_pass( GPU_framebuffer_texture_detach(fx->dof_far_blur); GPU_shader_uniform_texture(dof_shader_pass2, interface->color_uniform, fx->dof_half_downsampled_near); - GPU_texture_filter_mode(fx->dof_half_downsampled_near, false, false); + GPU_texture_filter_mode(fx->dof_half_downsampled_near, false); selection[0] = 1.0f; selection[1] = 0.0f; GPU_shader_uniform_vector(dof_shader_pass2, interface->select_uniform, 2, 1, selection); - GPU_framebuffer_texture_attach(fx->gbuffer, fx->dof_near_blur, 0, NULL); + GPU_framebuffer_texture_attach(fx->gbuffer, fx->dof_near_blur, 0); /* have to clear the buffer unfortunately */ glClear(GL_COLOR_BUFFER_BIT); /* the draw call we all waited for, draw a point per pixel, scaled per circle of confusion */ @@ -1025,14 +1049,15 @@ bool GPU_fx_do_composite_pass( GPU_texture_bind(fx->dof_near_blur, numslots++); GPU_shader_uniform_texture(dof_shader_pass3, interface->near_uniform, fx->dof_near_blur); - GPU_texture_filter_mode(fx->dof_near_blur, false, true); + GPU_texture_filter_mode(fx->dof_near_blur, true); GPU_texture_bind(fx->dof_far_blur, numslots++); GPU_shader_uniform_texture(dof_shader_pass3, interface->far_uniform, fx->dof_far_blur); - GPU_texture_filter_mode(fx->dof_far_blur, false, true); + GPU_texture_filter_mode(fx->dof_far_blur, true); GPU_texture_bind(fx->depth_buffer, numslots++); - GPU_texture_filter_mode(fx->depth_buffer, false, false); + GPU_texture_compare_mode(fx->depth_buffer, false); + GPU_texture_filter_mode(fx->depth_buffer, false); GPU_shader_uniform_texture(dof_shader_pass3, interface->depth_uniform, fx->depth_buffer); GPU_texture_bind(src, numslots++); @@ -1047,7 +1072,7 @@ bool GPU_fx_do_composite_pass( GPU_texture_unbind(fx->dof_near_blur); GPU_texture_unbind(fx->dof_far_blur); GPU_texture_unbind(src); - GPU_texture_filter_mode(fx->depth_buffer, true, false); + GPU_texture_compare_mode(fx->depth_buffer, true); GPU_texture_unbind(fx->depth_buffer); /* may not be attached, in that case this just returns */ @@ -1107,18 +1132,20 @@ bool GPU_fx_do_composite_pass( GPU_shader_uniform_texture(dof_shader_pass1, interface->color_uniform, src); GPU_texture_bind(fx->depth_buffer, numslots++); - GPU_texture_filter_mode(fx->depth_buffer, false, true); + GPU_texture_compare_mode(fx->depth_buffer, false); + GPU_texture_filter_mode(fx->depth_buffer, true); GPU_shader_uniform_texture(dof_shader_pass1, interface->depth_uniform, fx->depth_buffer); /* target is the downsampled coc buffer */ - GPU_framebuffer_texture_attach(fx->gbuffer, fx->dof_near_coc_buffer, 0, NULL); + GPU_framebuffer_texture_attach(fx->gbuffer, fx->dof_near_coc_buffer, 0); /* binding takes care of setting the viewport to the downsampled size */ GPU_texture_bind_as_framebuffer(fx->dof_near_coc_buffer); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); /* disable bindings */ GPU_texture_unbind(src); - GPU_texture_filter_mode(fx->depth_buffer, true, false); + GPU_texture_compare_mode(fx->depth_buffer, true); + GPU_texture_filter_mode(fx->depth_buffer, false); GPU_texture_unbind(fx->depth_buffer); GPU_framebuffer_texture_detach(fx->dof_near_coc_buffer); @@ -1144,14 +1171,15 @@ bool GPU_fx_do_composite_pass( GPU_shader_uniform_vector(dof_shader_pass2, interface->viewvecs_uniform, 4, 3, viewvecs[0]); GPU_texture_bind(fx->depth_buffer, numslots++); - GPU_texture_filter_mode(fx->depth_buffer, false, true); + GPU_texture_compare_mode(fx->depth_buffer, false); + GPU_texture_filter_mode(fx->depth_buffer, true); GPU_shader_uniform_texture(dof_shader_pass2, interface->depth_uniform, fx->depth_buffer); GPU_texture_bind(fx->dof_near_coc_buffer, numslots++); GPU_shader_uniform_texture(dof_shader_pass2, interface->color_uniform, fx->dof_near_coc_buffer); /* use final buffer as a temp here */ - GPU_framebuffer_texture_attach(fx->gbuffer, fx->dof_near_coc_final_buffer, 0, NULL); + GPU_framebuffer_texture_attach(fx->gbuffer, fx->dof_near_coc_final_buffer, 0); /* Drawing quad */ glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); @@ -1168,11 +1196,12 @@ bool GPU_fx_do_composite_pass( GPU_texture_bind(fx->dof_near_coc_final_buffer, numslots++); GPU_shader_uniform_texture(dof_shader_pass2, interface->color_uniform, fx->dof_near_coc_final_buffer); - GPU_framebuffer_texture_attach(fx->gbuffer, fx->dof_near_coc_blurred_buffer, 0, NULL); + GPU_framebuffer_texture_attach(fx->gbuffer, fx->dof_near_coc_blurred_buffer, 0); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); /* *unbind/detach */ - GPU_texture_filter_mode(fx->depth_buffer, true, false); + GPU_texture_compare_mode(fx->depth_buffer, true); + GPU_texture_filter_mode(fx->depth_buffer, false); GPU_texture_unbind(fx->depth_buffer); GPU_texture_unbind(fx->dof_near_coc_final_buffer); @@ -1195,7 +1224,7 @@ bool GPU_fx_do_composite_pass( GPU_texture_bind(fx->dof_near_coc_blurred_buffer, numslots++); GPU_shader_uniform_texture(dof_shader_pass3, interface->near_coc_blurred, fx->dof_near_coc_blurred_buffer); - GPU_framebuffer_texture_attach(fx->gbuffer, fx->dof_near_coc_final_buffer, 0, NULL); + GPU_framebuffer_texture_attach(fx->gbuffer, fx->dof_near_coc_final_buffer, 0); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); /* disable bindings */ @@ -1221,7 +1250,7 @@ bool GPU_fx_do_composite_pass( GPU_shader_uniform_texture(dof_shader_pass4, interface->near_coc_downsampled, fx->dof_near_coc_final_buffer); GPU_shader_uniform_vector(dof_shader_pass4, interface->invrendertargetdim_uniform, 2, 1, invrendertargetdim); - GPU_framebuffer_texture_attach(fx->gbuffer, fx->dof_near_coc_buffer, 0, NULL); + GPU_framebuffer_texture_attach(fx->gbuffer, fx->dof_near_coc_buffer, 0); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); /* disable bindings */ @@ -1256,7 +1285,8 @@ bool GPU_fx_do_composite_pass( GPU_shader_uniform_texture(dof_shader_pass5, interface->medium_blurred_uniform, fx->dof_near_coc_buffer); GPU_texture_bind(fx->depth_buffer, numslots++); - GPU_texture_filter_mode(fx->depth_buffer, false, true); + GPU_texture_compare_mode(fx->depth_buffer, false); + GPU_texture_filter_mode(fx->depth_buffer, true); GPU_shader_uniform_texture(dof_shader_pass5, interface->depth_uniform, fx->depth_buffer); /* if this is the last pass, prepare for rendering on the frambuffer */ @@ -1267,7 +1297,8 @@ bool GPU_fx_do_composite_pass( GPU_texture_unbind(fx->dof_near_coc_buffer); GPU_texture_unbind(fx->dof_near_coc_blurred_buffer); GPU_texture_unbind(src); - GPU_texture_filter_mode(fx->depth_buffer, true, false); + GPU_texture_compare_mode(fx->depth_buffer, true); + GPU_texture_filter_mode(fx->depth_buffer, false); GPU_texture_unbind(fx->depth_buffer); /* may not be attached, in that case this just returns */ diff --git a/source/blender/gpu/intern/gpu_debug.c b/source/blender/gpu/intern/gpu_debug.c index d632e767ca9..e306394c4c3 100644 --- a/source/blender/gpu/intern/gpu_debug.c +++ b/source/blender/gpu/intern/gpu_debug.c @@ -43,118 +43,12 @@ #include <stdlib.h> #include <string.h> -#define CASE_CODE_RETURN_STR(code) case code: return #code; +/* control whether we use older AMD_debug_output extension, or just the newer extensions + * TODO(merwin): determine whether all supported GPU + OS combos have newer extensions */ +#define LEGACY_DEBUG 0 -static const char *gpu_gl_error_symbol(GLenum err) -{ - switch (err) { - CASE_CODE_RETURN_STR(GL_NO_ERROR) - CASE_CODE_RETURN_STR(GL_INVALID_ENUM) - CASE_CODE_RETURN_STR(GL_INVALID_VALUE) - CASE_CODE_RETURN_STR(GL_INVALID_OPERATION) - CASE_CODE_RETURN_STR(GL_STACK_OVERFLOW) - CASE_CODE_RETURN_STR(GL_STACK_UNDERFLOW) - CASE_CODE_RETURN_STR(GL_OUT_OF_MEMORY) - -#if GL_ARB_imaging - CASE_CODE_RETURN_STR(GL_TABLE_TOO_LARGE) -#endif - -#if defined(WITH_GLU) - CASE_CODE_RETURN_STR(GLU_INVALID_ENUM) - CASE_CODE_RETURN_STR(GLU_INVALID_VALUE) - CASE_CODE_RETURN_STR(GLU_OUT_OF_MEMORY) -#endif - - default: - return "<unknown error>"; - } -} - -#undef CASE_CODE_RETURN_STR - - -static bool gpu_report_gl_errors(const char *file, int line, const char *str) -{ - GLenum gl_error = glGetError(); - - if (gl_error == GL_NO_ERROR) { - return true; - } - else { - /* glGetError should have cleared the error flag, so if we get the - * same flag twice that means glGetError itself probably triggered - * the error. This happens on Windows if the GL context is invalid. - */ - { - GLenum new_error = glGetError(); - if (gl_error == new_error) { - fprintf(stderr, "GL: Possible context invalidation issue\n"); - return false; - } - } - - fprintf(stderr, - "%s:%d: ``%s'' -> GL Error (0x%04X - %s): %s\n", - file, line, str, gl_error, - gpu_gl_error_symbol(gl_error), - gpuErrorString(gl_error)); - - return false; - } -} - - -const char *gpuErrorString(GLenum err) -{ - switch (err) { - case GL_NO_ERROR: - return "No Error"; - - case GL_INVALID_ENUM: - return "Invalid Enumeration"; - - case GL_INVALID_VALUE: - return "Invalid Value"; - - case GL_INVALID_OPERATION: - return "Invalid Operation"; - - case GL_STACK_OVERFLOW: - return "Stack Overflow"; - - case GL_STACK_UNDERFLOW: - return "Stack Underflow"; - - case GL_OUT_OF_MEMORY: - return "Out of Memory"; - -#if GL_ARB_imaging - case GL_TABLE_TOO_LARGE: - return "Table Too Large"; -#endif - -#if defined(WITH_GLU) - case GLU_INVALID_ENUM: - return "Invalid Enum (GLU)"; - - case GLU_INVALID_VALUE: - return "Invalid Value (GLU)"; - - case GLU_OUT_OF_MEMORY: - return "Out of Memory (GLU)"; -#endif - - default: - return "<unknown error>"; - } -} - - -/* Debug callbacks need the same calling convention as OpenGL functions. - */ -#if defined(_WIN32) && !defined(_WIN32_WCE) && !defined(__SCITECH_SNAP__) - /* Win32 but not WinCE */ +/* Debug callbacks need the same calling convention as OpenGL functions. */ +#if defined(_WIN32) # define APIENTRY __stdcall #else # define APIENTRY @@ -188,32 +82,11 @@ static const char* message_type_name(GLenum message) } } -static const char* category_name_amd(GLenum category) -{ - switch (category) { - case GL_DEBUG_CATEGORY_API_ERROR_AMD: return "API error"; - case GL_DEBUG_CATEGORY_WINDOW_SYSTEM_AMD: return "window system"; - case GL_DEBUG_CATEGORY_DEPRECATION_AMD: return "deprecated behavior"; - case GL_DEBUG_CATEGORY_UNDEFINED_BEHAVIOR_AMD: return "undefined behavior"; - case GL_DEBUG_CATEGORY_PERFORMANCE_AMD: return "performance"; - case GL_DEBUG_CATEGORY_SHADER_COMPILER_AMD: return "shader compiler"; - case GL_DEBUG_CATEGORY_APPLICATION_AMD: return "application"; - case GL_DEBUG_CATEGORY_OTHER_AMD: return "other"; - default: return "???"; - } -} - - static void APIENTRY gpu_debug_proc( GLenum source, GLenum type, GLuint UNUSED(id), GLenum severity, GLsizei UNUSED(length), const GLchar *message, const GLvoid *UNUSED(userParm)) { - if (type == GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR) { - /* Blender 2.7x uses OpenGL 2.1, we don't care if features are deprecated */ - return; - } - bool backtrace = false; switch (severity) { @@ -232,18 +105,28 @@ static void APIENTRY gpu_debug_proc( } } +#if LEGACY_DEBUG + +static const char* category_name_amd(GLenum category) +{ + switch (category) { + case GL_DEBUG_CATEGORY_API_ERROR_AMD: return "API error"; + case GL_DEBUG_CATEGORY_WINDOW_SYSTEM_AMD: return "window system"; + case GL_DEBUG_CATEGORY_DEPRECATION_AMD: return "deprecated behavior"; + case GL_DEBUG_CATEGORY_UNDEFINED_BEHAVIOR_AMD: return "undefined behavior"; + case GL_DEBUG_CATEGORY_PERFORMANCE_AMD: return "performance"; + case GL_DEBUG_CATEGORY_SHADER_COMPILER_AMD: return "shader compiler"; + case GL_DEBUG_CATEGORY_APPLICATION_AMD: return "application"; + case GL_DEBUG_CATEGORY_OTHER_AMD: return "other"; + default: return "???"; + } +} -#ifndef GLEW_ES_ONLY static void APIENTRY gpu_debug_proc_amd( GLuint UNUSED(id), GLenum category, GLenum severity, GLsizei UNUSED(length), const GLchar *message, GLvoid *UNUSED(userParm)) { - if (category == GL_DEBUG_CATEGORY_DEPRECATION_AMD) { - /* Blender 2.7x uses OpenGL 2.1, we don't care if features are deprecated */ - return; - } - bool backtrace = false; switch (severity) { @@ -260,8 +143,7 @@ static void APIENTRY gpu_debug_proc_amd( fflush(stderr); } } -#endif - +#endif /* LEGACY_DEBUG */ #undef APIENTRY @@ -269,137 +151,67 @@ void gpu_debug_init(void) { const char success[] = "Successfully hooked OpenGL debug callback."; -#if !defined(WITH_GLEW_ES) && !defined(GLEW_ES_ONLY) - if (GLEW_VERSION_4_3) { - fprintf(stderr, "Using OpenGL 4.3 debug facilities\n"); + if (GLEW_VERSION_4_3 || GLEW_KHR_debug) { + fprintf(stderr, "Using %s\n", GLEW_VERSION_4_3 ? "OpenGL 4.3 debug facilities" : "KHR_debug extension"); glEnable(GL_DEBUG_OUTPUT); glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS); glDebugMessageCallback((GLDEBUGPROC)gpu_debug_proc, mxGetCurrentContext()); glDebugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE, 0, NULL, GL_TRUE); GPU_string_marker(success); - return; } -#endif - - if (GLEW_KHR_debug) { -#ifndef GLEW_ES_ONLY - fprintf(stderr, "Using KHR_debug extension\n"); - glEnable(GL_DEBUG_OUTPUT); - glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS); - glDebugMessageCallback((GLDEBUGPROC)gpu_debug_proc, mxGetCurrentContext()); - glDebugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE, 0, NULL, GL_TRUE); - GPU_string_marker(success); -#endif - return; - } - -#ifndef GLEW_ES_ONLY - if (GLEW_ARB_debug_output) { + else if (GLEW_ARB_debug_output) { fprintf(stderr, "Using ARB_debug_output extension\n"); glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS); glDebugMessageCallbackARB((GLDEBUGPROCARB)gpu_debug_proc, mxGetCurrentContext()); glDebugMessageControlARB(GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE, 0, NULL, GL_TRUE); GPU_string_marker(success); - - return; } - - if (GLEW_AMD_debug_output) { +#if LEGACY_DEBUG + else if (GLEW_AMD_debug_output) { fprintf(stderr, "Using AMD_debug_output extension\n"); glDebugMessageCallbackAMD(gpu_debug_proc_amd, mxGetCurrentContext()); glDebugMessageEnableAMD(GL_DONT_CARE, GL_DONT_CARE, 0, NULL, GL_TRUE); GPU_string_marker(success); - - return; } #endif - - fprintf(stderr, "Failed to hook OpenGL debug callback.\n"); - - return; + else { + fprintf(stderr, "Failed to hook OpenGL debug callback.\n"); + } } void gpu_debug_exit(void) { -#ifndef WITH_GLEW_ES -#ifndef GLEW_ES_ONLY - if (GLEW_VERSION_4_3) { + if (GLEW_VERSION_4_3 || GLEW_KHR_debug) { glDebugMessageCallback(NULL, NULL); - - return; } -#endif -#endif - - if (GLEW_KHR_debug) { -#ifndef GLEW_ES_ONLY - glDebugMessageCallback(NULL, NULL); -#endif - return; - } - -#ifndef GLEW_ES_ONLY - if (GLEW_ARB_debug_output) { + else if (GLEW_ARB_debug_output) { glDebugMessageCallbackARB(NULL, NULL); - - return; } - - if (GLEW_AMD_debug_output) { +#if LEGACY_DEBUG + else if (GLEW_AMD_debug_output) { glDebugMessageCallbackAMD(NULL, NULL); - - return; } #endif - - return; } void GPU_string_marker(const char *buf) { -#ifndef WITH_GLEW_ES -#ifndef GLEW_ES_ONLY - if (GLEW_VERSION_4_3) { - glDebugMessageInsert( - GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_MARKER, 0, - GL_DEBUG_SEVERITY_NOTIFICATION, -1, buf); - - return; - } -#endif -#endif - - if (GLEW_KHR_debug) { -#ifndef GLEW_ES_ONLY + if (GLEW_VERSION_4_3 || GLEW_KHR_debug) { glDebugMessageInsert( GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_MARKER, 0, GL_DEBUG_SEVERITY_NOTIFICATION, -1, buf); -#endif - return; } - -#ifndef GLEW_ES_ONLY - if (GLEW_ARB_debug_output) { + else if (GLEW_ARB_debug_output) { glDebugMessageInsertARB( GL_DEBUG_SOURCE_APPLICATION_ARB, GL_DEBUG_TYPE_OTHER_ARB, 0, GL_DEBUG_SEVERITY_LOW_ARB, -1, buf); - - return; } - - if (GLEW_AMD_debug_output) { +#if LEGACY_DEBUG + else if (GLEW_AMD_debug_output) { glDebugMessageInsertAMD( GL_DEBUG_CATEGORY_APPLICATION_AMD, GL_DEBUG_SEVERITY_LOW_AMD, 0, 0, buf); - - return; - } - - if (GLEW_GREMEDY_string_marker) { - glStringMarkerGREMEDY(0, buf); - - return; } #endif } @@ -410,18 +222,6 @@ void GPU_print_error_debug(const char *str) fprintf(stderr, "GPU: %s\n", str); } - -void GPU_assert_no_gl_errors(const char *file, int line, const char *str) -{ - if (G.debug) { - GLboolean gl_ok = gpu_report_gl_errors(file, line, str); - - BLI_assert(gl_ok); - (void) gl_ok; - } -} - - static void gpu_state_print_fl_ex(const char *name, GLenum type) { const unsigned char err_mark[4] = {0xff, 0xff, 0xff, 0xff}; @@ -448,7 +248,8 @@ static void gpu_state_print_fl_ex(const char *name, GLenum type) void GPU_state_print(void) { - GPU_ASSERT_NO_GL_ERRORS("GPU_state_print"); /* clear any errors */ + /* clear any errors */ + while (glGetError() != GL_NO_ERROR) {} gpu_state_print_fl(GL_ACCUM_ALPHA_BITS); gpu_state_print_fl(GL_ACCUM_BLUE_BITS); diff --git a/source/blender/gpu/intern/gpu_draw.c b/source/blender/gpu/intern/gpu_draw.c index 7936811ab4d..fa8e05b6bfb 100644 --- a/source/blender/gpu/intern/gpu_draw.c +++ b/source/blender/gpu/intern/gpu_draw.c @@ -38,8 +38,6 @@ #include <string.h> -#include "GPU_glew.h" - #include "BLI_blenlib.h" #include "BLI_linklist.h" #include "BLI_math.h" @@ -222,7 +220,7 @@ void GPU_render_text( /* Checking powers of two for images since OpenGL ES requires it */ -static bool is_power_of_2_resolution(int w, int h) +static bool UNUSED_FUNCTION(is_power_of_2_resolution)(int w, int h) { return is_power_of_2_i(w) && is_power_of_2_i(h); } @@ -278,7 +276,7 @@ void GPU_set_gpu_mipmapping(int gpu_mipmap) int old_value = GTS.gpu_mipmap; /* only actually enable if it's supported */ - GTS.gpu_mipmap = gpu_mipmap && GLEW_EXT_framebuffer_object; + GTS.gpu_mipmap = gpu_mipmap; if (old_value != GTS.gpu_mipmap) { GPU_free_images(); @@ -298,11 +296,7 @@ static void gpu_generate_mipmap(GLenum target) glEnable(target); } - /* TODO: simplify when we transition to GL >= 3 */ - if (GLEW_VERSION_3_0 || GLEW_ARB_framebuffer_object) - glGenerateMipmap(target); - else if (GLEW_EXT_framebuffer_object) - glGenerateMipmapEXT(target); + glGenerateMipmap(target); if (is_ati && !target_enabled) glDisable(target); @@ -857,30 +851,6 @@ void GPU_create_gl_tex( int tpx = rectw; int tpy = recth; - /* scale if not a power of two. this is not strictly necessary for newer - * GPUs (OpenGL version >= 2.0) since they support non-power-of-two-textures - * Then don't bother scaling for hardware that supports NPOT textures! */ - if (textarget == GL_TEXTURE_2D && - ((!GPU_full_non_power_of_two_support() && !is_power_of_2_resolution(rectw, recth)) || - is_over_resolution_limit(textarget, rectw, recth))) - { - rectw = smaller_power_of_2_limit(rectw); - recth = smaller_power_of_2_limit(recth); - - if (use_high_bit_depth) { - ibuf = IMB_allocFromBuffer(NULL, frect, tpx, tpy); - IMB_scaleImBuf(ibuf, rectw, recth); - - frect = ibuf->rect_float; - } - else { - ibuf = IMB_allocFromBuffer(rect, NULL, tpx, tpy); - IMB_scaleImBuf(ibuf, rectw, recth); - - rect = ibuf->rect; - } - } - /* create image */ glGenTextures(1, (GLuint *)bind); glBindTexture(textarget, *bind); @@ -1205,9 +1175,7 @@ void GPU_paint_set_mipmap(bool mipmap) /* check if image has been downscaled and do scaled partial update */ static bool GPU_check_scaled_image(ImBuf *ibuf, Image *ima, float *frect, int x, int y, int w, int h) { - if ((!GPU_full_non_power_of_two_support() && !is_power_of_2_resolution(ibuf->x, ibuf->y)) || - is_over_resolution_limit(GL_TEXTURE_2D, ibuf->x, ibuf->y)) - { + if (is_over_resolution_limit(GL_TEXTURE_2D, ibuf->x, ibuf->y)) { int x_limit = smaller_power_of_2_limit(ibuf->x); int y_limit = smaller_power_of_2_limit(ibuf->y); @@ -1436,31 +1404,40 @@ void GPU_create_smoke(SmokeModifierData *smd, int highres) if (smoke_has_colors(sds->fluid)) { float *data = MEM_callocN(sizeof(float) * sds->total_cells * 4, "smokeColorTexture"); smoke_get_rgba(sds->fluid, data, 0); - sds->tex = GPU_texture_create_3D(sds->res[0], sds->res[1], sds->res[2], 4, data); + sds->tex = GPU_texture_create_3D(sds->res[0], sds->res[1], sds->res[2], data, NULL); MEM_freeN(data); } /* density only */ else { - sds->tex = GPU_texture_create_3D(sds->res[0], sds->res[1], sds->res[2], 1, smoke_get_density(sds->fluid)); + sds->tex = GPU_texture_create_3D_custom(sds->res[0], sds->res[1], sds->res[2], 1, + GPU_R8, smoke_get_density(sds->fluid), NULL); } - sds->tex_flame = (smoke_has_fuel(sds->fluid)) ? GPU_texture_create_3D(sds->res[0], sds->res[1], sds->res[2], 1, smoke_get_flame(sds->fluid)) : NULL; + sds->tex_flame = (smoke_has_fuel(sds->fluid)) ? + GPU_texture_create_3D_custom(sds->res[0], sds->res[1], sds->res[2], 1, + GPU_R8, smoke_get_flame(sds->fluid), NULL) : + NULL; } else if (!sds->tex && highres) { /* rgba texture for color + density */ if (smoke_turbulence_has_colors(sds->wt)) { float *data = MEM_callocN(sizeof(float) * smoke_turbulence_get_cells(sds->wt) * 4, "smokeColorTexture"); smoke_turbulence_get_rgba(sds->wt, data, 0); - sds->tex = GPU_texture_create_3D(sds->res_wt[0], sds->res_wt[1], sds->res_wt[2], 4, data); + sds->tex = GPU_texture_create_3D(sds->res_wt[0], sds->res_wt[1], sds->res_wt[2], data, NULL); MEM_freeN(data); } /* density only */ else { - sds->tex = GPU_texture_create_3D(sds->res_wt[0], sds->res_wt[1], sds->res_wt[2], 1, smoke_turbulence_get_density(sds->wt)); + sds->tex = GPU_texture_create_3D_custom(sds->res_wt[0], sds->res_wt[1], sds->res_wt[2], 1, + GPU_R8, smoke_turbulence_get_density(sds->wt), NULL); } - sds->tex_flame = (smoke_turbulence_has_fuel(sds->wt)) ? GPU_texture_create_3D(sds->res_wt[0], sds->res_wt[1], sds->res_wt[2], 1, smoke_turbulence_get_flame(sds->wt)) : NULL; + sds->tex_flame = (smoke_turbulence_has_fuel(sds->wt)) ? + GPU_texture_create_3D_custom(sds->res_wt[0], sds->res_wt[1], sds->res_wt[2], 1, + GPU_R8, smoke_turbulence_get_flame(sds->wt), NULL): + NULL; } - sds->tex_shadow = GPU_texture_create_3D(sds->res[0], sds->res[1], sds->res[2], 1, sds->shadow); + sds->tex_shadow = GPU_texture_create_3D_custom(sds->res[0], sds->res[1], sds->res[2], 1, + GPU_R8, sds->shadow, NULL); } #else // WITH_SMOKE (void)highres; @@ -2182,7 +2159,7 @@ int GPU_scene_object_lights(Scene *scene, Object *ob, int lay, float viewmat[4][ int count = 0; - for (Base *base = scene->base.first; base; base = base->next) { + for (BaseLegacy *base = scene->base.first; base; base = base->next) { if (base->object->type != OB_LAMP) continue; @@ -2285,7 +2262,13 @@ void GPU_state_init(void) glColorMaterial(GL_FRONT_AND_BACK, GL_DIFFUSE); GPU_default_lights(); - + + GPU_disable_program_point_size(); + + /* TODO: remove this when we switch to core profile */ + glEnable(GL_POINT_SPRITE); + + glDepthFunc(GL_LEQUAL); /* scaling matrices */ glEnable(GL_NORMALIZE); @@ -2307,7 +2290,7 @@ void GPU_state_init(void) glDisableClientState(GL_NORMAL_ARRAY); glDisableClientState(GL_COLOR_ARRAY); glDisableClientState(GL_TEXTURE_COORD_ARRAY); - + glPixelTransferi(GL_MAP_COLOR, GL_FALSE); glPixelTransferi(GL_RED_SCALE, 1); glPixelTransferi(GL_RED_BIAS, 0); @@ -2317,7 +2300,7 @@ void GPU_state_init(void) glPixelTransferi(GL_BLUE_BIAS, 0); glPixelTransferi(GL_ALPHA_SCALE, 1); glPixelTransferi(GL_ALPHA_BIAS, 0); - + glPixelTransferi(GL_DEPTH_BIAS, 0); glPixelTransferi(GL_DEPTH_SCALE, 1); glDepthRange(0.0, 1.0); @@ -2335,6 +2318,26 @@ void GPU_state_init(void) GPU_basic_shader_bind(GPU_SHADER_USE_COLOR); } +void GPU_enable_program_point_size(void) +{ +#ifdef __APPLE__ + /* TODO: remove this when we switch to core profile */ + glEnable(GL_VERTEX_PROGRAM_POINT_SIZE); +#else + glEnable(GL_PROGRAM_POINT_SIZE); +#endif +} + +void GPU_disable_program_point_size(void) +{ +#ifdef __APPLE__ + /* TODO: remove this when we switch to core profile */ + glDisable(GL_VERTEX_PROGRAM_POINT_SIZE); +#else + glDisable(GL_PROGRAM_POINT_SIZE); +#endif +} + #ifdef WITH_OPENSUBDIV /* Update face-varying variables offset which might be * different from mesh to mesh sharing the same material. diff --git a/source/blender/gpu/intern/gpu_extensions.c b/source/blender/gpu/intern/gpu_extensions.c index e0ce87d0e68..d7ed65e853e 100644 --- a/source/blender/gpu/intern/gpu_extensions.c +++ b/source/blender/gpu/intern/gpu_extensions.c @@ -56,10 +56,8 @@ /* Extensions support */ /* -- extension: version of GL that absorbs it + * EXT_gpu_shader4: 3.0 * ARB_framebuffer object: 3.0 - * EXT_framebuffer_object: 3.0 - * EXT_framebuffer_blit: 3.0 - * EXT_framebuffer_multisample: 3.0 * EXT_framebuffer_multisample_blit_scaled: ??? * ARB_draw_instanced: 3.1 * ARB_texture_multisample: 3.2 @@ -71,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; @@ -123,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); @@ -130,8 +140,21 @@ void GPU_get_dfdy_factors(float fac[2]) void gpu_extensions_init(void) { - /* BLI_assert(GLEW_VERSION_2_1); */ - /* ^-- maybe a bit extreme? */ + /* during 2.8 development each platform has its own OpenGL minimum requirements + * final 2.8 release will be unified on OpenGL 3.3 core profile, no required extensions + * see developer.blender.org/T49012 for details + */ +#ifdef _WIN32 + BLI_assert(GLEW_VERSION_3_3); +#elif defined(__APPLE__) + BLI_assert(GLEW_VERSION_2_1 && GLEW_EXT_gpu_shader4 + && GLEW_ARB_framebuffer_object + && GLEW_ARB_draw_elements_base_vertex + && GLEW_APPLE_flush_buffer_range); +#else + BLI_assert(GLEW_VERSION_3_3 || (GLEW_VERSION_3_0 && GLEW_ARB_draw_elements_base_vertex)); + /* vendor driver || Mesa compatibility profile */ +#endif glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, &GG.maxtextures); @@ -143,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); @@ -249,6 +275,8 @@ void gpu_extensions_exit(void) bool GPU_legacy_support(void) { /* return whether or not current GL context is compatible with legacy OpenGL */ + /* (will be removed after switching to core profile) */ + static bool checked = false; static bool support = true; diff --git a/source/blender/gpu/intern/gpu_framebuffer.c b/source/blender/gpu/intern/gpu_framebuffer.c index f62ef677434..3b44abb479c 100644 --- a/source/blender/gpu/intern/gpu_framebuffer.c +++ b/source/blender/gpu/intern/gpu_framebuffer.c @@ -54,44 +54,37 @@ struct GPUFrameBuffer { static void GPU_print_framebuffer_error(GLenum status, char err_out[256]) { + const char *format = "GPUFrameBuffer: framebuffer status %s\n"; const char *err = "unknown"; +#define format_status(X) \ + case GL_FRAMEBUFFER_##X: err = "GL_FRAMEBUFFER_"#X; \ + break; + switch (status) { - case GL_FRAMEBUFFER_COMPLETE_EXT: - break; - case GL_INVALID_OPERATION: - err = "Invalid operation"; - break; - case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT: - err = "Incomplete attachment"; - break; - case GL_FRAMEBUFFER_UNSUPPORTED_EXT: - err = "Unsupported framebuffer format"; - break; - case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT: - err = "Missing attachment"; - break; - case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT: - err = "Attached images must have same dimensions"; - break; - case GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT: - err = "Attached images must have same format"; - break; - case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT: - err = "Missing draw buffer"; - break; - case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT: - err = "Missing read buffer"; - break; + /* success */ + format_status(COMPLETE) + /* errors shared by OpenGL desktop & ES */ + format_status(INCOMPLETE_ATTACHMENT) + format_status(INCOMPLETE_MISSING_ATTACHMENT) + format_status(UNSUPPORTED) +#if 0 /* for OpenGL ES only */ + format_status(INCOMPLETE_DIMENSIONS) +#else /* for desktop GL only */ + format_status(INCOMPLETE_DRAW_BUFFER) + format_status(INCOMPLETE_READ_BUFFER) + format_status(INCOMPLETE_MULTISAMPLE) + format_status(UNDEFINED) +#endif } +#undef format_status + if (err_out) { - BLI_snprintf(err_out, 256, "GPUFrameBuffer: framebuffer incomplete error %d '%s'", - (int)status, err); + BLI_snprintf(err_out, 256, format, err); } else { - fprintf(stderr, "GPUFrameBuffer: framebuffer incomplete error %d '%s'\n", - (int)status, err); + fprintf(stderr, format, err); } } @@ -101,41 +94,33 @@ GPUFrameBuffer *GPU_framebuffer_create(void) { GPUFrameBuffer *fb; - if (!(GLEW_VERSION_3_0 || GLEW_ARB_framebuffer_object || - (GLEW_EXT_framebuffer_object && GLEW_EXT_framebuffer_blit))) - { - return NULL; - } - fb = MEM_callocN(sizeof(GPUFrameBuffer), "GPUFrameBuffer"); - glGenFramebuffersEXT(1, &fb->object); + glGenFramebuffers(1, &fb->object); if (!fb->object) { - fprintf(stderr, "GPUFFrameBuffer: framebuffer gen failed. %d\n", - (int)glGetError()); + fprintf(stderr, "GPUFFrameBuffer: framebuffer gen failed.\n"); GPU_framebuffer_free(fb); return NULL; } /* make sure no read buffer is enabled, so completeness check will not fail. We set those at binding time */ - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fb->object); + glBindFramebuffer(GL_FRAMEBUFFER, fb->object); glReadBuffer(GL_NONE); glDrawBuffer(GL_NONE); - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); + glBindFramebuffer(GL_FRAMEBUFFER, 0); return fb; } -int GPU_framebuffer_texture_attach(GPUFrameBuffer *fb, GPUTexture *tex, int slot, char err_out[256]) +bool GPU_framebuffer_texture_attach(GPUFrameBuffer *fb, GPUTexture *tex, int slot) { GLenum attachment; - GLenum error; if (slot >= GPU_FB_MAX_SLOTS) { fprintf(stderr, "Attaching to index %d framebuffer slot unsupported. " "Use at most %d\n", slot, GPU_FB_MAX_SLOTS); - return 0; + return false; } if ((G.debug & G_DEBUG)) { @@ -147,27 +132,16 @@ int GPU_framebuffer_texture_attach(GPUFrameBuffer *fb, GPUTexture *tex, int slot } if (GPU_texture_depth(tex)) - attachment = GL_DEPTH_ATTACHMENT_EXT; + attachment = GL_DEPTH_ATTACHMENT; else - attachment = GL_COLOR_ATTACHMENT0_EXT + slot; + attachment = GL_COLOR_ATTACHMENT0 + slot; - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fb->object); + glBindFramebuffer(GL_FRAMEBUFFER, fb->object); GG.currentfb = fb->object; - /* Clean glError buffer. */ - while (glGetError() != GL_NO_ERROR) {} - - glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, attachment, + glFramebufferTexture2D(GL_FRAMEBUFFER, attachment, GPU_texture_target(tex), GPU_texture_opengl_bindcode(tex), 0); - error = glGetError(); - - if (error == GL_INVALID_OPERATION) { - GPU_framebuffer_restore(); - GPU_print_framebuffer_error(error, err_out); - return 0; - } - if (GPU_texture_depth(tex)) fb->depthtex = tex; else @@ -175,7 +149,7 @@ int GPU_framebuffer_texture_attach(GPUFrameBuffer *fb, GPUTexture *tex, int slot GPU_texture_framebuffer_set(tex, fb, slot); - return 1; + return true; } void GPU_framebuffer_texture_detach(GPUTexture *tex) @@ -188,21 +162,21 @@ void GPU_framebuffer_texture_detach(GPUTexture *tex) return; if (GG.currentfb != fb->object) { - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fb->object); + glBindFramebuffer(GL_FRAMEBUFFER, fb->object); GG.currentfb = fb->object; } if (GPU_texture_depth(tex)) { fb->depthtex = NULL; - attachment = GL_DEPTH_ATTACHMENT_EXT; + attachment = GL_DEPTH_ATTACHMENT; } else { BLI_assert(fb->colortex[fb_attachment] == tex); fb->colortex[fb_attachment] = NULL; - attachment = GL_COLOR_ATTACHMENT0_EXT + fb_attachment; + attachment = GL_COLOR_ATTACHMENT0 + fb_attachment; } - glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, attachment, GPU_texture_target(tex), 0, 0); + glFramebufferTexture2D(GL_FRAMEBUFFER, attachment, GPU_texture_target(tex), 0, 0); GPU_texture_framebuffer_set(tex, NULL, -1); } @@ -222,7 +196,7 @@ void GPU_texture_bind_as_framebuffer(GPUTexture *tex) glDisable(GL_SCISSOR_TEST); /* bind framebuffer */ - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fb->object); + glBindFramebuffer(GL_FRAMEBUFFER, fb->object); if (GPU_texture_depth(tex)) { glDrawBuffer(GL_NONE); @@ -230,8 +204,8 @@ void GPU_texture_bind_as_framebuffer(GPUTexture *tex) } else { /* last bound prevails here, better allow explicit control here too */ - glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT + fb_attachment); - glReadBuffer(GL_COLOR_ATTACHMENT0_EXT + fb_attachment); + glDrawBuffer(GL_COLOR_ATTACHMENT0 + fb_attachment); + glReadBuffer(GL_COLOR_ATTACHMENT0 + fb_attachment); } if (GPU_texture_target(tex) == GL_TEXTURE_2D_MULTISAMPLE) { @@ -260,7 +234,7 @@ void GPU_framebuffer_slots_bind(GPUFrameBuffer *fb, int slot) for (i = 0; i < 4; i++) { if (fb->colortex[i]) { - attachments[numslots] = GL_COLOR_ATTACHMENT0_EXT + i; + attachments[numslots] = GL_COLOR_ATTACHMENT0 + i; numslots++; } } @@ -270,11 +244,11 @@ void GPU_framebuffer_slots_bind(GPUFrameBuffer *fb, int slot) glDisable(GL_SCISSOR_TEST); /* bind framebuffer */ - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fb->object); + glBindFramebuffer(GL_FRAMEBUFFER, fb->object); /* last bound prevails here, better allow explicit control here too */ glDrawBuffers(numslots, attachments); - glReadBuffer(GL_COLOR_ATTACHMENT0_EXT + slot); + glReadBuffer(GL_COLOR_ATTACHMENT0 + slot); /* push matrices and set default viewport and matrix */ glViewport(0, 0, GPU_texture_width(fb->colortex[slot]), GPU_texture_height(fb->colortex[slot])); @@ -286,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)) { @@ -301,15 +312,14 @@ void GPU_framebuffer_texture_unbind(GPUFrameBuffer *UNUSED(fb), GPUTexture *UNUS void GPU_framebuffer_bind_no_save(GPUFrameBuffer *fb, int slot) { - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fb->object); + glBindFramebuffer(GL_FRAMEBUFFER, fb->object); /* last bound prevails here, better allow explicit control here too */ - glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT + slot); - glReadBuffer(GL_COLOR_ATTACHMENT0_EXT + slot); + glDrawBuffer(GL_COLOR_ATTACHMENT0 + slot); + glReadBuffer(GL_COLOR_ATTACHMENT0 + 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) @@ -319,22 +329,17 @@ bool GPU_framebuffer_bound(GPUFrameBuffer *fb) bool GPU_framebuffer_check_valid(GPUFrameBuffer *fb, char err_out[256]) { - GLenum status; - - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fb->object); + glBindFramebuffer(GL_FRAMEBUFFER, fb->object); GG.currentfb = fb->object; - - /* Clean glError buffer. */ - while (glGetError() != GL_NO_ERROR) {} - - status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT); - - if (status != GL_FRAMEBUFFER_COMPLETE_EXT) { + + GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER); + + if (status != GL_FRAMEBUFFER_COMPLETE) { GPU_framebuffer_restore(); GPU_print_framebuffer_error(status, err_out); return false; } - + return true; } @@ -351,10 +356,10 @@ void GPU_framebuffer_free(GPUFrameBuffer *fb) } if (fb->object) { - glDeleteFramebuffersEXT(1, &fb->object); + glDeleteFramebuffers(1, &fb->object); if (GG.currentfb == fb->object) { - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); + glBindFramebuffer(GL_FRAMEBUFFER, 0); GG.currentfb = 0; } } @@ -365,7 +370,7 @@ void GPU_framebuffer_free(GPUFrameBuffer *fb) void GPU_framebuffer_restore(void) { if (GG.currentfb != 0) { - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); + glBindFramebuffer(GL_FRAMEBUFFER, 0); GG.currentfb = 0; } } @@ -390,8 +395,8 @@ void GPU_framebuffer_blur( /* We do the bind ourselves rather than using GPU_framebuffer_texture_bind() to avoid * pushing unnecessary matrices onto the OpenGL stack. */ - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, blurfb->object); - glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT); + glBindFramebuffer(GL_FRAMEBUFFER, blurfb->object); + glDrawBuffer(GL_COLOR_ATTACHMENT0); /* avoid warnings from texture binding */ GG.currentfb = blurfb->object; @@ -423,8 +428,8 @@ void GPU_framebuffer_blur( /* Blurring vertically */ - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fb->object); - glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT); + glBindFramebuffer(GL_FRAMEBUFFER, fb->object); + glDrawBuffer(GL_COLOR_ATTACHMENT0); GG.currentfb = fb->object; @@ -443,6 +448,40 @@ void GPU_framebuffer_blur( GPU_shader_unbind(); } +void GPU_framebuffer_blit(GPUFrameBuffer *fb_read, int read_slot, GPUFrameBuffer *fb_write, int write_slot, bool use_depth) +{ + GPUTexture *read_tex = (use_depth) ? fb_read->depthtex : fb_read->colortex[read_slot]; + GPUTexture *write_tex = (use_depth) ? fb_write->depthtex : fb_write->colortex[write_slot]; + int read_attach = (use_depth) ? GL_DEPTH_ATTACHMENT : GL_COLOR_ATTACHMENT0 + GPU_texture_framebuffer_attachment(read_tex); + int write_attach = (use_depth) ? GL_DEPTH_ATTACHMENT : GL_COLOR_ATTACHMENT0 + GPU_texture_framebuffer_attachment(write_tex); + int read_bind = GPU_texture_opengl_bindcode(read_tex); + int write_bind = GPU_texture_opengl_bindcode(write_tex); + const int read_w = GPU_texture_width(read_tex); + const int read_h = GPU_texture_height(read_tex); + const int write_w = GPU_texture_width(write_tex); + const int write_h = GPU_texture_height(write_tex); + + /* read from multi-sample buffer */ + glBindFramebuffer(GL_READ_FRAMEBUFFER, fb_read->object); + glFramebufferTexture2D( + GL_READ_FRAMEBUFFER, read_attach, + GL_TEXTURE_2D, read_bind, 0); + BLI_assert(glCheckFramebufferStatusEXT(GL_READ_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE); + + /* write into new single-sample buffer */ + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fb_write->object); + glFramebufferTexture2D( + GL_DRAW_FRAMEBUFFER, write_attach, + GL_TEXTURE_2D, write_bind, 0); + BLI_assert(glCheckFramebufferStatusEXT(GL_DRAW_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE); + + glBlitFramebuffer(0, 0, read_w, read_h, 0, 0, write_w, write_h, (use_depth) ? GL_DEPTH_BUFFER_BIT : GL_COLOR_BUFFER_BIT, GL_NEAREST); + + /* Restore previous framebuffer */ + glBindFramebuffer(GL_FRAMEBUFFER, GG.currentfb); + glDrawBuffer(GL_COLOR_ATTACHMENT0); +} + /* GPUOffScreen */ struct GPUOffScreen { @@ -464,12 +503,7 @@ GPUOffScreen *GPU_offscreen_create(int width, int height, int samples, char err_ } if (samples) { - if (!GLEW_EXT_framebuffer_multisample || - !GLEW_ARB_texture_multisample || - /* Only needed for GPU_offscreen_read_pixels. - * We could add an arg if we intend to use multi-sample - * offscreen buffers w/o reading their pixels */ - !GLEW_EXT_framebuffer_blit || + if (!GLEW_ARB_texture_multisample || /* This is required when blitting from a multi-sampled buffers, * even though we're not scaling. */ !GLEW_EXT_framebuffer_multisample_blit_scaled) @@ -484,18 +518,18 @@ GPUOffScreen *GPU_offscreen_create(int width, int height, int samples, char err_ return NULL; } - if (!GPU_framebuffer_texture_attach(ofs->fb, ofs->depth, 0, err_out)) { + if (!GPU_framebuffer_texture_attach(ofs->fb, ofs->depth, 0)) { GPU_offscreen_free(ofs); return NULL; } - ofs->color = GPU_texture_create_2D_multisample(width, height, NULL, GPU_HDR_NONE, samples, err_out); + ofs->color = GPU_texture_create_2D_multisample(width, height, NULL, samples, err_out); if (!ofs->color) { GPU_offscreen_free(ofs); return NULL; } - if (!GPU_framebuffer_texture_attach(ofs->fb, ofs->color, 0, err_out)) { + if (!GPU_framebuffer_texture_attach(ofs->fb, ofs->color, 0)) { GPU_offscreen_free(ofs); return NULL; } @@ -569,37 +603,37 @@ void GPU_offscreen_read_pixels(GPUOffScreen *ofs, int type, void *pixels) #ifdef USE_FBO_CTX_SWITCH /* read from multi-sample buffer */ - glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, ofs->color->fb->object); - glFramebufferTexture2DEXT( - GL_READ_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT + ofs->color->fb_attachment, + glBindFramebuffer(GL_READ_FRAMEBUFFER, ofs->color->fb->object); + glFramebufferTexture2D( + GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + ofs->color->fb_attachment, GL_TEXTURE_2D_MULTISAMPLE, ofs->color->bindcode, 0); - status = glCheckFramebufferStatusEXT(GL_READ_FRAMEBUFFER_EXT); - if (status != GL_FRAMEBUFFER_COMPLETE_EXT) { + status = glCheckFramebufferStatusEXT(GL_READ_FRAMEBUFFER); + if (status != GL_FRAMEBUFFER_COMPLETE) { goto finally; } #endif /* write into new single-sample buffer */ - glGenFramebuffersEXT(1, &fbo_blit); - glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, fbo_blit); - glFramebufferTexture2DEXT( - GL_DRAW_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, + glGenFramebuffers(1, &fbo_blit); + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo_blit); + glFramebufferTexture2D( + GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tex_blit, 0); - status = glCheckFramebufferStatusEXT(GL_DRAW_FRAMEBUFFER_EXT); - if (status != GL_FRAMEBUFFER_COMPLETE_EXT) { + status = glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER); + if (status != GL_FRAMEBUFFER_COMPLETE) { goto finally; } /* perform the copy */ - glBlitFramebufferEXT(0, 0, w, h, 0, 0, w, h, GL_COLOR_BUFFER_BIT, GL_NEAREST); + glBlitFramebuffer(0, 0, w, h, 0, 0, w, h, GL_COLOR_BUFFER_BIT, GL_NEAREST); /* read the results */ - glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, fbo_blit); + glBindFramebuffer(GL_READ_FRAMEBUFFER, fbo_blit); glReadPixels(0, 0, w, h, GL_RGBA, type, pixels); #ifdef USE_FBO_CTX_SWITCH /* restore the original frame-bufer */ - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, ofs->color->fb->object); + glBindFramebuffer(GL_FRAMEBUFFER, ofs->color->fb->object); #undef USE_FBO_CTX_SWITCH #endif @@ -610,10 +644,8 @@ finally: glDeleteTextures(1, &tex_blit); } if (fbo_blit) { - glDeleteFramebuffersEXT(1, &fbo_blit); + glDeleteFramebuffers(1, &fbo_blit); } - - GPU_ASSERT_NO_GL_ERRORS("Read Multi-Sample Pixels"); } else { glReadPixels(0, 0, w, h, GL_RGBA, type, pixels); diff --git a/source/blender/gpu/intern/gpu_immediate.c b/source/blender/gpu/intern/gpu_immediate.c new file mode 100644 index 00000000000..5188ca4c0e2 --- /dev/null +++ b/source/blender/gpu/intern/gpu_immediate.c @@ -0,0 +1,81 @@ +/* + * ***** 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) 2016 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): Mike Erwin + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#include "GPU_immediate.h" +#include "GPU_matrix.h" +#include "UI_resources.h" +#include "BLI_utildefines.h" + +#include "gpu_shader_private.h" + +void immBindBuiltinProgram(GPUBuiltinShader shader_id) +{ + GPUShader *shader = GPU_shader_get_builtin_shader(shader_id); + immBindProgram(shader->program); +} + +void immUniformThemeColor(int color_id) +{ + float color[4]; + UI_GetThemeColor4fv(color_id, color); + immUniformColor4fv(color); +} + +void immUniformThemeColorShade(int color_id, int offset) +{ + float color[4]; + UI_GetThemeColorShade4fv(color_id, offset, color); + immUniformColor4fv(color); +} + +void immUniformThemeColorShadeAlpha(int color_id, int color_offset, int alpha_offset) +{ + float color[4]; + UI_GetThemeColorShadeAlpha4fv(color_id, color_offset, alpha_offset, color); + immUniformColor4fv(color); +} + +void immUniformThemeColorBlendShade(int color_id1, int color_id2, float fac, int offset) +{ + float color[4]; + UI_GetThemeColorBlendShade4fv(color_id1, color_id2, fac, offset, color); + immUniformColor4fv(color); +} + +void immUniformThemeColorBlend(int color_id1, int color_id2, float fac) +{ + uint8_t color[3]; + UI_GetThemeColorBlend3ubv(color_id1, color_id2, fac, color); + immUniformColor3ubv(color); +} + +void immThemeColorShadeAlpha(int colorid, int coloffset, int alphaoffset) +{ + unsigned char col[4]; + UI_GetThemeColorShadeAlpha4ubv(colorid, coloffset, alphaoffset, col); + immUniformColor4ub(col[0], col[1], col[2], col[3]); +} diff --git a/source/blender/gpu/intern/gpu_init_exit.c b/source/blender/gpu/intern/gpu_init_exit.c index c72c83b6b07..7a6b1ff6c70 100644 --- a/source/blender/gpu/intern/gpu_init_exit.c +++ b/source/blender/gpu/intern/gpu_init_exit.c @@ -31,7 +31,8 @@ #include "BLI_sys_types.h" #include "GPU_init_exit.h" /* interface */ - +#include "GPU_immediate.h" +#include "GPU_batch.h" #include "BKE_global.h" #include "intern/gpu_codegen.h" @@ -59,14 +60,22 @@ void GPU_init(void) if (G.debug & G_DEBUG_GPU) gpu_debug_init(); + gpu_batch_init(); + + immInit(); } void GPU_exit(void) { + immDestroy(); + + gpu_batch_exit(); + if (G.debug & G_DEBUG_GPU) gpu_debug_exit(); + gpu_codegen_exit(); gpu_extensions_exit(); /* must come last */ diff --git a/source/blender/gpu/intern/gpu_material.c b/source/blender/gpu/intern/gpu_material.c index 4e2043471b6..28cf7bd1c76 100644 --- a/source/blender/gpu/intern/gpu_material.c +++ b/source/blender/gpu/intern/gpu_material.c @@ -2369,6 +2369,11 @@ static void gpu_lamp_shadow_free(GPULamp *lamp) } } +static GPUTexture *gpu_lamp_create_vsm_shadow_map(int size) +{ + return GPU_texture_create_2D_custom(size, size, 2, GPU_RG32F, NULL, NULL); +} + GPULamp *GPU_lamp_from_blender(Scene *scene, Object *ob, Object *par) { Lamp *la; @@ -2409,19 +2414,19 @@ GPULamp *GPU_lamp_from_blender(Scene *scene, Object *ob, Object *par) return lamp; } - if (!GPU_framebuffer_texture_attach(lamp->fb, lamp->depthtex, 0, NULL)) { + if (!GPU_framebuffer_texture_attach(lamp->fb, lamp->depthtex, 0)) { gpu_lamp_shadow_free(lamp); return lamp; } /* Shadow color map */ - lamp->tex = GPU_texture_create_vsm_shadow_map(lamp->size, NULL); + lamp->tex = gpu_lamp_create_vsm_shadow_map(lamp->size); if (!lamp->tex) { gpu_lamp_shadow_free(lamp); return lamp; } - if (!GPU_framebuffer_texture_attach(lamp->fb, lamp->tex, 0, NULL)) { + if (!GPU_framebuffer_texture_attach(lamp->fb, lamp->tex, 0)) { gpu_lamp_shadow_free(lamp); return lamp; } @@ -2438,13 +2443,13 @@ GPULamp *GPU_lamp_from_blender(Scene *scene, Object *ob, Object *par) return lamp; } - lamp->blurtex = GPU_texture_create_vsm_shadow_map(lamp->size * 0.5, NULL); + lamp->blurtex = gpu_lamp_create_vsm_shadow_map(lamp->size * 0.5); if (!lamp->blurtex) { gpu_lamp_shadow_free(lamp); return lamp; } - if (!GPU_framebuffer_texture_attach(lamp->blurfb, lamp->blurtex, 0, NULL)) { + if (!GPU_framebuffer_texture_attach(lamp->blurfb, lamp->blurtex, 0)) { gpu_lamp_shadow_free(lamp); return lamp; } @@ -2466,7 +2471,7 @@ GPULamp *GPU_lamp_from_blender(Scene *scene, Object *ob, Object *par) return lamp; } - if (!GPU_framebuffer_texture_attach(lamp->fb, lamp->tex, 0, NULL)) { + if (!GPU_framebuffer_texture_attach(lamp->fb, lamp->tex, 0)) { gpu_lamp_shadow_free(lamp); return lamp; } diff --git a/source/blender/gpu/intern/gpu_matrix.c b/source/blender/gpu/intern/gpu_matrix.c new file mode 100644 index 00000000000..a987e3ba1ce --- /dev/null +++ b/source/blender/gpu/intern/gpu_matrix.c @@ -0,0 +1,710 @@ +/* + * ***** 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 ipmlied 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) 2012 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): Alexandr Kuznetsov, Jason Wilkins, Mike Erwin + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file source/blender/gpu/intern/gpu_matrix.c + * \ingroup gpu + */ + +#include "GPU_matrix.h" + +#include "BLI_math_matrix.h" +#include "BLI_math_rotation.h" +#include "BLI_math_vector.h" + + +#define DEBUG_MATRIX_BIND 0 + +#define MATRIX_STACK_DEPTH 32 + +typedef float Mat4[4][4]; +typedef float Mat3[3][3]; + +typedef struct { + Mat4 ModelViewStack3D[MATRIX_STACK_DEPTH]; + Mat4 ProjectionMatrix3D; + + Mat3 ModelViewStack2D[MATRIX_STACK_DEPTH]; + Mat3 ProjectionMatrix2D; + + MatrixMode mode; + unsigned top; /* of current stack (would have to replicate if gpuResume2D/3D are implemented) */ + + bool dirty; + + /* TODO: cache of derived matrices (Normal, MVP, inverse MVP, etc) + * generate as needed for shaders, invalidate when original matrices change + * + * TODO: separate Model from View transform? Batches/objects have model, + * camera/eye has view & projection + */ +} MatrixState; + +static MatrixState state; /* TODO(merwin): make part of GPUContext, alongside immediate mode & state tracker */ + +#define ModelView3D state.ModelViewStack3D[state.top] +#define ModelView2D state.ModelViewStack2D[state.top] +#define Projection3D state.ProjectionMatrix3D +#define Projection2D state.ProjectionMatrix2D + +void gpuMatrixInit(void) +{ + memset(&state, 0, sizeof(MatrixState)); +} + +void gpuMatrixBegin2D(void) +{ + state.mode = MATRIX_MODE_2D; + state.top = 0; + unit_m3(ModelView2D); + gpuOrtho2D(-1.0f, +1.0f, -1.0f, +1.0f); // or identity? +} + +void gpuMatrixBegin3D(void) +{ + state.mode = MATRIX_MODE_3D; + state.top = 0; + unit_m4(ModelView3D); + gpuOrtho(-1.0f, +1.0f, -1.0f, +1.0f, -1.0f, +1.0f); // or identity? +} + +#if SUPPORT_LEGACY_MATRIX +void gpuMatrixBegin3D_legacy(void) +{ + /* copy top matrix from each legacy stack into new fresh stack */ + state.mode = MATRIX_MODE_3D; + state.top = 0; + state.dirty = true; + glGetFloatv(GL_MODELVIEW_MATRIX, (float*)ModelView3D); + glGetFloatv(GL_PROJECTION_MATRIX, (float*)Projection3D); +} +#endif + +void gpuMatrixEnd(void) +{ + state.mode = MATRIX_MODE_INACTIVE; +} + + +#ifdef WITH_GPU_SAFETY + +/* Check if matrix is numerically good */ +static void checkmat(cosnt float *m) +{ + const int n = state.mode == MATRIX_MODE_3D ? 16 : 9; + for (int i = 0; i < n; i++) { +#if _MSC_VER + BLI_assert(_finite(m[i])); +#else + BLI_assert(!isinf(m[i])); +#endif + } +} + +#define CHECKMAT(m) checkmat((const float*)m) + +#else + +#define CHECKMAT(m) + +#endif + + +void gpuPushMatrix(void) +{ + BLI_assert(state.mode != MATRIX_MODE_INACTIVE); + BLI_assert(state.top < MATRIX_STACK_DEPTH); + state.top++; + if (state.mode == MATRIX_MODE_3D) + copy_m4_m4(ModelView3D, state.ModelViewStack3D[state.top - 1]); + else + copy_m3_m3(ModelView2D, state.ModelViewStack2D[state.top - 1]); +} + +void gpuPopMatrix(void) +{ + BLI_assert(state.mode != MATRIX_MODE_INACTIVE); + BLI_assert(state.top > 0); + state.top--; + state.dirty = true; +} + +void gpuLoadMatrix3D(const float m[4][4]) +{ + BLI_assert(state.mode == MATRIX_MODE_3D); + copy_m4_m4(ModelView3D, m); + CHECKMAT(ModelView3D); + state.dirty = true; +} + +void gpuLoadMatrix2D(const float m[3][3]) +{ + BLI_assert(state.mode == MATRIX_MODE_2D); + copy_m3_m3(ModelView2D, m); + CHECKMAT(ModelView2D); + state.dirty = true; +} + +void gpuLoadIdentity(void) +{ + switch (state.mode) { + case MATRIX_MODE_3D: + unit_m4(ModelView3D); + break; + case MATRIX_MODE_2D: + unit_m3(ModelView2D); + break; + default: + BLI_assert(false); + } + state.dirty = true; +} + +void gpuTranslate2f(float x, float y) +{ + Mat3 m; + unit_m3(m); + m[2][0] = x; + m[2][1] = y; + gpuMultMatrix2D(m); +} + +void gpuTranslate2fv(const float vec[2]) +{ + gpuTranslate2f(vec[0], vec[1]); +} + +void gpuTranslate3f(float x, float y, float z) +{ + BLI_assert(state.mode == MATRIX_MODE_3D); +#if 1 + translate_m4(ModelView3D, x, y, z); + CHECKMAT(ModelView3D); +#else /* above works well in early testing, below is generic version */ + Mat4 m; + unit_m4(m); + m[3][0] = x; + m[3][1] = y; + m[3][2] = z; + gpuMultMatrix3D(m); +#endif + state.dirty = true; +} + +void gpuTranslate3fv(const float vec[3]) +{ + gpuTranslate3f(vec[0], vec[1], vec[2]); +} + +void gpuScaleUniform(float factor) +{ + switch (state.mode) { + case MATRIX_MODE_3D: + { + Mat4 m; + scale_m4_fl(m, factor); + gpuMultMatrix3D(m); + break; + } + case MATRIX_MODE_2D: + { + #if 0 + Mat3 m; + scale_m3_fl(m, factor); + /* this does 3D scaling in a 3x3 matrix. Can 2D scaling use this safely, or must set m[2][2] = 1.0? */ + #else + Mat3 m = {{0.0f}}; + m[0][0] = factor; + m[1][1] = factor; + m[2][2] = 1.0f; + #endif + gpuMultMatrix2D(m); + break; + } + default: + BLI_assert(false); + } +} + +void gpuScale2f(float x, float y) +{ + Mat3 m = {{0.0f}}; + m[0][0] = x; + m[1][1] = y; + m[2][2] = 1.0f; + gpuMultMatrix2D(m); +} + +void gpuScale2fv(const float vec[2]) +{ + gpuScale2f(vec[0], vec[1]); +} + +void gpuScale3f(float x, float y, float z) +{ + Mat4 m = {{0.0f}}; + m[0][0] = x; + m[1][1] = y; + m[2][2] = z; + m[3][3] = 1.0f; + gpuMultMatrix3D(m); +} + +void gpuScale3fv(const float vec[3]) +{ + gpuScale3f(vec[0], vec[1], vec[2]); +} + +void gpuMultMatrix3D(const float m[4][4]) +{ + BLI_assert(state.mode == MATRIX_MODE_3D); + mul_m4_m4_post(ModelView3D, m); + CHECKMAT(ModelView3D); + state.dirty = true; +} + +void gpuMultMatrix2D(const float m[3][3]) +{ + BLI_assert(state.mode == MATRIX_MODE_2D); + mul_m3_m3_post(ModelView2D, m); + CHECKMAT(ModelView2D); + state.dirty = true; +} + +void gpuRotate3f(float deg, float x, float y, float z) +{ + const float axis[3] = {x, y, z}; + gpuRotate3fv(deg, axis); +} + +void gpuRotate3fv(float deg, const float axis[3]) +{ + Mat4 m; + axis_angle_to_mat4(m, axis, DEG2RADF(deg)); + gpuMultMatrix3D(m); +} + +void gpuRotateAxis(float deg, char axis) +{ + BLI_assert(state.mode == MATRIX_MODE_3D); +#if 1 /* rotate_m4 works in place, right? */ + rotate_m4(ModelView3D, axis, DEG2RADF(deg)); + CHECKMAT(ModelView3D); + state.dirty = true; +#else /* rotate_m4 creates a new matrix */ + Mat4 m; + rotate_m4(m, axis, DEG2RADF(deg)); + gpuMultMatrix3D(m); +#endif +} + +static void mat4_ortho_set(float m[4][4], float left, float right, float bottom, float top, float near, float far) +{ + m[0][0] = 2.0f / (right - left); + m[1][0] = 0.0f; + m[2][0] = 0.0f; + m[3][0] = -(right + left) / (right - left); + + m[0][1] = 0.0f; + m[1][1] = 2.0f / (top - bottom); + m[2][1] = 0.0f; + m[3][1] = -(top + bottom) / (top - bottom); + + m[0][2] = 0.0f; + m[1][2] = 0.0f; + m[2][2] = -2.0f / (far - near); + m[3][2] = -(far + near) / (far - near); + + m[0][3] = 0.0f; + m[1][3] = 0.0f; + m[2][3] = 0.0f; + m[3][3] = 1.0f; + + state.dirty = true; +} + +static void mat4_frustum_set(float m[][4], float left, float right, float bottom, float top, float near, float far) +{ + m[0][0] = 2.0f * near / (right - left); + m[1][0] = 0.0f; + m[2][0] = (right + left) / (right - left); + m[3][0] = 0.0f; + + m[0][1] = 0.0f; + m[1][1] = 2.0f * near / (top - bottom); + m[2][1] = (top + bottom) / (top - bottom); + m[3][1] = 0.0f; + + m[0][2] = 0.0f; + m[1][2] = 0.0f; + m[2][2] = -(far + near) / (far - near); + m[3][2] = -2.0f * far * near / (far - near); + + m[0][3] = 0.0f; + m[1][3] = 0.0f; + m[2][3] = -1.0f; + m[3][3] = 0.0f; + + state.dirty = true; +} + +static void mat4_look_from_origin(float m[4][4], float lookdir[3], float camup[3]) +{ +/* This function is loosely based on Mesa implementation. + * + * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008) + * Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice including the dates of first publication and + * either this permission notice or a reference to + * http://oss.sgi.com/projects/FreeB/ + * shall be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF + * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * Except as contained in this notice, the name of Silicon Graphics, Inc. + * shall not be used in advertising or otherwise to promote the sale, use or + * other dealings in this Software without prior written authorization from + * Silicon Graphics, Inc. + */ + + float side[3]; + + normalize_v3(lookdir); + + cross_v3_v3v3(side, lookdir, camup); + + normalize_v3(side); + + cross_v3_v3v3(camup, side, lookdir); + + m[0][0] = side[0]; + m[1][0] = side[1]; + m[2][0] = side[2]; + m[3][0] = 0.0f; + + m[0][1] = camup[0]; + m[1][1] = camup[1]; + m[2][1] = camup[2]; + m[3][1] = 0.0f; + + m[0][2] = -lookdir[0]; + m[1][2] = -lookdir[1]; + m[2][2] = -lookdir[2]; + m[3][2] = 0.0f; + + m[0][3] = 0.0f; + m[1][3] = 0.0f; + m[2][3] = 0.0f; + m[3][3] = 1.0f; + + state.dirty = true; +} + +void gpuOrtho(float left, float right, float bottom, float top, float near, float far) +{ + BLI_assert(state.mode == MATRIX_MODE_3D); + mat4_ortho_set(Projection3D, left, right, bottom, top, near, far); + CHECKMAT(Projection3D); + state.dirty = true; +} + +void gpuOrtho2D(float left, float right, float bottom, float top) +{ + /* TODO: this function, but correct */ + BLI_assert(state.mode == MATRIX_MODE_2D); + Mat4 m; + mat4_ortho_set(m, left, right, bottom, top, -1.0f, 1.0f); + copy_m3_m4(Projection2D, m); + CHECKMAT(Projection2D); + state.dirty = true; +} + +void gpuFrustum(float left, float right, float bottom, float top, float near, float far) +{ + BLI_assert(state.mode == MATRIX_MODE_3D); + mat4_frustum_set(Projection3D, left, right, bottom, top, near, far); + CHECKMAT(Projection3D); + state.dirty = true; +} + +void gpuPerspective(float fovy, float aspect, float near, float far) +{ + float half_height = tanf(fovy * (float)(M_PI / 360.0)) * near; + float half_width = half_height * aspect; + gpuFrustum(-half_width, +half_width, -half_height, +half_height, near, far); +} + +void gpuLookAt(float eyeX, float eyeY, float eyeZ, float centerX, float centerY, float centerZ, float upX, float upY, float upZ) +{ + Mat4 cm; + float lookdir[3]; + float camup[3] = {upX, upY, upZ}; + + lookdir[0] = centerX - eyeX; + lookdir[1] = centerY - eyeY; + lookdir[2] = centerZ - eyeZ; + + mat4_look_from_origin(cm, lookdir, camup); + + gpuMultMatrix3D(cm); + gpuTranslate3f(-eyeX, -eyeY, -eyeZ); +} + +void gpuProject(const float obj[3], const float model[4][4], const float proj[4][4], const GLint view[4], float win[3]) +{ + float v[4]; + + mul_v4_m4v3(v, model, obj); + mul_m4_v4(proj, v); + + win[0] = view[0] + (view[2] * (v[0] + 1)) * 0.5f; + win[1] = view[1] + (view[3] * (v[1] + 1)) * 0.5f; + win[2] = (v[2] + 1) * 0.5f; +} + +bool gpuUnProject(const float win[3], const float model[4][4], const float proj[4][4], const GLint view[4], float obj[3]) +{ + float pm[4][4]; + float in[4]; + float out[4]; + + mul_m4_m4m4(pm, proj, model); + + if (!invert_m4(pm)) { + return false; + } + + in[0] = win[0]; + in[1] = win[1]; + in[2] = win[2]; + in[3] = 1; + + /* Map x and y from window coordinates */ + in[0] = (in[0] - view[0]) / view[2]; + in[1] = (in[1] - view[1]) / view[3]; + + /* Map to range -1 to +1 */ + in[0] = 2 * in[0] - 1; + in[1] = 2 * in[1] - 1; + in[2] = 2 * in[2] - 1; + + mul_v4_m4v3(out, pm, in); + + if (out[3] == 0.0f) { + return false; + } + else { + out[0] /= out[3]; + out[1] /= out[3]; + out[2] /= out[3]; + + obj[0] = out[0]; + obj[1] = out[1]; + obj[2] = out[2]; + + return true; + } +} + +const float *gpuGetModelViewMatrix3D(float m[4][4]) +{ +#if SUPPORT_LEGACY_MATRIX + if (state.mode == MATRIX_MODE_INACTIVE) { + if (m == NULL) { + static Mat4 temp; + m = temp; + } + + glGetFloatv(GL_MODELVIEW_MATRIX, (float*)m); + return (const float*)m; + } +#endif + + BLI_assert(state.mode == MATRIX_MODE_3D); + + if (m) { + copy_m4_m4(m, ModelView3D); + return (const float*)m; + } + else { + return (const float*)ModelView3D; + } +} + +const float *gpuGetProjectionMatrix3D(float m[4][4]) +{ +#if SUPPORT_LEGACY_MATRIX + if (state.mode == MATRIX_MODE_INACTIVE) { + if (m == NULL) { + static Mat4 temp; + m = temp; + } + + glGetFloatv(GL_PROJECTION_MATRIX, (float*)m); + return (const float*)m; + } +#endif + + BLI_assert(state.mode == MATRIX_MODE_3D); + + if (m) { + copy_m4_m4(m, ModelView3D); + return (const float*)m; + } + else { + return (const float*)ModelView3D; + } +} + +const float *gpuGetModelViewProjectionMatrix3D(float m[4][4]) +{ + if (m == NULL) { + static Mat4 temp; + m = temp; + } + +#if SUPPORT_LEGACY_MATRIX + if (state.mode == MATRIX_MODE_INACTIVE) { + Mat4 proj; + glGetFloatv(GL_MODELVIEW_MATRIX, (float*)m); + glGetFloatv(GL_PROJECTION_MATRIX, (float*)proj); + mul_m4_m4_pre(m, proj); + return (const float*)m; + } +#endif + + BLI_assert(state.mode == MATRIX_MODE_3D); + + mul_m4_m4m4(m, Projection3D, ModelView3D); + return (const float*)m; +} + +const float *gpuGetNormalMatrix(float m[3][3]) +{ + if (m == NULL) { + static Mat3 temp3; + m = temp3; + } + + copy_m3_m4(m, (const float (*)[4])gpuGetModelViewMatrix3D(NULL)); + + invert_m3(m); + transpose_m3(m); + + return (const float*)m; +} + +const float *gpuGetNormalMatrixInverse(float m[3][3]) +{ + if (m == NULL) { + static Mat3 temp3; + m = temp3; + } + + gpuGetNormalMatrix(m); + invert_m3(m); + + return (const float*)m; +} + +void gpuBindMatrices(GLuint program) +{ + /* TODO: split this into 2 functions + * 1) get uniform locations & determine 2D or 3D + */ + GLint loc_MV = glGetUniformLocation(program, "ModelViewMatrix"); + GLint loc_P = glGetUniformLocation(program, "ProjectionMatrix"); + GLint loc_MVP = glGetUniformLocation(program, "ModelViewProjectionMatrix"); + GLint loc_N = glGetUniformLocation(program, "NormalMatrix"); + + /* 2) set uniform values to matrix stack values + * program needs to be bound + */ + glUseProgram(program); + + + /* call this portion before a draw call if desired matrices are dirty */ + if (loc_MV != -1) { + #if DEBUG_MATRIX_BIND + puts("setting 3D MV matrix"); + #endif + + glUniformMatrix4fv(loc_MV, 1, GL_FALSE, gpuGetModelViewMatrix3D(NULL)); + } + + if (loc_P != -1) { + #if DEBUG_MATRIX_BIND + puts("setting 3D P matrix"); + #endif + + glUniformMatrix4fv(loc_P, 1, GL_FALSE, gpuGetProjectionMatrix3D(NULL)); + } + + if (loc_MVP != -1) { + #if DEBUG_MATRIX_BIND + puts("setting 3D MVP matrix"); + #endif + + glUniformMatrix4fv(loc_MVP, 1, GL_FALSE, gpuGetModelViewProjectionMatrix3D(NULL)); + } + + if (loc_N != -1) { + #if DEBUG_MATRIX_BIND + puts("setting 3D normal matrix"); + #endif + + glUniformMatrix3fv(loc_N, 1, GL_FALSE, gpuGetNormalMatrix(NULL)); + } + + state.dirty = false; +} + +bool gpuMatricesDirty(void) +{ + return state.dirty; +} + +#if SUPPORT_LEGACY_MATRIX +void gpuMatrixUpdate_legacy(void) +{ + BLI_assert(state.mode == MATRIX_MODE_INACTIVE); + state.dirty = true; +} +#endif diff --git a/source/blender/gpu/intern/gpu_shader.c b/source/blender/gpu/intern/gpu_shader.c index 14f2764b009..e5c1dfb5bcc 100644 --- a/source/blender/gpu/intern/gpu_shader.c +++ b/source/blender/gpu/intern/gpu_shader.c @@ -36,15 +36,80 @@ #include "GPU_compositing.h" #include "GPU_debug.h" #include "GPU_extensions.h" -#include "GPU_glew.h" #include "GPU_shader.h" +#include "GPU_uniformbuffer.h" #include "GPU_texture.h" +#include "gpu_shader_private.h" + /* TODO(sergey): Find better default values for this constants. */ #define MAX_DEFINE_LENGTH 1024 #define MAX_EXT_DEFINE_LENGTH 1024 /* Non-generated shaders */ +extern char datatoc_gpu_shader_depth_only_frag_glsl[]; +extern char datatoc_gpu_shader_uniform_color_frag_glsl[]; +extern char datatoc_gpu_shader_checker_frag_glsl[]; +extern char datatoc_gpu_shader_diag_stripes_frag_glsl[]; +extern char datatoc_gpu_shader_simple_lighting_frag_glsl[]; +extern char datatoc_gpu_shader_flat_color_frag_glsl[]; +extern char datatoc_gpu_shader_flat_color_alpha_test_0_frag_glsl[]; +extern char datatoc_gpu_shader_2D_vert_glsl[]; +extern char datatoc_gpu_shader_2D_flat_color_vert_glsl[]; +extern char datatoc_gpu_shader_2D_smooth_color_vert_glsl[]; +extern char datatoc_gpu_shader_2D_smooth_color_frag_glsl[]; +extern char datatoc_gpu_shader_2D_image_vert_glsl[]; + +extern char datatoc_gpu_shader_3D_image_vert_glsl[]; +extern char datatoc_gpu_shader_image_color_frag_glsl[]; +extern char datatoc_gpu_shader_image_interlace_frag_glsl[]; +extern char datatoc_gpu_shader_image_mask_uniform_color_frag_glsl[]; +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_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_passthrough_vert_glsl[]; + +extern char datatoc_gpu_shader_instance_vert_glsl[]; +extern char datatoc_gpu_shader_instance_variying_size_variying_color_vert_glsl[]; +extern char datatoc_gpu_shader_instance_objectspace_variying_color_vert_glsl[]; +extern char datatoc_gpu_shader_instance_screenspace_variying_color_vert_glsl[]; +extern char datatoc_gpu_shader_instance_screen_aligned_axis_name_vert_glsl[]; + +extern char datatoc_gpu_shader_3D_groundpoint_vert_glsl[]; +extern char datatoc_gpu_shader_3D_groundline_geom_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[]; +extern char datatoc_gpu_shader_point_varying_color_outline_smooth_frag_glsl[]; +extern char datatoc_gpu_shader_point_varying_color_frag_glsl[]; +extern char datatoc_gpu_shader_3D_point_fixed_size_varying_color_vert_glsl[]; +extern char datatoc_gpu_shader_3D_point_varying_size_vert_glsl[]; +extern char datatoc_gpu_shader_3D_point_varying_size_varying_color_vert_glsl[]; +extern char datatoc_gpu_shader_3D_point_uniform_size_smooth_vert_glsl[]; +extern char datatoc_gpu_shader_3D_point_uniform_size_outline_smooth_vert_glsl[]; +extern char datatoc_gpu_shader_2D_point_varying_size_varying_color_vert_glsl[]; +extern char datatoc_gpu_shader_2D_point_uniform_size_smooth_vert_glsl[]; +extern char datatoc_gpu_shader_2D_point_uniform_size_outline_smooth_vert_glsl[]; +extern char datatoc_gpu_shader_2D_point_uniform_size_varying_color_outline_smooth_vert_glsl[]; + +extern char datatoc_gpu_shader_edges_front_back_persp_vert_glsl[]; +extern char datatoc_gpu_shader_edges_front_back_persp_geom_glsl[]; +extern char datatoc_gpu_shader_edges_front_back_persp_legacy_vert_glsl[]; +extern char datatoc_gpu_shader_edges_front_back_ortho_vert_glsl[]; +extern char datatoc_gpu_shader_edges_overlay_vert_glsl[]; +extern char datatoc_gpu_shader_edges_overlay_geom_glsl[]; +extern char datatoc_gpu_shader_edges_overlay_simple_geom_glsl[]; +extern char datatoc_gpu_shader_edges_overlay_frag_glsl[]; +extern char datatoc_gpu_shader_text_vert_glsl[]; +extern char datatoc_gpu_shader_text_frag_glsl[]; +extern char datatoc_gpu_shader_keyframe_diamond_vert_glsl[]; +extern char datatoc_gpu_shader_keyframe_diamond_frag_glsl[]; + extern char datatoc_gpu_shader_fire_frag_glsl[]; extern char datatoc_gpu_shader_smoke_vert_glsl[]; extern char datatoc_gpu_shader_smoke_frag_glsl[]; @@ -62,41 +127,25 @@ extern char datatoc_gpu_shader_fx_dof_hq_geo_glsl[]; extern char datatoc_gpu_shader_fx_depth_resolve_glsl[]; extern char datatoc_gpu_shader_fx_lib_glsl[]; -static struct GPUShadersGlobal { - struct { - GPUShader *vsm_store; - GPUShader *sep_gaussian_blur; - GPUShader *smoke; - GPUShader *smoke_fire; - GPUShader *smoke_coba; - /* cache for shader fx. Those can exist in combinations so store them here */ - GPUShader *fx_shaders[MAX_FX_SHADERS * 2]; - } shaders; -} GG = {{NULL}}; - -/* GPUShader */ - -struct GPUShader { - GLuint program; /* handle for full program (links shader stages below) */ +/* cache of built-in shaders (each is created on first use) */ +static GPUShader *builtin_shaders[GPU_NUM_BUILTIN_SHADERS] = { NULL }; - GLuint vertex; /* handle for vertex shader */ - GLuint geometry; /* handle for geometry shader */ - GLuint fragment; /* handle for fragment shader */ +/* cache for shader fx. Those can exist in combinations so store them here */ +static GPUShader *fx_shaders[MAX_FX_SHADERS * 2] = { NULL }; - int totattrib; /* total number of attributes */ - int uniforms; /* required uniforms */ - - void *uniform_interface; /* cached uniform interface for shader. Data depends on shader */ -}; +typedef struct { + const char *vert; + const char *frag; + const char *geom; /* geometry stage runs between vert & frag, but is less common, so it goes last */ +} GPUShaderStages; static void shader_print_errors(const char *task, const char *log, const char **code, int totcode) { - int i; int line = 1; fprintf(stderr, "GPUShader: %s error:\n", task); - for (i = 0; i < totcode; i++) { + for (int i = 0; i < totcode; i++) { const char *c, *pos, *end = code[i] + strlen(code[i]); if (G.debug & G_DEBUG) { @@ -119,9 +168,9 @@ static void shader_print_errors(const char *task, const char *log, const char ** static const char *gpu_shader_version(void) { - if (GLEW_VERSION_3_2) { - if (GLEW_ARB_compatibility) { - return "#version 150 compatibility\n"; + if (GLEW_VERSION_3_3) { + if (GPU_legacy_support()) { + return "#version 330 compatibility\n"; /* highest version that is widely supported * gives us native geometry shaders! * use compatibility profile so we can continue using builtin shader input/output names @@ -132,16 +181,6 @@ static const char *gpu_shader_version(void) /* latest version that is compatible with existing shaders */ } } - else if (GLEW_VERSION_3_1) { - if (GLEW_ARB_compatibility) { - return "#version 140\n"; - /* also need the ARB_compatibility extension, handled below */ - } - else { - return "#version 130\n"; - /* latest version that is compatible with existing shaders */ - } - } else if (GLEW_VERSION_3_0) { return "#version 130\n"; /* GLSL 1.3 has modern syntax/keywords/datatypes so use if available @@ -179,9 +218,8 @@ static void gpu_shader_standard_extensions(char defines[MAX_EXT_DEFINE_LENGTH], strcat(defines, "#extension GL_ARB_draw_instanced: enable\n"); } - if (!GLEW_VERSION_3_0 && GLEW_EXT_gpu_shader4) { - strcat(defines, "#extension GL_EXT_gpu_shader4: enable\n"); - /* TODO: maybe require this? shaders become so much nicer */ + if (!GLEW_VERSION_3_0) { + strcat(defines, "#extension GL_EXT_gpu_shader4: require\n"); } } } @@ -453,20 +491,20 @@ GPUShader *GPU_shader_create_ex(const char *vertexcode, void GPU_shader_bind(GPUShader *shader) { - GPU_ASSERT_NO_GL_ERRORS("Pre Shader Bind"); + BLI_assert(shader && shader->program); + glUseProgram(shader->program); - GPU_ASSERT_NO_GL_ERRORS("Post Shader Bind"); } void GPU_shader_unbind(void) { - GPU_ASSERT_NO_GL_ERRORS("Pre Shader Unbind"); glUseProgram(0); - GPU_ASSERT_NO_GL_ERRORS("Post Shader Unbind"); } void GPU_shader_free(GPUShader *shader) { + BLI_assert(shader); + if (shader->vertex) glDeleteShader(shader->vertex); if (shader->geometry) @@ -484,14 +522,29 @@ void GPU_shader_free(GPUShader *shader) int GPU_shader_get_uniform(GPUShader *shader, const char *name) { + BLI_assert(shader && shader->program); + 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; @@ -502,16 +555,12 @@ void GPU_shader_uniform_vector(GPUShader *UNUSED(shader), int location, int leng if (location == -1 || value == NULL) return; - GPU_ASSERT_NO_GL_ERRORS("Pre Uniform Vector"); - if (length == 1) glUniform1fv(location, arraysize, value); else if (length == 2) glUniform2fv(location, arraysize, value); else if (length == 3) glUniform3fv(location, arraysize, value); else if (length == 4) glUniform4fv(location, arraysize, value); else if (length == 9) glUniformMatrix3fv(location, arraysize, 0, value); else if (length == 16) glUniformMatrix4fv(location, arraysize, 0, value); - - GPU_ASSERT_NO_GL_ERRORS("Post Uniform Vector"); } void GPU_shader_uniform_vector_int(GPUShader *UNUSED(shader), int location, int length, int arraysize, const int *value) @@ -519,14 +568,10 @@ void GPU_shader_uniform_vector_int(GPUShader *UNUSED(shader), int location, int if (location == -1) return; - GPU_ASSERT_NO_GL_ERRORS("Pre Uniform Vector"); - if (length == 1) glUniform1iv(location, arraysize, value); else if (length == 2) glUniform2iv(location, arraysize, value); else if (length == 3) glUniform3iv(location, arraysize, value); else if (length == 4) glUniform4iv(location, arraysize, value); - - GPU_ASSERT_NO_GL_ERRORS("Post Uniform Vector"); } void GPU_shader_uniform_int(GPUShader *UNUSED(shader), int location, int value) @@ -534,7 +579,7 @@ void GPU_shader_uniform_int(GPUShader *UNUSED(shader), int location, int value) if (location == -1) return; - GPU_CHECK_ERRORS_AROUND(glUniform1i(location, value)); + glUniform1i(location, value); } void GPU_shader_geometry_stage_primitive_io(GPUShader *shader, int input, int output, int number) @@ -547,9 +592,19 @@ 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) { - GLenum arbnumber; int number = GPU_texture_bound_number(tex); int bindcode = GPU_texture_opengl_bindcode(tex); int target = GPU_texture_target(tex); @@ -565,78 +620,156 @@ void GPU_shader_uniform_texture(GPUShader *UNUSED(shader), int location, GPUText if (location == -1) return; - GPU_ASSERT_NO_GL_ERRORS("Pre Uniform Texture"); + if (number != 0) + glActiveTexture(GL_TEXTURE0 + number); - arbnumber = (GLenum)((GLuint)GL_TEXTURE0 + number); - - if (number != 0) glActiveTexture(arbnumber); if (bindcode != 0) glBindTexture(target, bindcode); else GPU_invalid_tex_bind(target); + glUniform1i(location, number); - glEnable(target); - if (number != 0) glActiveTexture(GL_TEXTURE0); - GPU_ASSERT_NO_GL_ERRORS("Post Uniform Texture"); + if (number != 0) + glActiveTexture(GL_TEXTURE0); } int GPU_shader_get_attribute(GPUShader *shader, const char *name) { - int index; - - GPU_CHECK_ERRORS_AROUND(index = glGetAttribLocation(shader->program, name)); + BLI_assert(shader && shader->program); - return index; + return glGetAttribLocation(shader->program, name); } GPUShader *GPU_shader_get_builtin_shader(GPUBuiltinShader shader) { - GPUShader *retval = NULL; - - switch (shader) { - case GPU_SHADER_VSM_STORE: - if (!GG.shaders.vsm_store) - GG.shaders.vsm_store = GPU_shader_create( - datatoc_gpu_shader_vsm_store_vert_glsl, datatoc_gpu_shader_vsm_store_frag_glsl, - NULL, NULL, NULL, 0, 0, 0); - retval = GG.shaders.vsm_store; - break; - case GPU_SHADER_SEP_GAUSSIAN_BLUR: - if (!GG.shaders.sep_gaussian_blur) - GG.shaders.sep_gaussian_blur = GPU_shader_create( - datatoc_gpu_shader_sep_gaussian_blur_vert_glsl, - datatoc_gpu_shader_sep_gaussian_blur_frag_glsl, - NULL, NULL, NULL, 0, 0, 0); - retval = GG.shaders.sep_gaussian_blur; - break; - case GPU_SHADER_SMOKE: - if (!GG.shaders.smoke) - GG.shaders.smoke = GPU_shader_create( - datatoc_gpu_shader_smoke_vert_glsl, datatoc_gpu_shader_smoke_frag_glsl, - NULL, NULL, NULL, 0, 0, 0); - retval = GG.shaders.smoke; - break; - case GPU_SHADER_SMOKE_FIRE: - if (!GG.shaders.smoke_fire) - GG.shaders.smoke_fire = GPU_shader_create( - datatoc_gpu_shader_smoke_vert_glsl, datatoc_gpu_shader_fire_frag_glsl, - NULL, NULL, NULL, 0, 0, 0); - retval = GG.shaders.smoke_fire; - break; - case GPU_SHADER_SMOKE_COBA: - if (!GG.shaders.smoke_coba) - GG.shaders.smoke_coba = GPU_shader_create( - datatoc_gpu_shader_smoke_vert_glsl, datatoc_gpu_shader_smoke_frag_glsl, - NULL, NULL, "#define USE_COBA;\n", 0, 0, 0); - retval = GG.shaders.smoke_coba; - break; - } + BLI_assert(shader != GPU_NUM_BUILTIN_SHADERS); /* don't be a troll */ + + static const GPUShaderStages builtin_shader_stages[GPU_NUM_BUILTIN_SHADERS] = { + [GPU_SHADER_VSM_STORE] = { datatoc_gpu_shader_vsm_store_vert_glsl, datatoc_gpu_shader_vsm_store_frag_glsl }, + [GPU_SHADER_SEP_GAUSSIAN_BLUR] = { datatoc_gpu_shader_sep_gaussian_blur_vert_glsl, + datatoc_gpu_shader_sep_gaussian_blur_frag_glsl }, + [GPU_SHADER_SMOKE] = { datatoc_gpu_shader_smoke_vert_glsl, datatoc_gpu_shader_smoke_frag_glsl }, + [GPU_SHADER_SMOKE_FIRE] = { datatoc_gpu_shader_smoke_vert_glsl, datatoc_gpu_shader_smoke_frag_glsl }, + [GPU_SHADER_SMOKE_COBA] = { datatoc_gpu_shader_smoke_vert_glsl, datatoc_gpu_shader_smoke_frag_glsl }, + + [GPU_SHADER_TEXT] = { datatoc_gpu_shader_text_vert_glsl, datatoc_gpu_shader_text_frag_glsl }, + [GPU_SHADER_KEYFRAME_DIAMOND] = { datatoc_gpu_shader_keyframe_diamond_vert_glsl, + datatoc_gpu_shader_keyframe_diamond_frag_glsl }, + [GPU_SHADER_EDGES_FRONT_BACK_PERSP] = { datatoc_gpu_shader_edges_front_back_persp_vert_glsl, + /* this version is */ datatoc_gpu_shader_flat_color_frag_glsl, + /* magical but slooow */ datatoc_gpu_shader_edges_front_back_persp_geom_glsl }, + [GPU_SHADER_EDGES_FRONT_BACK_ORTHO] = { datatoc_gpu_shader_edges_front_back_ortho_vert_glsl, + datatoc_gpu_shader_flat_color_frag_glsl }, + [GPU_SHADER_EDGES_OVERLAY_SIMPLE] = { datatoc_gpu_shader_3D_vert_glsl, datatoc_gpu_shader_edges_overlay_frag_glsl, + datatoc_gpu_shader_edges_overlay_simple_geom_glsl }, + [GPU_SHADER_EDGES_OVERLAY] = { datatoc_gpu_shader_edges_overlay_vert_glsl, + datatoc_gpu_shader_edges_overlay_frag_glsl, + datatoc_gpu_shader_edges_overlay_geom_glsl }, + [GPU_SHADER_SIMPLE_LIGHTING] = { datatoc_gpu_shader_3D_vert_glsl, datatoc_gpu_shader_simple_lighting_frag_glsl }, + + [GPU_SHADER_2D_IMAGE_MASK_UNIFORM_COLOR] = { datatoc_gpu_shader_3D_image_vert_glsl, + datatoc_gpu_shader_image_mask_uniform_color_frag_glsl }, + [GPU_SHADER_3D_IMAGE_MODULATE_ALPHA] = { datatoc_gpu_shader_3D_image_vert_glsl, + datatoc_gpu_shader_image_modulate_alpha_frag_glsl }, + [GPU_SHADER_3D_IMAGE_RECT_MODULATE_ALPHA] = { datatoc_gpu_shader_3D_image_vert_glsl, + datatoc_gpu_shader_image_rect_modulate_alpha_frag_glsl }, + [GPU_SHADER_3D_IMAGE_DEPTH] = { datatoc_gpu_shader_3D_image_vert_glsl, + datatoc_gpu_shader_image_depth_linear_frag_glsl }, + + [GPU_SHADER_2D_IMAGE_INTERLACE] = { datatoc_gpu_shader_2D_image_vert_glsl, + datatoc_gpu_shader_image_interlace_frag_glsl }, + [GPU_SHADER_2D_CHECKER] = { datatoc_gpu_shader_2D_vert_glsl, datatoc_gpu_shader_checker_frag_glsl }, + + [GPU_SHADER_2D_DIAG_STRIPES] = { datatoc_gpu_shader_2D_vert_glsl, datatoc_gpu_shader_diag_stripes_frag_glsl }, + + [GPU_SHADER_2D_UNIFORM_COLOR] = { datatoc_gpu_shader_2D_vert_glsl, datatoc_gpu_shader_uniform_color_frag_glsl }, + [GPU_SHADER_2D_FLAT_COLOR] = { datatoc_gpu_shader_2D_flat_color_vert_glsl, + datatoc_gpu_shader_flat_color_frag_glsl }, + [GPU_SHADER_2D_SMOOTH_COLOR] = { datatoc_gpu_shader_2D_smooth_color_vert_glsl, + datatoc_gpu_shader_2D_smooth_color_frag_glsl }, + [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_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_passthrough_vert_glsl, + datatoc_gpu_shader_uniform_color_frag_glsl, + datatoc_gpu_shader_3D_groundline_geom_glsl }, + + [GPU_SHADER_3D_OBJECTSPACE_SIMPLE_LIGHTING_VARIYING_COLOR] = + { datatoc_gpu_shader_instance_objectspace_variying_color_vert_glsl, + datatoc_gpu_shader_simple_lighting_frag_glsl}, + [GPU_SHADER_3D_OBJECTSPACE_VARIYING_COLOR] = { datatoc_gpu_shader_instance_objectspace_variying_color_vert_glsl, + datatoc_gpu_shader_flat_color_frag_glsl}, + [GPU_SHADER_3D_SCREENSPACE_VARIYING_COLOR] = { datatoc_gpu_shader_instance_screenspace_variying_color_vert_glsl, + datatoc_gpu_shader_flat_color_frag_glsl}, + [GPU_SHADER_3D_INSTANCE_SCREEN_ALIGNED_AXIS] = { datatoc_gpu_shader_instance_screen_aligned_axis_name_vert_glsl, + datatoc_gpu_shader_flat_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] = + { datatoc_gpu_shader_2D_point_varying_size_varying_color_vert_glsl, + datatoc_gpu_shader_point_varying_color_frag_glsl }, + [GPU_SHADER_2D_POINT_UNIFORM_SIZE_UNIFORM_COLOR_SMOOTH] = + { datatoc_gpu_shader_2D_point_uniform_size_smooth_vert_glsl, + datatoc_gpu_shader_point_uniform_color_smooth_frag_glsl }, + [GPU_SHADER_2D_POINT_UNIFORM_SIZE_UNIFORM_COLOR_OUTLINE_SMOOTH] = + { datatoc_gpu_shader_2D_point_uniform_size_outline_smooth_vert_glsl, + datatoc_gpu_shader_point_uniform_color_outline_smooth_frag_glsl }, + [GPU_SHADER_2D_POINT_UNIFORM_SIZE_VARYING_COLOR_OUTLINE_SMOOTH] = + { datatoc_gpu_shader_2D_point_uniform_size_varying_color_outline_smooth_vert_glsl, + datatoc_gpu_shader_point_varying_color_outline_smooth_frag_glsl }, + [GPU_SHADER_3D_POINT_FIXED_SIZE_UNIFORM_COLOR] = { datatoc_gpu_shader_3D_vert_glsl, + datatoc_gpu_shader_point_uniform_color_frag_glsl }, + [GPU_SHADER_3D_POINT_FIXED_SIZE_VARYING_COLOR] = { datatoc_gpu_shader_3D_point_fixed_size_varying_color_vert_glsl, + datatoc_gpu_shader_point_varying_color_frag_glsl }, + [GPU_SHADER_3D_POINT_VARYING_SIZE_UNIFORM_COLOR] = { datatoc_gpu_shader_3D_point_varying_size_vert_glsl, + datatoc_gpu_shader_point_uniform_color_frag_glsl }, + [GPU_SHADER_3D_POINT_VARYING_SIZE_VARYING_COLOR] = + { datatoc_gpu_shader_3D_point_varying_size_varying_color_vert_glsl, + datatoc_gpu_shader_point_varying_color_frag_glsl }, + [GPU_SHADER_3D_POINT_UNIFORM_SIZE_UNIFORM_COLOR_SMOOTH] = + { datatoc_gpu_shader_3D_point_uniform_size_smooth_vert_glsl, + datatoc_gpu_shader_point_uniform_color_smooth_frag_glsl }, + [GPU_SHADER_3D_POINT_UNIFORM_SIZE_UNIFORM_COLOR_OUTLINE_SMOOTH] = + { datatoc_gpu_shader_3D_point_uniform_size_outline_smooth_vert_glsl, + datatoc_gpu_shader_point_uniform_color_outline_smooth_frag_glsl }, + + [GPU_SHADER_INSTANCE_UNIFORM_COLOR] = { datatoc_gpu_shader_instance_vert_glsl, datatoc_gpu_shader_uniform_color_frag_glsl }, + [GPU_SHADER_INSTANCE_VARIYING_COLOR_VARIYING_SIZE] = + { datatoc_gpu_shader_instance_variying_size_variying_color_vert_glsl, + datatoc_gpu_shader_flat_color_frag_glsl }, + }; + + if (builtin_shaders[shader] == NULL) { + /* just a few special cases */ + const char *defines = (shader == GPU_SHADER_SMOKE_COBA) ? "#define USE_COBA;\n" : + (shader == GPU_SHADER_SIMPLE_LIGHTING) ? "#define USE_NORMALS;\n" : + (shader == GPU_SHADER_3D_OBJECTSPACE_SIMPLE_LIGHTING_VARIYING_COLOR) ? "#define USE_INSTANCE_COLOR;\n" : NULL; + + const GPUShaderStages *stages = builtin_shader_stages + shader; + + if (shader == GPU_SHADER_EDGES_FRONT_BACK_PERSP && !GLEW_VERSION_3_2) { + /* TODO: remove after switch to core profile (maybe) */ + static const GPUShaderStages legacy_fancy_edges = + { datatoc_gpu_shader_edges_front_back_persp_legacy_vert_glsl, + datatoc_gpu_shader_flat_color_alpha_test_0_frag_glsl }; + stages = &legacy_fancy_edges; + } - if (retval == NULL) - printf("Unable to create a GPUShader for builtin shader: %u\n", shader); + /* common case */ + builtin_shaders[shader] = GPU_shader_create(stages->vert, stages->frag, stages->geom, + NULL, defines, 0, 0, 0); + } - return retval; + return builtin_shaders[shader]; } #define MAX_DEFINES 100 @@ -656,7 +789,7 @@ GPUShader *GPU_shader_get_builtin_fx_shader(int effect, bool persp) strcat(defines, "#define PERSP_MATRIX\n"); } - if (!GG.shaders.fx_shaders[offset]) { + if (!fx_shaders[offset]) { GPUShader *shader = NULL; switch (effect) { @@ -710,49 +843,27 @@ GPUShader *GPU_shader_get_builtin_fx_shader(int effect, bool persp) break; } - GG.shaders.fx_shaders[offset] = shader; + fx_shaders[offset] = shader; GPU_fx_shader_init_interface(shader, effect); } - return GG.shaders.fx_shaders[offset]; + return fx_shaders[offset]; } void GPU_shader_free_builtin_shaders(void) { - int i; - - if (GG.shaders.vsm_store) { - GPU_shader_free(GG.shaders.vsm_store); - GG.shaders.vsm_store = NULL; - } - - if (GG.shaders.sep_gaussian_blur) { - GPU_shader_free(GG.shaders.sep_gaussian_blur); - GG.shaders.sep_gaussian_blur = NULL; - } - - if (GG.shaders.smoke) { - GPU_shader_free(GG.shaders.smoke); - GG.shaders.smoke = NULL; - } - - if (GG.shaders.smoke_fire) { - GPU_shader_free(GG.shaders.smoke_fire); - GG.shaders.smoke_fire = NULL; - } - - if (GG.shaders.smoke_coba) { - GPU_shader_free(GG.shaders.smoke_coba); - GG.shaders.smoke_coba = NULL; + for (int i = 0; i < GPU_NUM_BUILTIN_SHADERS; ++i) { + if (builtin_shaders[i]) { + GPU_shader_free(builtin_shaders[i]); + builtin_shaders[i] = NULL; + } } - for (i = 0; i < 2 * MAX_FX_SHADERS; ++i) { - if (GG.shaders.fx_shaders[i]) { - GPU_shader_free(GG.shaders.fx_shaders[i]); - GG.shaders.fx_shaders[i] = NULL; + for (int i = 0; i < 2 * MAX_FX_SHADERS; ++i) { + if (fx_shaders[i]) { + GPU_shader_free(fx_shaders[i]); + fx_shaders[i] = NULL; } } } - - diff --git a/source/blender/gpu/intern/gpu_shader_private.h b/source/blender/gpu/intern/gpu_shader_private.h new file mode 100644 index 00000000000..d5193e09aa4 --- /dev/null +++ b/source/blender/gpu/intern/gpu_shader_private.h @@ -0,0 +1,40 @@ +/* + * ***** 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. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file gpu_shader_private.h + * \ingroup gpu + */ + +#pragma once + +#include "GPU_glew.h" + +struct GPUShader { + GLuint program; /* handle for full program (links shader stages below) */ + + GLuint vertex; /* handle for vertex shader */ + GLuint geometry; /* handle for geometry shader */ + GLuint fragment; /* handle for fragment shader */ + + int totattrib; /* total number of attributes */ + int uniforms; /* required uniforms */ + + void *uniform_interface; /* cached uniform interface for shader. Data depends on shader */ +}; diff --git a/source/blender/gpu/intern/gpu_texture.c b/source/blender/gpu/intern/gpu_texture.c index 54f0003c086..3513250993e 100644 --- a/source/blender/gpu/intern/gpu_texture.c +++ b/source/blender/gpu/intern/gpu_texture.c @@ -49,9 +49,8 @@ static struct GPUTextureGlobal { } GG = {NULL, NULL, NULL}; /* GPUTexture */ - struct GPUTexture { - int w, h; /* width/height */ + int w, h, d; /* width/height/depth */ int number; /* number for multitexture binding */ int refcount; /* reference count */ GLenum target; /* GL_TEXTURE_* */ @@ -62,42 +61,162 @@ struct GPUTexture { GPUFrameBuffer *fb; /* GPUFramebuffer this texture is attached to */ int fb_attachment; /* slot the texture is attached to */ - int depth; /* is a depth texture? if 3D how deep? */ + bool depth; /* is a depth texture? */ }; -static unsigned char *GPU_texture_convert_pixels(int length, const float *fpixels) +static GLenum GPU_texture_get_format(int components, GPUTextureFormat data_type, GLenum *format, bool *is_depth) { - unsigned char *pixels, *p; - const float *fp = fpixels; - const int len = 4 * length; + if (data_type == GPU_DEPTH_COMPONENT24 || + data_type == GPU_DEPTH_COMPONENT16 || + data_type == GPU_DEPTH_COMPONENT32F) + { + *is_depth = true; + *format = GL_DEPTH_COMPONENT; + } + else { + *is_depth = false; + + switch (components) { + case 1: *format = GL_RED; break; + case 2: *format = GL_RG; break; + case 3: *format = GL_RGB; break; + case 4: *format = GL_RGBA; break; + default: break; + } + } + + /* You can add any of the available type to this list + * For available types see GPU_texture.h */ + switch (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 */ + /* ** Add Format here **/ + /* Texture only format */ + /* ** Add Format here **/ + /* Special formats texture only */ + /* ** Add Format here **/ + /* Depth Formats */ + case GPU_DEPTH_COMPONENT32F: return GL_DEPTH_COMPONENT32F; + case GPU_DEPTH_COMPONENT24: return GL_DEPTH_COMPONENT24; + case GPU_DEPTH_COMPONENT16: return GL_DEPTH_COMPONENT16; + default: + fprintf(stderr, "Texture format incorrect or unsupported\n"); + return 0; + } +} - p = pixels = MEM_callocN(sizeof(unsigned char) * len, "GPUTexturePixels"); +static float *GPU_texture_3D_rescale(GPUTexture *tex, int w, int h, int d, int channels, const float *fpixels) +{ + const unsigned int xf = w / tex->w, yf = h / tex->h, zf = d / tex->d; + float *nfpixels = MEM_mallocN(channels * sizeof(float) * tex->w * tex->h * tex->d, "GPUTexture Rescaled 3Dtex"); + + if (nfpixels) { + GPU_print_error_debug("You need to scale a 3D texture, feel the pain!"); + + for (unsigned k = 0; k < tex->d; k++) { + for (unsigned j = 0; j < tex->h; j++) { + for (unsigned i = 0; i < tex->w; i++) { + /* obviously doing nearest filtering here, + * it's going to be slow in any case, let's not make it worse */ + float xb = i * xf; + float yb = j * yf; + float zb = k * zf; + unsigned int offset = k * (tex->w * tex->h) + i * tex->h + j; + unsigned int offset_orig = (zb) * (w * h) + (xb) * h + (yb); - for (int a = 0; a < len; a++, p++, fp++) - *p = FTOCHAR((*fp)); + if (channels == 4) { + nfpixels[offset * 4] = fpixels[offset_orig * 4]; + nfpixels[offset * 4 + 1] = fpixels[offset_orig * 4 + 1]; + nfpixels[offset * 4 + 2] = fpixels[offset_orig * 4 + 2]; + nfpixels[offset * 4 + 3] = fpixels[offset_orig * 4 + 3]; + } + else + nfpixels[offset] = fpixels[offset_orig]; + } + } + } + } - return pixels; + return nfpixels; } -static void GPU_glTexSubImageEmpty(GLenum target, GLenum format, int x, int y, int w, int h) +/* This tries to allocate video memory for a given texture + * If alloc fails, lower the resolution until it fits. */ +static bool GPU_texture_try_alloc( + GPUTexture *tex, GLenum proxy, GLenum internalformat, GLenum format, int channels, + bool try_rescale, const float *fpixels, float **rescaled_fpixels) { - void *pixels = MEM_callocN(sizeof(char) * 4 * w * h, "GPUTextureEmptyPixels"); + int r_width; - if (target == GL_TEXTURE_1D) - glTexSubImage1D(target, 0, x, w, format, GL_UNSIGNED_BYTE, pixels); - else - glTexSubImage2D(target, 0, x, y, w, h, format, GL_UNSIGNED_BYTE, pixels); - - MEM_freeN(pixels); + switch (proxy) { + case GL_PROXY_TEXTURE_1D: + glTexImage1D(proxy, 0, internalformat, tex->w, 0, format, GL_FLOAT, NULL); + break; + case GL_PROXY_TEXTURE_2D: + glTexImage2D(proxy, 0, internalformat, tex->w, tex->h, 0, format, GL_FLOAT, NULL); + break; + case GL_PROXY_TEXTURE_3D: + glTexImage3D(proxy, 0, internalformat, tex->w, tex->h, tex->d, 0, format, GL_FLOAT, NULL); + break; + } + + glGetTexLevelParameteriv(proxy, 0, GL_TEXTURE_WIDTH, &r_width); + + if (r_width == 0 && try_rescale) { + const int w = tex->w, h = tex->h, d = tex->d; + + /* Find largest texture possible */ + while (r_width == 0) { + tex->w /= 2; + tex->h /= 2; + tex->d /= 2; + + /* really unlikely to happen but keep this just in case */ + if (tex->w == 0) break; + if (tex->h == 0 && proxy != GL_PROXY_TEXTURE_1D) break; + if (tex->d == 0 && proxy == GL_PROXY_TEXTURE_3D) break; + + if (proxy == GL_PROXY_TEXTURE_1D) + glTexImage1D(proxy, 0, internalformat, tex->w, 0, format, GL_FLOAT, NULL); + else if (proxy == GL_PROXY_TEXTURE_2D) + glTexImage2D(proxy, 0, internalformat, tex->w, tex->h, 0, format, GL_FLOAT, NULL); + else if (proxy == GL_PROXY_TEXTURE_3D) + glTexImage3D(proxy, 0, internalformat, tex->w, tex->h, tex->d, 0, format, GL_FLOAT, NULL); + + glGetTexLevelParameteriv(GL_PROXY_TEXTURE_3D, 0, GL_TEXTURE_WIDTH, &r_width); + } + + /* Rescale */ + if (r_width > 0) { + switch (proxy) { + case GL_PROXY_TEXTURE_1D: + case GL_PROXY_TEXTURE_2D: + /* Do nothing for now */ + return false; + case GL_PROXY_TEXTURE_3D: + *rescaled_fpixels = GPU_texture_3D_rescale(tex, w, h, d, channels, fpixels); + return (bool)*rescaled_fpixels; + } + } + } + + return (r_width > 0); } static GPUTexture *GPU_texture_create_nD( - int w, int h, int n, const float *fpixels, int depth, - GPUHDRType hdr_type, int components, int samples, - char err_out[256]) + int w, int h, int d, int n, const float *fpixels, + GPUTextureFormat data_type, int components, int samples, + const bool can_rescale, char err_out[256]) { - GLenum type, format, internalformat; - void *pixels = NULL; + GLenum format, internalformat, proxy; + float *rescaled_fpixels = NULL; + const float *pix; + bool valid; if (samples) { CLAMP_MAX(samples, GPU_max_color_texture_samples()); @@ -106,121 +225,99 @@ static GPUTexture *GPU_texture_create_nD( GPUTexture *tex = MEM_callocN(sizeof(GPUTexture), "GPUTexture"); tex->w = w; tex->h = h; + tex->d = d; tex->number = -1; tex->refcount = 1; - tex->target = (n == 1) ? GL_TEXTURE_1D : (samples ? GL_TEXTURE_2D_MULTISAMPLE : GL_TEXTURE_2D); - tex->target_base = (n == 1) ? GL_TEXTURE_1D : GL_TEXTURE_2D; - tex->depth = depth; + + if (n == 1) { + if (h == 0) + tex->target_base = tex->target = GL_TEXTURE_1D; + else + tex->target_base = tex->target = GL_TEXTURE_1D_ARRAY; + } + else if (n == 2) { + if (d == 0) + tex->target_base = tex->target = GL_TEXTURE_2D; + else + tex->target_base = tex->target = GL_TEXTURE_2D_ARRAY; + } + else if (n == 3) { + tex->target_base = tex->target = GL_TEXTURE_3D; + } + tex->fb_attachment = -1; + if (samples && n == 2 && d == 0) + tex->target = GL_TEXTURE_2D_MULTISAMPLE; + + internalformat = GPU_texture_get_format(components, data_type, &format, &tex->depth); + + /* Generate Texture object */ glGenTextures(1, &tex->bindcode); if (!tex->bindcode) { - if (err_out) { - BLI_snprintf(err_out, 256, "GPUTexture: texture create failed: %d", - (int)glGetError()); - } - else { - fprintf(stderr, "GPUTexture: texture create failed: %d\n", - (int)glGetError()); - } + if (err_out) + BLI_snprintf(err_out, 256, "GPUTexture: texture create failed"); + else + fprintf(stderr, "GPUTexture: texture create failed"); GPU_texture_free(tex); return NULL; } - if (!GPU_full_non_power_of_two_support()) { - tex->w = power_of_2_max_i(tex->w); - tex->h = power_of_2_max_i(tex->h); - } - tex->number = 0; glBindTexture(tex->target, tex->bindcode); - if (depth) { - type = GL_UNSIGNED_BYTE; - format = GL_DEPTH_COMPONENT; - internalformat = GL_DEPTH_COMPONENT; + /* Check if texture fit in VRAM */ + if (d > 0) { + proxy = GL_PROXY_TEXTURE_3D; + } + else if (h > 0) { + proxy = GL_PROXY_TEXTURE_2D; } else { - type = GL_FLOAT; - - if (components == 4) { - format = GL_RGBA; - switch (hdr_type) { - case GPU_HDR_NONE: - internalformat = GL_RGBA8; - break; - /* the following formats rely on ARB_texture_float or OpenGL 3.0 */ - case GPU_HDR_HALF_FLOAT: - internalformat = GL_RGBA16F_ARB; - break; - case GPU_HDR_FULL_FLOAT: - internalformat = GL_RGBA32F_ARB; - break; - default: - break; - } - } - else if (components == 2) { - /* these formats rely on ARB_texture_rg or OpenGL 3.0 */ - format = GL_RG; - switch (hdr_type) { - case GPU_HDR_NONE: - internalformat = GL_RG8; - break; - case GPU_HDR_HALF_FLOAT: - internalformat = GL_RG16F; - break; - case GPU_HDR_FULL_FLOAT: - internalformat = GL_RG32F; - break; - default: - break; - } - } - - if (fpixels && hdr_type == GPU_HDR_NONE) { - type = GL_UNSIGNED_BYTE; - pixels = GPU_texture_convert_pixels(w * h, fpixels); - } + proxy = GL_PROXY_TEXTURE_1D; } - if (tex->target == GL_TEXTURE_1D) { - glTexImage1D(tex->target, 0, internalformat, tex->w, 0, format, type, NULL); + valid = GPU_texture_try_alloc(tex, proxy, internalformat, format, components, can_rescale, fpixels, + &rescaled_fpixels); - if (fpixels) { - glTexSubImage1D(tex->target, 0, 0, w, format, type, - pixels ? pixels : fpixels); + if (!valid) { + if (err_out) + BLI_snprintf(err_out, 256, "GPUTexture: texture alloc failed"); + else + fprintf(stderr, "GPUTexture: texture alloc failed. Not enough Video Memory."); + GPU_texture_free(tex); + return NULL; + } - if (tex->w > w) { - GPU_glTexSubImageEmpty(tex->target, format, w, 0, tex->w - w, 1); - } - } + /* Upload Texture */ + pix = (rescaled_fpixels) ? rescaled_fpixels : fpixels; + + if (tex->target == GL_TEXTURE_1D) { + glTexImage1D(tex->target, 0, internalformat, tex->w, 0, format, GL_FLOAT, pix); } - else { + else if (tex->target == GL_TEXTURE_1D_ARRAY || + tex->target == GL_TEXTURE_2D || + tex->target == GL_TEXTURE_2D_MULTISAMPLE) + { if (samples) { glTexImage2DMultisample(tex->target, samples, internalformat, tex->w, tex->h, true); + if (pix) + glTexSubImage2D(tex->target, 0, 0, 0, tex->w, tex->h, format, GL_FLOAT, pix); } else { - glTexImage2D(tex->target, 0, internalformat, tex->w, tex->h, 0, - format, type, NULL); - } - - if (fpixels) { - glTexSubImage2D(tex->target, 0, 0, 0, w, h, - format, type, pixels ? pixels : fpixels); - - if (tex->w > w) - GPU_glTexSubImageEmpty(tex->target, format, w, 0, tex->w - w, tex->h); - if (tex->h > h) - GPU_glTexSubImageEmpty(tex->target, format, 0, h, w, tex->h - h); + glTexImage2D(tex->target, 0, internalformat, tex->w, tex->h, 0, format, GL_FLOAT, pix); } } + else { + glTexImage3D(tex->target, 0, internalformat, tex->w, tex->h, tex->d, 0, format, GL_FLOAT, pix); + } - if (pixels) - MEM_freeN(pixels); + if (rescaled_fpixels) + MEM_freeN(rescaled_fpixels); - if (depth) { + /* Texture Parameters */ + if (tex->depth) { glTexParameteri(tex->target_base, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(tex->target_base, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(tex->target_base, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_R_TO_TEXTURE); @@ -232,137 +329,14 @@ static GPUTexture *GPU_texture_create_nD( glTexParameteri(tex->target_base, GL_TEXTURE_MAG_FILTER, GL_LINEAR); } - if (tex->target_base != GL_TEXTURE_1D) { - glTexParameteri(tex->target_base, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(tex->target_base, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + if (n > 1) { glTexParameteri(tex->target_base, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); } - else - glTexParameteri(tex->target_base, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - - return tex; -} - - -GPUTexture *GPU_texture_create_3D(int w, int h, int depth, int channels, const float *fpixels) -{ - GLenum type, format, internalformat; - void *pixels = NULL; - - GPUTexture *tex = MEM_callocN(sizeof(GPUTexture), "GPUTexture"); - tex->w = w; - tex->h = h; - tex->depth = depth; - tex->number = -1; - tex->refcount = 1; - tex->target = GL_TEXTURE_3D; - tex->target_base = GL_TEXTURE_3D; - - glGenTextures(1, &tex->bindcode); - - if (!tex->bindcode) { - fprintf(stderr, "GPUTexture: texture create failed: %d\n", - (int)glGetError()); - GPU_texture_free(tex); - return NULL; - } - - tex->number = 0; - glBindTexture(tex->target, tex->bindcode); - - GPU_ASSERT_NO_GL_ERRORS("3D glBindTexture"); - - type = GL_FLOAT; - if (channels == 4) { - format = GL_RGBA; - internalformat = GL_RGBA8; - } - else { - format = GL_RED; - internalformat = GL_INTENSITY8; + if (n > 2) { + glTexParameteri(tex->target_base, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); } - /* 3D textures are quite heavy, test if it's possible to create them first */ - glTexImage3D(GL_PROXY_TEXTURE_3D, 0, internalformat, tex->w, tex->h, tex->depth, 0, format, type, NULL); - - bool rescale = false; - int r_width; - - glGetTexLevelParameteriv(GL_PROXY_TEXTURE_3D, 0, GL_TEXTURE_WIDTH, &r_width); - - while (r_width == 0) { - rescale = true; - tex->w /= 2; - tex->h /= 2; - tex->depth /= 2; - glTexImage3D(GL_PROXY_TEXTURE_3D, 0, internalformat, tex->w, tex->h, tex->depth, 0, format, type, NULL); - glGetTexLevelParameteriv(GL_PROXY_TEXTURE_3D, 0, GL_TEXTURE_WIDTH, &r_width); - } - - /* really unlikely to happen but keep this just in case */ - tex->w = max_ii(tex->w, 1); - tex->h = max_ii(tex->h, 1); - tex->depth = max_ii(tex->depth, 1); - -#if 0 - if (fpixels) - pixels = GPU_texture_convert_pixels(w*h*depth, fpixels); -#endif - - GPU_ASSERT_NO_GL_ERRORS("3D glTexImage3D"); - - /* hardcore stuff, 3D texture rescaling - warning, this is gonna hurt your performance a lot, but we need it - * for gooseberry */ - if (rescale && fpixels) { - /* FIXME: should these be floating point? */ - const unsigned int xf = w / tex->w, yf = h / tex->h, zf = depth / tex->depth; - float *tex3d = MEM_mallocN(channels * sizeof(float) * tex->w * tex->h * tex->depth, "tex3d"); - - GPU_print_error_debug("You need to scale a 3D texture, feel the pain!"); - - for (unsigned k = 0; k < tex->depth; k++) { - for (unsigned j = 0; j < tex->h; j++) { - for (unsigned i = 0; i < tex->w; i++) { - /* obviously doing nearest filtering here, - * it's going to be slow in any case, let's not make it worse */ - float xb = i * xf; - float yb = j * yf; - float zb = k * zf; - unsigned int offset = k * (tex->w * tex->h) + i * tex->h + j; - unsigned int offset_orig = (zb) * (w * h) + (xb) * h + (yb); - - if (channels == 4) { - tex3d[offset * 4] = fpixels[offset_orig * 4]; - tex3d[offset * 4 + 1] = fpixels[offset_orig * 4 + 1]; - tex3d[offset * 4 + 2] = fpixels[offset_orig * 4 + 2]; - tex3d[offset * 4 + 3] = fpixels[offset_orig * 4 + 3]; - } - else - tex3d[offset] = fpixels[offset_orig]; - } - } - } - - glTexImage3D(tex->target, 0, internalformat, tex->w, tex->h, tex->depth, 0, format, type, tex3d); - - MEM_freeN(tex3d); - } - else { - if (fpixels) { - glTexImage3D(tex->target, 0, internalformat, tex->w, tex->h, tex->depth, 0, format, type, fpixels); - GPU_ASSERT_NO_GL_ERRORS("3D glTexSubImage3D"); - } - } - - - glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); - - if (pixels) - MEM_freeN(pixels); - GPU_texture_unbind(tex); return tex; @@ -400,7 +374,7 @@ GPUTexture *GPU_texture_from_blender(Image *ima, ImageUser *iuser, int textarget ima->gputexture[gputt] = tex; if (!glIsTexture(tex->bindcode)) { - GPU_ASSERT_NO_GL_ERRORS("Blender Texture Not Loaded"); + GPU_print_error_debug("Blender Texture Not Loaded"); } else { GLint w, h, border; @@ -454,7 +428,7 @@ GPUTexture *GPU_texture_from_preview(PreviewImage *prv, int mipmap) prv->gputexture[0] = tex; if (!glIsTexture(tex->bindcode)) { - GPU_ASSERT_NO_GL_ERRORS("Blender Texture Not Loaded"); + GPU_print_error_debug("Blender Texture Not Loaded"); } else { GLint w, h; @@ -473,114 +447,64 @@ GPUTexture *GPU_texture_from_preview(PreviewImage *prv, int mipmap) } -GPUTexture *GPU_texture_create_1D(int w, const float *fpixels, char err_out[256]) +GPUTexture *GPU_texture_create_1D(int w, const float *pixels, char err_out[256]) { - GPUTexture *tex = GPU_texture_create_nD(w, 1, 1, fpixels, 0, GPU_HDR_NONE, 4, 0, err_out); - - if (tex) - GPU_texture_unbind(tex); - - return tex; + return GPU_texture_create_nD(w, 0, 0, 1, pixels, GPU_RGBA8, 4, 0, false, err_out); } -GPUTexture *GPU_texture_create_2D(int w, int h, const float *fpixels, GPUHDRType hdr, char err_out[256]) +GPUTexture *GPU_texture_create_1D_custom( + int w, int channels, GPUTextureFormat data_type, const float *pixels, char err_out[256]) { - GPUTexture *tex = GPU_texture_create_nD(w, h, 2, fpixels, 0, hdr, 4, 0, err_out); - - if (tex) - GPU_texture_unbind(tex); - - return tex; + return GPU_texture_create_nD(w, 0, 0, 1, pixels, data_type, channels, 0, false, err_out); } -GPUTexture *GPU_texture_create_2D_multisample( - int w, int h, const float *fpixels, GPUHDRType hdr, int samples, char err_out[256]) -{ - GPUTexture *tex = GPU_texture_create_nD(w, h, 2, fpixels, 0, hdr, 4, samples, err_out); - - if (tex) - GPU_texture_unbind(tex); - return tex; +GPUTexture *GPU_texture_create_2D(int w, int h, const float *pixels, char err_out[256]) +{ + return GPU_texture_create_nD(w, h, 0, 2, pixels, GPU_RGBA8, 4, 0, false, err_out); } -GPUTexture *GPU_texture_create_depth(int w, int h, char err_out[256]) +GPUTexture *GPU_texture_create_2D_custom( + int w, int h, int channels, GPUTextureFormat data_type, const float *pixels, char err_out[256]) { - GPUTexture *tex = GPU_texture_create_nD(w, h, 2, NULL, 1, GPU_HDR_NONE, 1, 0, err_out); - - if (tex) - GPU_texture_unbind(tex); - - return tex; + return GPU_texture_create_nD(w, h, 0, 2, pixels, data_type, channels, 0, false, err_out); } -GPUTexture *GPU_texture_create_depth_multisample(int w, int h, int samples, char err_out[256]) -{ - GPUTexture *tex = GPU_texture_create_nD(w, h, 2, NULL, 1, GPU_HDR_NONE, 1, samples, err_out); - - if (tex) - GPU_texture_unbind(tex); - return tex; +GPUTexture *GPU_texture_create_2D_multisample(int w, int h, const float *pixels, int samples, char err_out[256]) +{ + return GPU_texture_create_nD(w, h, 0, 2, pixels, GPU_RGBA8, 4, samples, false, err_out); } -/** - * A shadow map for VSM needs two components (depth and depth^2) - */ -GPUTexture *GPU_texture_create_vsm_shadow_map(int size, char err_out[256]) +GPUTexture *GPU_texture_create_2D_array(int w, int h, int d, const float *pixels, char err_out[256]) { - GPUTexture *tex = GPU_texture_create_nD(size, size, 2, NULL, 0, GPU_HDR_FULL_FLOAT, 2, 0, err_out); - - if (tex) { - /* Now we tweak some of the settings */ - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - - GPU_texture_unbind(tex); - } - - return tex; + return GPU_texture_create_nD(w, h, d, 2, pixels, GPU_RGBA8, 4, 0, false, err_out); } -GPUTexture *GPU_texture_create_2D_procedural(int w, int h, const float *pixels, bool repeat, char err_out[256]) +GPUTexture *GPU_texture_create_3D(int w, int h, int d, const float *pixels, char err_out[256]) { - GPUTexture *tex = GPU_texture_create_nD(w, h, 2, pixels, 0, GPU_HDR_HALF_FLOAT, 2, 0, err_out); - - if (tex) { - /* Now we tweak some of the settings */ - if (repeat) { - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); - } - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - - GPU_texture_unbind(tex); - } - - return tex; + return GPU_texture_create_nD(w, h, d, 3, pixels, GPU_RGBA8, 4, 0, true, err_out); } -GPUTexture *GPU_texture_create_1D_procedural(int w, const float *pixels, char err_out[256]) +GPUTexture *GPU_texture_create_3D_custom(int w, int h, int d, int channels, GPUTextureFormat data_type, const float *pixels, char err_out[256]) { - GPUTexture *tex = GPU_texture_create_nD(w, 0, 1, pixels, 0, GPU_HDR_HALF_FLOAT, 2, 0, err_out); - - if (tex) { - /* Now we tweak some of the settings */ - glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_S, GL_REPEAT); - glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + return GPU_texture_create_nD(w, h, d, 3, pixels, data_type, channels, 0, true, err_out); +} - GPU_texture_unbind(tex); - } +GPUTexture *GPU_texture_create_depth(int w, int h, char err_out[256]) +{ + return GPU_texture_create_nD(w, h, 0, 2, NULL, GPU_DEPTH_COMPONENT24, 1, 0, false, err_out); +} - return tex; +GPUTexture *GPU_texture_create_depth_multisample(int w, int h, int samples, char err_out[256]) +{ + return GPU_texture_create_nD(w, h, 0, 2, NULL, GPU_DEPTH_COMPONENT24, 1, samples, false, err_out); } void GPU_invalid_tex_init(void) { const float color[4] = {1.0f, 0.0f, 1.0f, 1.0f}; GG.invalid_tex_1D = GPU_texture_create_1D(1, color, NULL); - GG.invalid_tex_2D = GPU_texture_create_2D(1, 1, color, GPU_HDR_NONE, NULL); - GG.invalid_tex_3D = GPU_texture_create_3D(1, 1, 1, 4, color); + GG.invalid_tex_2D = GPU_texture_create_2D(1, 1, color, NULL); + GG.invalid_tex_3D = GPU_texture_create_3D(1, 1, 1, color, NULL); } void GPU_invalid_tex_bind(int mode) @@ -625,21 +549,26 @@ void GPU_texture_bind(GPUTexture *tex, int number) if (number < 0) return; - GPU_ASSERT_NO_GL_ERRORS("Pre Texture Bind"); + if (number != 0) + glActiveTexture(GL_TEXTURE0 + number); - GLenum arbnumber = (GLenum)((GLuint)GL_TEXTURE0 + number); - if (number != 0) glActiveTexture(arbnumber); - if (tex->bindcode != 0) { + if (tex->bindcode != 0) glBindTexture(tex->target_base, tex->bindcode); - } else GPU_invalid_tex_bind(tex->target_base); - glEnable(tex->target_base); - if (number != 0) glActiveTexture(GL_TEXTURE0); - tex->number = number; + /* TODO: remove this lines once we're using GLSL everywhere */ + GLenum target = tex->target_base; + if (tex->target_base == GL_TEXTURE_1D_ARRAY) + target = GL_TEXTURE_2D; + if (tex->target_base == GL_TEXTURE_2D_ARRAY) + target = GL_TEXTURE_3D; + glEnable(target); + + if (number != 0) + glActiveTexture(GL_TEXTURE0); - GPU_ASSERT_NO_GL_ERRORS("Post Texture Bind"); + tex->number = number; } void GPU_texture_unbind(GPUTexture *tex) @@ -651,18 +580,24 @@ void GPU_texture_unbind(GPUTexture *tex) if (tex->number == -1) return; - - GPU_ASSERT_NO_GL_ERRORS("Pre Texture Unbind"); - GLenum arbnumber = (GLenum)((GLuint)GL_TEXTURE0 + tex->number); - if (tex->number != 0) glActiveTexture(arbnumber); + if (tex->number != 0) + glActiveTexture(GL_TEXTURE0 + tex->number); + glBindTexture(tex->target_base, 0); - glDisable(tex->target_base); - if (tex->number != 0) glActiveTexture(GL_TEXTURE0); - tex->number = -1; + /* TODO: remove this lines */ + GLenum target = tex->target_base; + if (tex->target_base == GL_TEXTURE_1D_ARRAY) + target = GL_TEXTURE_2D; + if (tex->target_base == GL_TEXTURE_2D_ARRAY) + target = GL_TEXTURE_3D; + glDisable(target); + + if (tex->number != 0) + glActiveTexture(GL_TEXTURE0); - GPU_ASSERT_NO_GL_ERRORS("Post Texture Unbind"); + tex->number = -1; } int GPU_texture_bound_number(GPUTexture *tex) @@ -670,7 +605,7 @@ int GPU_texture_bound_number(GPUTexture *tex) return tex->number; } -void GPU_texture_filter_mode(GPUTexture *tex, bool compare, bool use_filter) +void GPU_texture_compare_mode(GPUTexture *tex, bool use_compare) { if (tex->number >= GPU_max_textures()) { fprintf(stderr, "Not enough texture slots.\n"); @@ -680,29 +615,60 @@ void GPU_texture_filter_mode(GPUTexture *tex, bool compare, bool use_filter) if (tex->number == -1) return; - GPU_ASSERT_NO_GL_ERRORS("Pre Texture Unbind"); + if (tex->number != 0) + glActiveTexture(GL_TEXTURE0 + tex->number); - GLenum arbnumber = (GLenum)((GLuint)GL_TEXTURE0 + tex->number); - if (tex->number != 0) glActiveTexture(arbnumber); + /* TODO viewport: use GL_COMPARE_REF_TO_TEXTURE after we switch to core profile */ + if (tex->depth) + glTexParameteri(tex->target_base, GL_TEXTURE_COMPARE_MODE, use_compare ? GL_COMPARE_R_TO_TEXTURE : GL_NONE); - if (tex->depth) { - if (compare) - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_R_TO_TEXTURE); - else - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_NONE); - } + if (tex->number != 0) + glActiveTexture(GL_TEXTURE0); +} - if (use_filter) { - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); +void GPU_texture_filter_mode(GPUTexture *tex, bool use_filter) +{ + if (tex->number >= GPU_max_textures()) { + fprintf(stderr, "Not enough texture slots.\n"); + return; } - else { - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + + if (tex->number == -1) + return; + + if (tex->number != 0) + glActiveTexture(GL_TEXTURE0 + tex->number); + + GLenum filter = use_filter ? GL_LINEAR : GL_NEAREST; + glTexParameteri(tex->target_base, GL_TEXTURE_MAG_FILTER, filter); + glTexParameteri(tex->target_base, GL_TEXTURE_MIN_FILTER, filter); + + if (tex->number != 0) + glActiveTexture(GL_TEXTURE0); +} + +void GPU_texture_wrap_mode(GPUTexture *tex, bool use_repeat) +{ + if (tex->number >= GPU_max_textures()) { + fprintf(stderr, "Not enough texture slots.\n"); + return; } - if (tex->number != 0) glActiveTexture(GL_TEXTURE0); - GPU_ASSERT_NO_GL_ERRORS("Post Texture Unbind"); + if (tex->number == -1) + return; + + if (tex->number != 0) + glActiveTexture(GL_TEXTURE0 + tex->number); + + GLenum repeat = use_repeat ? GL_REPEAT : GL_CLAMP_TO_EDGE; + glTexParameteri(tex->target_base, GL_TEXTURE_WRAP_S, repeat); + if (tex->target_base != GL_TEXTURE_1D) + glTexParameteri(tex->target_base, GL_TEXTURE_WRAP_T, repeat); + if (tex->target_base == GL_TEXTURE_3D) + glTexParameteri(tex->target_base, GL_TEXTURE_WRAP_R, repeat); + + if (tex->number != 0) + glActiveTexture(GL_TEXTURE0); } void GPU_texture_free(GPUTexture *tex) 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 new file mode 100644 index 00000000000..c8e60c089d3 --- /dev/null +++ b/source/blender/gpu/intern/gpu_viewport.c @@ -0,0 +1,397 @@ +/* + * ***** 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) 2006 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/gpu/intern/gpu_viewport.c + * \ingroup gpu + * + * System that manages viewport drawing. + */ + +#include <string.h> + +#include "BLI_rect.h" +#include "BLI_string.h" + +#include "DNA_vec_types.h" + +#include "BKE_global.h" + +#include "GPU_framebuffer.h" +#include "GPU_glew.h" +#include "GPU_immediate.h" +#include "GPU_texture.h" +#include "GPU_viewport.h" + +#include "DRW_engine.h" + +#include "MEM_guardedalloc.h" + +struct GPUViewport { + float pad[4]; + + /* debug */ + GPUTexture *debug_depth; + int size[2]; + + /* Viewport Buffer Storage */ + FramebufferList *fbl; + TextureList *txl; + PassList *psl; + StorageList *stl; + + char engine_name[32]; + + /* Mode storage */ + FramebufferList *fbl_mode; + TextureList *txl_mode; + PassList *psl_mode; + StorageList *stl_mode; + int mode; +}; + +static void GPU_viewport_buffers_free(FramebufferList *fbl, TextureList *txl); +static void GPU_viewport_storage_free(StorageList *stl); +static void GPU_viewport_passes_free(PassList *psl); + +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->stl = MEM_callocN(sizeof(StorageList), "StorageList"); + viewport->fbl_mode = MEM_callocN(sizeof(FramebufferList), "FramebufferList"); + viewport->txl_mode = MEM_callocN(sizeof(TextureList), "TextureList"); + viewport->psl_mode = MEM_callocN(sizeof(PassList), "PassList"); + viewport->stl_mode = MEM_callocN(sizeof(StorageList), "StorageList"); + viewport->size[0] = viewport->size[1] = -1; + + return viewport; +} + +void GPU_viewport_get_engine_data(GPUViewport *viewport, FramebufferList **fbs, TextureList **txs, PassList **pss, StorageList **str) +{ + *fbs = viewport->fbl; + *txs = viewport->txl; + *pss = viewport->psl; + *str = viewport->stl; +} + +void GPU_viewport_get_mode_data(GPUViewport *viewport, FramebufferList **fbs, TextureList **txs, PassList **pss, StorageList **str) +{ + *fbs = viewport->fbl_mode; + *txs = viewport->txl_mode; + *pss = viewport->psl_mode; + *str = viewport->stl_mode; +} + +void GPU_viewport_bind(GPUViewport *viewport, const rcti *rect, const char *engine, int mode) +{ + DefaultFramebufferList *dfbl = (DefaultFramebufferList *)viewport->fbl; + DefaultTextureList *dtxl = (DefaultTextureList *)viewport->txl; + + /* add one pixel because of scissor test */ + int rect_w = BLI_rcti_size_x(rect) + 1, rect_h = BLI_rcti_size_y(rect) + 1; + + if (G.debug_value != 666 && G.debug_value != 667) { + /* TODO for testing only, we need proper cache invalidation */ + GPU_viewport_passes_free(viewport->psl); + GPU_viewport_passes_free(viewport->psl_mode); + } + + if (!STREQ(engine, viewport->engine_name)) { + GPU_viewport_storage_free(viewport->stl); + GPU_viewport_buffers_free(viewport->fbl, viewport->txl); + + BLI_strncpy(viewport->engine_name, engine, 32); + } + + if (mode != viewport->mode) { + GPU_viewport_buffers_free(viewport->fbl_mode, viewport->txl_mode); + GPU_viewport_passes_free(viewport->psl_mode); + GPU_viewport_storage_free(viewport->stl_mode); + + viewport->mode = mode; + } + + if (dfbl->default_fb) { + if (rect_w != viewport->size[0] || rect_h != viewport->size[1]) { + GPU_viewport_buffers_free(viewport->fbl, viewport->txl); + GPU_viewport_buffers_free(viewport->fbl_mode, viewport->txl_mode); + } + } + + if (!dfbl->default_fb) { + bool ok = true; + viewport->size[0] = rect_w; + viewport->size[1] = rect_h; + + dfbl->default_fb = GPU_framebuffer_create(); + if (!dfbl->default_fb) { + ok = false; + goto cleanup; + } + + /* Color */ + /* No multi samples for now */ + dtxl->color = GPU_texture_create_2D(rect_w, rect_h, NULL, NULL); + if (!dtxl->color) { + ok = false; + goto cleanup; + } + + if (!GPU_framebuffer_texture_attach(dfbl->default_fb, dtxl->color, 0)) { + ok = false; + goto cleanup; + } + + /* Depth */ + dtxl->depth = GPU_texture_create_depth(rect_w, rect_h, NULL); + if (!dtxl->depth) { + ok = false; + goto cleanup; + } + else if (!GPU_framebuffer_texture_attach(dfbl->default_fb, dtxl->depth, 0)) { + ok = false; + goto cleanup; + } + else if (!GPU_framebuffer_check_valid(dfbl->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(dfbl->default_fb, 0); +} + +static void draw_ofs_to_screen(GPUViewport *viewport) +{ + DefaultTextureList *dtxl = (DefaultTextureList *)viewport->txl; + + GPUTexture *color = dtxl->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) +{ + DefaultFramebufferList *dfbl = (DefaultFramebufferList *)viewport->fbl; + + if (dfbl->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(FramebufferList *fbl, TextureList *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_storage_free(StorageList *stl) +{ + for (int i = MAX_STORAGE - 1; i > -1; --i) { + void *storage = stl->storage[i]; + if (storage) { + MEM_freeN(storage); + stl->storage[i] = NULL; + } + } +} + +static void GPU_viewport_passes_free(PassList *psl) +{ + for (int 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); + + GPU_viewport_buffers_free(viewport->fbl, viewport->txl); + GPU_viewport_passes_free(viewport->psl); + GPU_viewport_storage_free(viewport->stl); + + GPU_viewport_buffers_free(viewport->fbl_mode, viewport->txl_mode); + GPU_viewport_passes_free(viewport->psl_mode); + GPU_viewport_storage_free(viewport->stl_mode); + + MEM_freeN(viewport->fbl); + MEM_freeN(viewport->txl); + MEM_freeN(viewport->psl); + MEM_freeN(viewport->stl); + + MEM_freeN(viewport->fbl_mode); + MEM_freeN(viewport->txl_mode); + MEM_freeN(viewport->psl_mode); + MEM_freeN(viewport->stl_mode); +} + +/****************** debug ********************/ + +bool GPU_viewport_debug_depth_create(GPUViewport *viewport, int width, int height, char err_out[256]) +{ + viewport->debug_depth = GPU_texture_create_2D_custom(width, height, 4, GPU_RGBA16F, NULL, err_out); + return (viewport->debug_depth != NULL); +} + +void GPU_viewport_debug_depth_free(GPUViewport *viewport) +{ + if (viewport->debug_depth != NULL) { + MEM_freeN(viewport->debug_depth); + viewport->debug_depth = NULL; + } +} + +void GPU_viewport_debug_depth_store(GPUViewport *viewport, const int x, const int y) +{ + const int w = GPU_texture_width(viewport->debug_depth); + const int h = GPU_texture_height(viewport->debug_depth); + + GPU_texture_bind(viewport->debug_depth, 0); + glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT24, x, y, w, h, 0); + GPU_texture_unbind(viewport->debug_depth); +} + +void GPU_viewport_debug_depth_draw(GPUViewport *viewport, const float znear, const float zfar) +{ + const float w = (float)GPU_texture_width(viewport->debug_depth); + const float h = (float)GPU_texture_height(viewport->debug_depth); + + 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_DEPTH); + + GPU_texture_bind(viewport->debug_depth, 0); + + immUniform1f("znear", znear); + immUniform1f("zfar", zfar); + 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(viewport->debug_depth); + + immUnbindProgram(); +} + +int GPU_viewport_debug_depth_width(const GPUViewport *viewport) +{ + return GPU_texture_width(viewport->debug_depth); +} + +int GPU_viewport_debug_depth_height(const GPUViewport *viewport) +{ + return GPU_texture_height(viewport->debug_depth); +} + +bool GPU_viewport_debug_depth_is_valid(GPUViewport *viewport) +{ + return viewport->debug_depth != NULL; +} diff --git a/source/blender/gpu/shaders/gpu_shader_2D_flat_color_vert.glsl b/source/blender/gpu/shaders/gpu_shader_2D_flat_color_vert.glsl new file mode 100644 index 00000000000..96c833f3b93 --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_2D_flat_color_vert.glsl @@ -0,0 +1,20 @@ + +uniform mat4 ModelViewProjectionMatrix; + +#if __VERSION__ == 120 + attribute vec2 pos; + attribute vec4 color; + + flat varying vec4 finalColor; +#else + in vec2 pos; + in vec4 color; + + flat out vec4 finalColor; +#endif + +void main() +{ + gl_Position = ModelViewProjectionMatrix * vec4(pos, 0.0, 1.0); + finalColor = color; +} diff --git a/source/blender/gpu/shaders/gpu_shader_2D_image_vert.glsl b/source/blender/gpu/shaders/gpu_shader_2D_image_vert.glsl new file mode 100644 index 00000000000..a6c00b080b2 --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_2D_image_vert.glsl @@ -0,0 +1,18 @@ + +uniform mat4 ModelViewProjectionMatrix; + +#if __VERSION__ == 120 + attribute vec2 texCoord; + attribute vec2 pos; + varying vec2 texCoord_interp; +#else + in vec2 texCoord; + in vec2 pos; + out vec2 texCoord_interp; +#endif + +void main() +{ + gl_Position = ModelViewProjectionMatrix * vec4(pos.xy, 0.0f, 1.0f); + texCoord_interp = texCoord; +} diff --git a/source/blender/gpu/shaders/gpu_shader_2D_point_uniform_size_outline_smooth_vert.glsl b/source/blender/gpu/shaders/gpu_shader_2D_point_uniform_size_outline_smooth_vert.glsl new file mode 100644 index 00000000000..a37ae16f837 --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_2D_point_uniform_size_outline_smooth_vert.glsl @@ -0,0 +1,29 @@ + +uniform mat4 ModelViewProjectionMatrix; +uniform float size; +uniform float outlineWidth; + +#if __VERSION__ == 120 + attribute vec2 pos; + varying vec4 radii; +#else + in vec2 pos; + out vec4 radii; +#endif + +void main() { + gl_Position = ModelViewProjectionMatrix * vec4(pos, 0.0, 1.0); + gl_PointSize = size; + + // calculate concentric radii in pixels + float radius = 0.5 * size; + + // start at the outside and progress toward the center + radii[0] = radius; + radii[1] = radius - 1.0; + radii[2] = radius - outlineWidth; + radii[3] = radius - outlineWidth - 1.0; + + // convert to PointCoord units + radii /= size; +} diff --git a/source/blender/gpu/shaders/gpu_shader_2D_point_uniform_size_smooth_vert.glsl b/source/blender/gpu/shaders/gpu_shader_2D_point_uniform_size_smooth_vert.glsl new file mode 100644 index 00000000000..201e5e90ecc --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_2D_point_uniform_size_smooth_vert.glsl @@ -0,0 +1,26 @@ + +uniform mat4 ModelViewProjectionMatrix; +uniform float size; + +#if __VERSION__ == 120 + attribute vec2 pos; + varying vec2 radii; +#else + in vec2 pos; + out vec2 radii; +#endif + +void main() { + gl_Position = ModelViewProjectionMatrix * vec4(pos, 0.0, 1.0); + gl_PointSize = size; + + // calculate concentric radii in pixels + float radius = 0.5 * size; + + // start at the outside and progress toward the center + radii[0] = radius; + radii[1] = radius - 1.0; + + // convert to PointCoord units + radii /= size; +} diff --git a/source/blender/gpu/shaders/gpu_shader_2D_point_uniform_size_varying_color_outline_smooth_vert.glsl b/source/blender/gpu/shaders/gpu_shader_2D_point_uniform_size_varying_color_outline_smooth_vert.glsl new file mode 100644 index 00000000000..d3a142cc7bd --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_2D_point_uniform_size_varying_color_outline_smooth_vert.glsl @@ -0,0 +1,34 @@ + +uniform mat4 ModelViewProjectionMatrix; +uniform float size; +uniform float outlineWidth; + +#if __VERSION__ == 120 + attribute vec2 pos; + attribute vec4 color; + varying vec4 radii; + varying vec4 fillColor; +#else + in vec2 pos; + in vec4 color; + out vec4 radii; + out vec4 fillColor; +#endif + +void main() { + gl_Position = ModelViewProjectionMatrix * vec4(pos, 0.0, 1.0); + gl_PointSize = size; + fillColor = color; + + // calculate concentric radii in pixels + float radius = 0.5 * size; + + // start at the outside and progress toward the center + radii[0] = radius; + radii[1] = radius - 1.0; + radii[2] = radius - outlineWidth; + radii[3] = radius - outlineWidth - 1.0; + + // convert to PointCoord units + radii /= size; +} diff --git a/source/blender/gpu/shaders/gpu_shader_2D_point_varying_size_varying_color_vert.glsl b/source/blender/gpu/shaders/gpu_shader_2D_point_varying_size_varying_color_vert.glsl new file mode 100644 index 00000000000..42ff51e3d03 --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_2D_point_varying_size_varying_color_vert.glsl @@ -0,0 +1,21 @@ + +uniform mat4 ModelViewProjectionMatrix; + +#if __VERSION__ == 120 + attribute vec2 pos; + attribute float size; + attribute vec4 color; + varying vec4 finalColor; +#else + in vec2 pos; + in float size; + in vec4 color; + out vec4 finalColor; +#endif + +void main() +{ + gl_Position = ModelViewProjectionMatrix * vec4(pos, 0.0, 1.0); + gl_PointSize = size; + finalColor = color; +} diff --git a/source/blender/gpu/shaders/gpu_shader_2D_smooth_color_frag.glsl b/source/blender/gpu/shaders/gpu_shader_2D_smooth_color_frag.glsl new file mode 100644 index 00000000000..654439d1feb --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_2D_smooth_color_frag.glsl @@ -0,0 +1,13 @@ + +#if __VERSION__ == 120 + noperspective varying vec4 finalColor; + #define fragColor gl_FragColor +#else + noperspective in vec4 finalColor; + out vec4 fragColor; +#endif + +void main() +{ + fragColor = finalColor; +} diff --git a/source/blender/gpu/shaders/gpu_shader_2D_smooth_color_vert.glsl b/source/blender/gpu/shaders/gpu_shader_2D_smooth_color_vert.glsl new file mode 100644 index 00000000000..9daf2d75016 --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_2D_smooth_color_vert.glsl @@ -0,0 +1,20 @@ + +uniform mat4 ModelViewProjectionMatrix; + +#if __VERSION__ == 120 + attribute vec2 pos; + attribute vec4 color; + + noperspective varying vec4 finalColor; +#else + in vec2 pos; + in vec4 color; + + noperspective out vec4 finalColor; +#endif + +void main() +{ + gl_Position = ModelViewProjectionMatrix * vec4(pos, 0.0, 1.0); + finalColor = color; +} diff --git a/source/blender/gpu/shaders/gpu_shader_2D_vert.glsl b/source/blender/gpu/shaders/gpu_shader_2D_vert.glsl new file mode 100644 index 00000000000..4049171f73d --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_2D_vert.glsl @@ -0,0 +1,13 @@ + +uniform mat4 ModelViewProjectionMatrix; + +#if __VERSION__ == 120 + attribute vec2 pos; +#else + in vec2 pos; +#endif + +void main() +{ + gl_Position = ModelViewProjectionMatrix * vec4(pos, 0.0, 1.0); +} diff --git a/source/blender/gpu/shaders/gpu_shader_3D_flat_color_vert.glsl b/source/blender/gpu/shaders/gpu_shader_3D_flat_color_vert.glsl new file mode 100644 index 00000000000..8c241cff5d4 --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_3D_flat_color_vert.glsl @@ -0,0 +1,20 @@ + +uniform mat4 ModelViewProjectionMatrix; + +#if __VERSION__ == 120 + attribute vec3 pos; + attribute vec4 color; + + flat varying vec4 finalColor; +#else + in vec3 pos; + in vec4 color; + + flat out vec4 finalColor; +#endif + +void main() +{ + gl_Position = ModelViewProjectionMatrix * vec4(pos, 1.0); + finalColor = color; +} 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_groundpoint_vert.glsl b/source/blender/gpu/shaders/gpu_shader_3D_groundpoint_vert.glsl new file mode 100644 index 00000000000..55f410eb25d --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_3D_groundpoint_vert.glsl @@ -0,0 +1,11 @@ + +/* Made 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_image_vert.glsl b/source/blender/gpu/shaders/gpu_shader_3D_image_vert.glsl new file mode 100644 index 00000000000..e9f847f28b3 --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_3D_image_vert.glsl @@ -0,0 +1,18 @@ + +uniform mat4 ModelViewProjectionMatrix; + +#if __VERSION__ == 120 + attribute vec2 texCoord; + attribute vec3 pos; + varying vec2 texCoord_interp; +#else + in vec2 texCoord; + in vec3 pos; + out vec2 texCoord_interp; +#endif + +void main() +{ + gl_Position = ModelViewProjectionMatrix * vec4(pos.xyz, 1.0f); + texCoord_interp = texCoord; +} diff --git a/source/blender/gpu/shaders/gpu_shader_3D_passthrough_vert.glsl b/source/blender/gpu/shaders/gpu_shader_3D_passthrough_vert.glsl new file mode 100644 index 00000000000..60793bf56b6 --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_3D_passthrough_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_point_fixed_size_varying_color_vert.glsl b/source/blender/gpu/shaders/gpu_shader_3D_point_fixed_size_varying_color_vert.glsl new file mode 100644 index 00000000000..84e77e59e90 --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_3D_point_fixed_size_varying_color_vert.glsl @@ -0,0 +1,18 @@ + +uniform mat4 ModelViewProjectionMatrix; + +#if __VERSION__ == 120 + attribute vec3 pos; + attribute vec4 color; + varying vec4 finalColor; +#else + in vec3 pos; + in vec4 color; + out vec4 finalColor; +#endif + +void main() +{ + gl_Position = ModelViewProjectionMatrix * vec4(pos, 1.0); + finalColor = color; +} diff --git a/source/blender/gpu/shaders/gpu_shader_3D_point_uniform_size_outline_smooth_vert.glsl b/source/blender/gpu/shaders/gpu_shader_3D_point_uniform_size_outline_smooth_vert.glsl new file mode 100644 index 00000000000..d05920002ed --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_3D_point_uniform_size_outline_smooth_vert.glsl @@ -0,0 +1,29 @@ + +uniform mat4 ModelViewProjectionMatrix; +uniform float size; +uniform float outlineWidth; + +#if __VERSION__ == 120 + attribute vec3 pos; + varying vec4 radii; +#else + in vec3 pos; + out vec4 radii; +#endif + +void main() { + gl_Position = ModelViewProjectionMatrix * vec4(pos, 1.0); + gl_PointSize = size; + + // calculate concentric radii in pixels + float radius = 0.5 * size; + + // start at the outside and progress toward the center + radii[0] = radius; + radii[1] = radius - 1.0; + radii[2] = radius - outlineWidth; + radii[3] = radius - outlineWidth - 1.0; + + // convert to PointCoord units + radii /= size; +} diff --git a/source/blender/gpu/shaders/gpu_shader_3D_point_uniform_size_smooth_vert.glsl b/source/blender/gpu/shaders/gpu_shader_3D_point_uniform_size_smooth_vert.glsl new file mode 100644 index 00000000000..287f95b48ab --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_3D_point_uniform_size_smooth_vert.glsl @@ -0,0 +1,26 @@ + +uniform mat4 ModelViewProjectionMatrix; +uniform float size; + +#if __VERSION__ == 120 + attribute vec3 pos; + varying vec2 radii; +#else + in vec3 pos; + out vec2 radii; +#endif + +void main() { + gl_Position = ModelViewProjectionMatrix * vec4(pos, 1.0); + gl_PointSize = size; + + // calculate concentric radii in pixels + float radius = 0.5 * size; + + // start at the outside and progress toward the center + radii[0] = radius; + radii[1] = radius - 1.0; + + // convert to PointCoord units + radii /= size; +} diff --git a/source/blender/gpu/shaders/gpu_shader_3D_point_varying_size_varying_color_vert.glsl b/source/blender/gpu/shaders/gpu_shader_3D_point_varying_size_varying_color_vert.glsl new file mode 100644 index 00000000000..7999435f0e4 --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_3D_point_varying_size_varying_color_vert.glsl @@ -0,0 +1,21 @@ + +uniform mat4 ModelViewProjectionMatrix; + +#if __VERSION__ == 120 + attribute vec3 pos; + attribute float size; + attribute vec4 color; + varying vec4 finalColor; +#else + in vec3 pos; + in float size; + in vec4 color; + out vec4 finalColor; +#endif + +void main() +{ + gl_Position = ModelViewProjectionMatrix * vec4(pos, 1.0); + gl_PointSize = size; + finalColor = color; +} diff --git a/source/blender/gpu/shaders/gpu_shader_3D_point_varying_size_vert.glsl b/source/blender/gpu/shaders/gpu_shader_3D_point_varying_size_vert.glsl new file mode 100644 index 00000000000..1fcda765b99 --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_3D_point_varying_size_vert.glsl @@ -0,0 +1,16 @@ + +uniform mat4 ModelViewProjectionMatrix; + +#if __VERSION__ == 120 + attribute vec3 pos; + attribute float size; +#else + in vec3 pos; + in float size; +#endif + +void main() +{ + gl_Position = ModelViewProjectionMatrix * vec4(pos, 1.0); + gl_PointSize = size; +} diff --git a/source/blender/gpu/shaders/gpu_shader_3D_smooth_color_frag.glsl b/source/blender/gpu/shaders/gpu_shader_3D_smooth_color_frag.glsl new file mode 100644 index 00000000000..955a49aa7d2 --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_3D_smooth_color_frag.glsl @@ -0,0 +1,13 @@ + +#if __VERSION__ == 120 + varying vec4 finalColor; + #define fragColor gl_FragColor +#else + in vec4 finalColor; + out vec4 fragColor; +#endif + +void main() +{ + fragColor = finalColor; +} diff --git a/source/blender/gpu/shaders/gpu_shader_3D_smooth_color_vert.glsl b/source/blender/gpu/shaders/gpu_shader_3D_smooth_color_vert.glsl new file mode 100644 index 00000000000..22c2cfa8b93 --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_3D_smooth_color_vert.glsl @@ -0,0 +1,20 @@ + +uniform mat4 ModelViewProjectionMatrix; + +#if __VERSION__ == 120 + attribute vec3 pos; + attribute vec4 color; + + varying vec4 finalColor; +#else + in vec3 pos; + in vec4 color; + + out vec4 finalColor; +#endif + +void main() +{ + gl_Position = ModelViewProjectionMatrix * vec4(pos, 1.0); + finalColor = color; +} diff --git a/source/blender/gpu/shaders/gpu_shader_3D_vert.glsl b/source/blender/gpu/shaders/gpu_shader_3D_vert.glsl new file mode 100644 index 00000000000..58150c004e5 --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_3D_vert.glsl @@ -0,0 +1,27 @@ + +uniform mat4 ModelViewProjectionMatrix; +#ifdef USE_NORMALS +uniform mat3 NormalMatrix; +#endif + +#if __VERSION__ == 120 + attribute vec3 pos; +#ifdef USE_NORMALS + attribute vec3 nor; + varying vec3 normal; +#endif +#else + in vec3 pos; +#ifdef USE_NORMALS + in vec3 nor; + out vec3 normal; +#endif +#endif + +void main() +{ +#ifdef USE_NORMALS + normal = normalize(NormalMatrix * nor); +#endif + gl_Position = ModelViewProjectionMatrix * vec4(pos, 1.0); +} diff --git a/source/blender/gpu/shaders/gpu_shader_basic_frag.glsl b/source/blender/gpu/shaders/gpu_shader_basic_frag.glsl index 01a335af048..a0141f1ab2c 100644 --- a/source/blender/gpu/shaders/gpu_shader_basic_frag.glsl +++ b/source/blender/gpu/shaders/gpu_shader_basic_frag.glsl @@ -20,12 +20,6 @@ #define STIPPLE_HEXAGON 3 #define STIPPLE_DIAG_STRIPES 4 #define STIPPLE_DIAG_STRIPES_SWAP 5 -#define STIPPLE_S3D_INTERLACE_ROW 6 -#define STIPPLE_S3D_INTERLACE_ROW_SWAP 7 -#define STIPPLE_S3D_INTERLACE_COLUMN 8 -#define STIPPLE_S3D_INTERLACE_COLUMN_SWAP 9 -#define STIPPLE_S3D_INTERLACE_CHECKERBOARD 10 -#define STIPPLE_S3D_INTERLACE_CHECKERBOARD_SWAP 11 #if defined(USE_SOLID_LIGHTING) || defined(USE_SCENE_LIGHTING) #if defined(USE_FLAT_NORMAL) @@ -58,7 +52,7 @@ uniform sampler2D_default texture_map; #ifdef USE_STIPPLE uniform int stipple_id; #if defined(DRAW_LINE) -varying in float t; +varying float t; uniform int stipple_pattern; #endif #endif @@ -74,14 +68,9 @@ void main() /* We have to use mod function and integer casting. * This can be optimized further with the bitwise operations * when GLSL 1.3 is supported. */ - if (stipple_id == STIPPLE_HALFTONE || - stipple_id == STIPPLE_S3D_INTERLACE_CHECKERBOARD || - stipple_id == STIPPLE_S3D_INTERLACE_CHECKERBOARD_SWAP) - { + if (stipple_id == STIPPLE_HALFTONE) { int result = int(mod(gl_FragCoord.x + gl_FragCoord.y, 2)); bool dis = result == 0; - if (stipple_id == STIPPLE_S3D_INTERLACE_CHECKERBOARD_SWAP) - dis = !dis; if (dis) discard; } @@ -116,22 +105,6 @@ void main() if (!((16 - modx > mody && mody > 8 - modx) || mody > 24 - modx)) discard; } - else if (stipple_id == STIPPLE_S3D_INTERLACE_ROW || stipple_id == STIPPLE_S3D_INTERLACE_ROW_SWAP) { - int result = int(mod(gl_FragCoord.y, 2)); - bool dis = result == 0; - if (stipple_id == STIPPLE_S3D_INTERLACE_ROW_SWAP) - dis = !dis; - if (dis) - discard; - } - else if (stipple_id == STIPPLE_S3D_INTERLACE_COLUMN || stipple_id == STIPPLE_S3D_INTERLACE_COLUMN_SWAP) { - int result = int(mod(gl_FragCoord.x, 2)); - bool dis = result != 0; - if (stipple_id == STIPPLE_S3D_INTERLACE_COLUMN_SWAP) - dis = !dis; - if (dis) - discard; - } else if (stipple_id == STIPPLE_HEXAGON) { int mody = int(mod(gl_FragCoord.y, 2)); int modx = int(mod(gl_FragCoord.x, 4)); diff --git a/source/blender/gpu/shaders/gpu_shader_basic_geom.glsl b/source/blender/gpu/shaders/gpu_shader_basic_geom.glsl index a88681a5fd3..13f05b340bf 100644 --- a/source/blender/gpu/shaders/gpu_shader_basic_geom.glsl +++ b/source/blender/gpu/shaders/gpu_shader_basic_geom.glsl @@ -14,9 +14,9 @@ layout(line_strip, max_vertices = 10) out; layout(triangle_strip, max_vertices = 6) out; #endif -varying out float t; -varying in vec4 varying_vertex_color_line[]; -varying out vec4 varying_vertex_color; +out float t; +in vec4 varying_vertex_color_line[]; +out vec4 varying_vertex_color; uniform ivec4 viewport; uniform float line_width; diff --git a/source/blender/gpu/shaders/gpu_shader_checker_frag.glsl b/source/blender/gpu/shaders/gpu_shader_checker_frag.glsl new file mode 100644 index 00000000000..3b24af916a0 --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_checker_frag.glsl @@ -0,0 +1,24 @@ + +uniform vec4 color1; +uniform vec4 color2; +uniform int size; + +#if __VERSION__ == 120 + #define fragColor gl_FragColor +#else + out vec4 fragColor; +#endif + +void main() +{ + vec2 phase = mod(gl_FragCoord.xy, (size*2)); + + if ((phase.x > size && phase.y < size) || + (phase.x < size && phase.y > size)) + { + fragColor = color1; + } + else { + fragColor = color2; + } +} diff --git a/source/blender/gpu/shaders/gpu_shader_depth_only_frag.glsl b/source/blender/gpu/shaders/gpu_shader_depth_only_frag.glsl new file mode 100644 index 00000000000..60e71e19004 --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_depth_only_frag.glsl @@ -0,0 +1,6 @@ + +void main() +{ + // no color output, only depth (line below is implicit) + // gl_FragDepth = gl_FragCoord.z; +} diff --git a/source/blender/gpu/shaders/gpu_shader_diag_stripes_frag.glsl b/source/blender/gpu/shaders/gpu_shader_diag_stripes_frag.glsl new file mode 100644 index 00000000000..74cf1c5a3dc --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_diag_stripes_frag.glsl @@ -0,0 +1,24 @@ + +uniform vec4 color1; +uniform vec4 color2; +uniform int size1; +uniform int size2; + +#if __VERSION__ == 120 + #define fragColor gl_FragColor +#else + out vec4 fragColor; +#endif + +void main() +{ + float phase = mod((gl_FragCoord.x + gl_FragCoord.y), (size1 + size2)); + + if (phase < size1) + { + fragColor = color1; + } + else { + fragColor = color2; + } +} diff --git a/source/blender/gpu/shaders/gpu_shader_edges_front_back_ortho_vert.glsl b/source/blender/gpu/shaders/gpu_shader_edges_front_back_ortho_vert.glsl new file mode 100755 index 00000000000..ed281141e16 --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_edges_front_back_ortho_vert.glsl @@ -0,0 +1,64 @@ + +// Draw "fancy" wireframe, displaying front-facing, back-facing and +// silhouette lines differently. +// Mike Erwin, April 2015 + +uniform bool drawFront = true; +uniform bool drawBack = true; +uniform bool drawSilhouette = true; + +uniform vec4 frontColor; +uniform vec4 backColor; +uniform vec4 silhouetteColor; + +uniform vec3 eye; // direction we are looking + +uniform mat4 ModelViewProjectionMatrix; + +#if __VERSION__ == 120 + attribute vec3 pos; + + // normals of faces this edge joins (object coords) + attribute vec3 N1; + attribute vec3 N2; + + flat varying vec4 finalColor; +#else + in vec3 pos; + + // normals of faces this edge joins (object coords) + in vec3 N1; + in vec3 N2; + + flat out vec4 finalColor; +#endif + +// TODO: in float angle; // [-pi .. +pi], + peak, 0 flat, - valley + +// to discard an entire line, set both endpoints to nowhere +// and it won't produce any fragments +const vec4 nowhere = vec4(vec3(0.0), 1.0); + +void main() +{ + bool face_1_front = dot(N1, eye) > 0.0; + bool face_2_front = dot(N2, eye) > 0.0; + + vec4 position = ModelViewProjectionMatrix * vec4(pos, 1.0); + + if (face_1_front && face_2_front) { + // front-facing edge + gl_Position = drawFront ? position : nowhere; + finalColor = frontColor; + } + else if (face_1_front || face_2_front) { + // exactly one face is front-facing, silhouette edge + gl_Position = drawSilhouette ? position : nowhere; + finalColor = silhouetteColor; + } + else { + // back-facing edge + gl_Position = drawBack ? position : nowhere; + finalColor = backColor; + } +} diff --git a/source/blender/gpu/shaders/gpu_shader_edges_front_back_persp_geom.glsl b/source/blender/gpu/shaders/gpu_shader_edges_front_back_persp_geom.glsl new file mode 100644 index 00000000000..10b5fad7972 --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_edges_front_back_persp_geom.glsl @@ -0,0 +1,60 @@ + +// Draw "fancy" wireframe, displaying front-facing, back-facing and +// silhouette lines differently. +// Mike Erwin, April 2015 + +// After working with this shader a while, convinced we should make +// separate shaders for perpective & ortho. (Oct 2016) + +// Due to perspective, the line segment's endpoints might disagree on +// whether the adjacent faces are front facing. This geometry shader +// decides which edge type to use if endpoints disagree. + +uniform mat4 ProjectionMatrix; + +uniform bool drawFront = true; +uniform bool drawBack = true; +uniform bool drawSilhouette = true; + +uniform vec4 frontColor; +uniform vec4 backColor; +uniform vec4 silhouetteColor; + +layout(lines) in; +layout(line_strip, max_vertices = 2) out; + +in vec4 MV_pos[]; +in float edgeClass[]; + +flat out vec4 finalColor; + +void emitLine(vec4 color) +{ + gl_Position = ProjectionMatrix * MV_pos[0]; + EmitVertex(); + gl_Position = ProjectionMatrix * MV_pos[1]; + finalColor = color; + EmitVertex(); + EndPrimitive(); +} + +void main() +{ + float finalEdgeClass = max(edgeClass[0], edgeClass[1]); + + if (finalEdgeClass > 0.0f) { + // front-facing edge + if (drawFront) + emitLine(frontColor); + } + else if (finalEdgeClass < 0.0f) { + // back-facing edge + if (drawBack) + emitLine(backColor); + } + else { + // exactly one face is front-facing, silhouette edge + if (drawSilhouette) + emitLine(silhouetteColor); + } +} diff --git a/source/blender/gpu/shaders/gpu_shader_edges_front_back_persp_legacy_vert.glsl b/source/blender/gpu/shaders/gpu_shader_edges_front_back_persp_legacy_vert.glsl new file mode 100644 index 00000000000..baf69c3e272 --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_edges_front_back_persp_legacy_vert.glsl @@ -0,0 +1,78 @@ + +// Draw "fancy" wireframe, displaying front-facing, back-facing and +// silhouette lines differently. +// Mike Erwin, April 2015 + +// After working with this shader a while, convinced we should make +// separate shaders for perpective & ortho. (Oct 2016) + +// This shader is an imperfect stepping stone until all platforms are +// ready for geometry shaders. + +// Due to perspective, the line segment's endpoints might disagree on +// whether the adjacent faces are front facing. Need to use a geometry +// shader or pass in an extra position attribute (the other endpoint) +// to do this properly. + +uniform bool drawFront = true; +uniform bool drawBack = true; +uniform bool drawSilhouette = true; + +uniform vec4 frontColor; +uniform vec4 backColor; +uniform vec4 silhouetteColor; + +uniform mat4 ModelViewMatrix; +uniform mat4 ModelViewProjectionMatrix; +uniform mat3 NormalMatrix; + +#if __VERSION__ == 120 + attribute vec3 pos; + + // normals of faces this edge joins (object coords) + attribute vec3 N1; + attribute vec3 N2; + + flat varying vec4 finalColor; +#else + in vec3 pos; + + // normals of faces this edge joins (object coords) + in vec3 N1; + in vec3 N2; + + flat out vec4 finalColor; +#endif + +// TODO: in float angle; // [-pi .. +pi], + peak, 0 flat, - valley + +// to discard an entire line, set its color to invisible +// (must have GL_BLEND enabled, or discard in fragment shader) +const vec4 invisible = vec4(0.0); + +bool front(vec3 N) +{ + vec4 xformed = ModelViewMatrix * vec4(pos, 1.0); + return dot(NormalMatrix * N, normalize(-xformed.xyz)) > 0.0; +} + +void main() +{ + bool face_1_front = front(N1); + bool face_2_front = front(N2); + + gl_Position = ModelViewProjectionMatrix * vec4(pos, 1.0); + + if (face_1_front && face_2_front) { + // front-facing edge + finalColor = drawFront ? frontColor : invisible; + } + else if (face_1_front || face_2_front) { + // exactly one face is front-facing, silhouette edge + finalColor = drawSilhouette ? silhouetteColor : invisible; + } + else { + // back-facing edge + finalColor = drawBack ? backColor : invisible; + } +} diff --git a/source/blender/gpu/shaders/gpu_shader_edges_front_back_persp_vert.glsl b/source/blender/gpu/shaders/gpu_shader_edges_front_back_persp_vert.glsl new file mode 100755 index 00000000000..e1fb78dd1a9 --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_edges_front_back_persp_vert.glsl @@ -0,0 +1,44 @@ + +// Draw "fancy" wireframe, displaying front-facing, back-facing and +// silhouette lines differently. +// Mike Erwin, April 2015 + +// After working with this shader a while, convinced we should make +// separate shaders for perpective & ortho. (Oct 2016) + +// Due to perspective, the line segment's endpoints might disagree on +// whether the adjacent faces are front facing. We use a geometry +// shader to resolve this properly. + +uniform mat4 ModelViewMatrix; +uniform mat3 NormalMatrix; + +in vec3 pos; +in vec3 N1, N2; // normals of faces this edge joins (object coords) + +out vec4 MV_pos; +out float edgeClass; + +// TODO: in float angle; // [-pi .. +pi], + peak, 0 flat, - valley + +bool front(vec3 N, vec3 eye) +{ + return dot(NormalMatrix * N, eye) > 0.0; +} + +void main() +{ + MV_pos = ModelViewMatrix * vec4(pos, 1.0); + + vec3 eye = normalize(-MV_pos.xyz); + + bool face_1_front = front(N1, eye); + bool face_2_front = front(N2, eye); + + if (face_1_front && face_2_front) + edgeClass = 1.0; // front-facing edge + else if (face_1_front || face_2_front) + edgeClass = 0.0; // exactly one face is front-facing, silhouette edge + else + edgeClass = -1.0; // back-facing edge +} diff --git a/source/blender/gpu/shaders/gpu_shader_edges_overlay_frag.glsl b/source/blender/gpu/shaders/gpu_shader_edges_overlay_frag.glsl new file mode 100644 index 00000000000..0538c037dcf --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_edges_overlay_frag.glsl @@ -0,0 +1,20 @@ + +#define SMOOTH 1 + +const float transitionWidth = 1.0; + +uniform vec4 fillColor = vec4(0); +uniform vec4 outlineColor = vec4(0,0,0,1); + +noperspective in vec3 distanceToOutline; + +out vec4 FragColor; + +void main() { + float edgeness = min(min(distanceToOutline.x, distanceToOutline.y), distanceToOutline.z); +#if SMOOTH + FragColor = mix(outlineColor, fillColor, smoothstep(0, transitionWidth, edgeness)); +#else + FragColor = (edgeness <= 0) ? outlineColor : fillColor; +#endif +} diff --git a/source/blender/gpu/shaders/gpu_shader_edges_overlay_geom.glsl b/source/blender/gpu/shaders/gpu_shader_edges_overlay_geom.glsl new file mode 100644 index 00000000000..ad0dccb6c81 --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_edges_overlay_geom.glsl @@ -0,0 +1,67 @@ +layout(triangles) in; +layout(triangle_strip, max_vertices=3) out; + +uniform float outlineWidth = 1.0; +uniform vec2 viewportSize; + +in vec4 pos_xformed[]; +in float widthModulator[]; + +noperspective out vec3 distanceToOutline; + +// project to screen space +vec2 proj(int axis) { + vec4 pos = pos_xformed[axis]; + return (0.5 * (pos.xy / pos.w) + 0.5) * viewportSize; +} + +float dist(vec2 pos[3], int v) { + // current vertex position + vec2 vpos = pos[v]; + // endpoints of opposite edge + vec2 e1 = pos[(v + 1) % 3]; + vec2 e2 = pos[(v + 2) % 3]; + + float abs_det = length(cross(vec3(vpos - e1, 0), vec3(vpos - e2, 0))); // could simplify + return abs_det / distance(e2, e1); +} + +vec3 distance[3]; + +void clearEdge(int v) { + float distant = 10 * outlineWidth; + for (int i = 0; i < 3; ++i) + distance[i][v] += distant; +} + +void modulateEdge(int v) { + float offset = min(widthModulator[v],1) * outlineWidth; + for (int i = 0; i < 3; ++i) + distance[i][v] -= offset; +} + +void main() { + vec2 pos[3] = vec2[3](proj(0), proj(1), proj(2)); + + for (int v = 0; v < 3; ++v) + distance[v] = vec3(0); + + for (int v = 0; v < 3; ++v) { + if (widthModulator[v] > 0) { + distance[v][v] = dist(pos, v); + modulateEdge(v); + } + } + + for (int v = 0; v < 3; ++v) + if (widthModulator[v] <= 0) + clearEdge(v); + + for (int v = 0; v < 3; ++v) { + gl_Position = pos_xformed[v]; + distanceToOutline = distance[v]; + EmitVertex(); + } + + EndPrimitive(); +} diff --git a/source/blender/gpu/shaders/gpu_shader_edges_overlay_simple_geom.glsl b/source/blender/gpu/shaders/gpu_shader_edges_overlay_simple_geom.glsl new file mode 100644 index 00000000000..ec692e210c2 --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_edges_overlay_simple_geom.glsl @@ -0,0 +1,52 @@ +layout(triangles) in; +layout(triangle_strip, max_vertices=3) out; + +uniform float outlineWidth = 1.0; +uniform vec2 viewportSize; + +noperspective out vec3 distanceToOutline; + +// project to screen space +vec2 proj(int axis) { + vec4 pos = gl_in[axis].gl_Position; + return (0.5 * (pos.xy / pos.w) + 0.5) * viewportSize; +} + +float dist(vec2 pos[3], int v) { + // current vertex position + vec2 vpos = pos[v]; + // endpoints of opposite edge + vec2 e1 = pos[(v + 1) % 3]; + vec2 e2 = pos[(v + 2) % 3]; + + float abs_det = length(cross(vec3(vpos - e1, 0), vec3(vpos - e2, 0))); // could simplify + return abs_det / distance(e2, e1); +} + +vec3 distance[3]; + +void modulateEdge(int v) { + float offset = 0.5 * outlineWidth; + for (int i = 0; i < 3; ++i) + distance[i][v] -= offset; +} + +void main() { + vec2 pos[3] = vec2[3](proj(0), proj(1), proj(2)); + + for (int v = 0; v < 3; ++v) + distance[v] = vec3(0); + + for (int v = 0; v < 3; ++v) { + distance[v][v] = dist(pos, v); + modulateEdge(v); + } + + for (int v = 0; v < 3; ++v) { + gl_Position = gl_in[v].gl_Position; + distanceToOutline = distance[v]; + EmitVertex(); + } + + EndPrimitive(); +} diff --git a/source/blender/gpu/shaders/gpu_shader_edges_overlay_vert.glsl b/source/blender/gpu/shaders/gpu_shader_edges_overlay_vert.glsl new file mode 100644 index 00000000000..71a43d1b7ae --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_edges_overlay_vert.glsl @@ -0,0 +1,13 @@ + +//mat4 ModelViewProjectionMatrix; + +in vec3 pos; +in float edgeWidthModulator; + +out vec4 pos_xformed; +out float widthModulator; + +void main() { + pos_xformed = gl_ModelViewProjectionMatrix * vec4(pos, 1.0); + widthModulator = edgeWidthModulator; +} diff --git a/source/blender/gpu/shaders/gpu_shader_flat_color_alpha_test_0_frag.glsl b/source/blender/gpu/shaders/gpu_shader_flat_color_alpha_test_0_frag.glsl new file mode 100644 index 00000000000..10b4c2ac39d --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_flat_color_alpha_test_0_frag.glsl @@ -0,0 +1,16 @@ + +#if __VERSION__ == 120 + flat varying vec4 finalColor; + #define fragColor gl_FragColor +#else + flat in vec4 finalColor; + out vec4 fragColor; +#endif + +void main() +{ + if (finalColor.a > 0.0) + fragColor = finalColor; + else + discard; +} diff --git a/source/blender/gpu/shaders/gpu_shader_flat_color_frag.glsl b/source/blender/gpu/shaders/gpu_shader_flat_color_frag.glsl new file mode 100644 index 00000000000..91097d24cb2 --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_flat_color_frag.glsl @@ -0,0 +1,13 @@ + +#if __VERSION__ == 120 + flat varying vec4 finalColor; + #define fragColor gl_FragColor +#else + flat in vec4 finalColor; + out vec4 fragColor; +#endif + +void main() +{ + fragColor = finalColor; +} diff --git a/source/blender/gpu/shaders/gpu_shader_image_color_frag.glsl b/source/blender/gpu/shaders/gpu_shader_image_color_frag.glsl new file mode 100644 index 00000000000..b7697b0a3cc --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_image_color_frag.glsl @@ -0,0 +1,17 @@ + +#if __VERSION__ == 120 + varying vec2 texCoord_interp; + #define fragColor gl_FragColor +#else + in vec2 texCoord_interp; + out vec4 fragColor; + #define texture2D texture +#endif + +uniform vec4 color; +uniform sampler2D image; + +void main() +{ + fragColor = texture2D(image, texCoord_interp) * color; +} diff --git a/source/blender/gpu/shaders/gpu_shader_image_depth_linear_frag.glsl b/source/blender/gpu/shaders/gpu_shader_image_depth_linear_frag.glsl new file mode 100644 index 00000000000..7f76fbf03be --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_image_depth_linear_frag.glsl @@ -0,0 +1,22 @@ + +#if __VERSION__ == 120 + varying vec2 texCoord_interp; + #define fragColor gl_FragColor +#else + in vec2 texCoord_interp; + out vec4 fragColor; + #define texture2D texture +#endif + +uniform float znear; +uniform float zfar; +uniform sampler2D image; + +void main() +{ + float depth = texture2D(image, texCoord_interp).r; + + /* normalize */ + fragColor.rgb = vec3((2.0f * znear) / (zfar + znear - (depth * (zfar - znear)))); + fragColor.a = 1.0f; +} diff --git a/source/blender/gpu/shaders/gpu_shader_image_interlace_frag.glsl b/source/blender/gpu/shaders/gpu_shader_image_interlace_frag.glsl new file mode 100644 index 00000000000..8b303104bb3 --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_image_interlace_frag.glsl @@ -0,0 +1,52 @@ + +/* Keep these in sync with GPU_shader.h */ +#define INTERLACE_ROW 0 +#define INTERLACE_COLUMN 1 +#define INTERLACE_CHECKERBOARD 2 + +#if __VERSION__ == 120 + varying vec2 texCoord_interp; + #define fragColor gl_FragColor +#else + in vec2 texCoord_interp; + out vec4 fragColor; + #define texture2DRect texture +#endif + +uniform int interlace_id; +uniform sampler2DRect image_a; +uniform sampler2DRect image_b; + +bool interlace() +{ +#if __VERSION__ == 120 + if (interlace_id == INTERLACE_CHECKERBOARD) { + return int(mod(gl_FragCoord.x + gl_FragCoord.y, 2)) != 0; + } + else if (interlace_id == INTERLACE_ROW) { + return int(mod(gl_FragCoord.y, 2)) != 0; + } + else if (interlace_id == INTERLACE_COLUMN) { + return int(mod(gl_FragCoord.x, 2)) != 0; + } +#else + if (interlace_id == INTERLACE_CHECKERBOARD) { + return (int(gl_FragCoord.x + gl_FragCoord.y) & 1) != 0; + } + else if (interlace_id == INTERLACE_ROW) { + return (int(gl_FragCoord.y) & 1) != 0; + } + else if (interlace_id == INTERLACE_COLUMN) { + return (int(gl_FragCoord.x) & 1) != 0; + } +#endif +} + +void main() +{ + if (interlace()) { + fragColor = texture2DRect(image_a, texCoord_interp); + } else { + fragColor = texture2DRect(image_b, texCoord_interp); + } +} diff --git a/source/blender/gpu/shaders/gpu_shader_image_mask_uniform_color_frag.glsl b/source/blender/gpu/shaders/gpu_shader_image_mask_uniform_color_frag.glsl new file mode 100644 index 00000000000..e78779559a1 --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_image_mask_uniform_color_frag.glsl @@ -0,0 +1,18 @@ + +#if __VERSION__ == 120 + varying vec2 texCoord_interp; + #define fragColor gl_FragColor +#else + in vec2 texCoord_interp; + out vec4 fragColor; + #define texture2D texture +#endif + +uniform sampler2D image; +uniform vec4 color; + +void main() +{ + fragColor.a = texture2D(image, texCoord_interp).a * color.a; + fragColor.rgb = color.rgb; +} diff --git a/source/blender/gpu/shaders/gpu_shader_image_modulate_alpha_frag.glsl b/source/blender/gpu/shaders/gpu_shader_image_modulate_alpha_frag.glsl new file mode 100644 index 00000000000..74e17198985 --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_image_modulate_alpha_frag.glsl @@ -0,0 +1,18 @@ + +#if __VERSION__ == 120 + varying vec2 texCoord_interp; + #define fragColor gl_FragColor +#else + in vec2 texCoord_interp; + out vec4 fragColor; + #define texture2D texture +#endif + +uniform float alpha; +uniform sampler2D image; + +void main() +{ + fragColor = texture2D(image, texCoord_interp); + fragColor.a *= alpha; +} diff --git a/source/blender/gpu/shaders/gpu_shader_image_rect_modulate_alpha_frag.glsl b/source/blender/gpu/shaders/gpu_shader_image_rect_modulate_alpha_frag.glsl new file mode 100644 index 00000000000..aae3b40efd4 --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_image_rect_modulate_alpha_frag.glsl @@ -0,0 +1,18 @@ + +#if __VERSION__ == 120 + varying vec2 texCoord_interp; + #define fragColor gl_FragColor +#else + in vec2 texCoord_interp; + out vec4 fragColor; + #define texture2DRect texture +#endif + +uniform float alpha; +uniform sampler2DRect image; + +void main() +{ + fragColor = texture2DRect(image, texCoord_interp); + fragColor.a *= alpha; +} diff --git a/source/blender/gpu/shaders/gpu_shader_instance_objectspace_variying_color_vert.glsl b/source/blender/gpu/shaders/gpu_shader_instance_objectspace_variying_color_vert.glsl new file mode 100644 index 00000000000..ce82dc6af2a --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_instance_objectspace_variying_color_vert.glsl @@ -0,0 +1,29 @@ + +uniform mat4 ViewMatrix; +uniform mat4 ViewProjectionMatrix; +uniform mat4 ModelMatrix; + +/* ---- Instanciated Attribs ---- */ +in vec3 pos; +in vec3 nor; + +/* ---- Per instance Attribs ---- */ +in mat4 InstanceModelMatrix; +in vec4 color; + +out vec3 normal; +flat out vec4 finalColor; + +void main() +{ + mat4 FinalModelMatrix = ModelMatrix * InstanceModelMatrix; + mat4 ModelViewProjectionMatrix = ViewProjectionMatrix * FinalModelMatrix; + /* This is slow and run per vertex, but it's still faster than + * doing it per instance on CPU and sending it on via instance attrib */ + mat3 NormalMatrix = transpose(inverse(mat3(ViewMatrix * FinalModelMatrix))); + + gl_Position = ModelViewProjectionMatrix * vec4(pos, 1.0); + normal = NormalMatrix * nor; + + finalColor = color; +} diff --git a/source/blender/gpu/shaders/gpu_shader_instance_screen_aligned_axis_name_vert.glsl b/source/blender/gpu/shaders/gpu_shader_instance_screen_aligned_axis_name_vert.glsl new file mode 100644 index 00000000000..a39bfde41ee --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_instance_screen_aligned_axis_name_vert.glsl @@ -0,0 +1,29 @@ + +uniform mat4 ViewProjectionMatrix; +uniform vec3 screen_vecs[2]; + +/* ---- Instanciated Attribs ---- */ +in vec3 pos; /* using Z as axis id */ + +/* ---- Per instance Attribs ---- */ +in mat4 InstanceModelMatrix; +in vec3 color; +in float size; + +flat out vec4 finalColor; + +void main() +{ + vec3 offset; + + if (pos.z == 0.0) + offset = vec3(1.125, 0.0, 0.0); + else if (pos.z == 1.0) + offset = vec3(0.0, 1.125, 0.0); + else + offset = vec3(0.0, 0.0, 1.125); + + vec3 screen_pos = screen_vecs[0].xyz * pos.x + screen_vecs[1].xyz * pos.y; + gl_Position = ViewProjectionMatrix * (InstanceModelMatrix * vec4(offset * size, 1.0) + vec4(screen_pos * size, 0.0)); + finalColor = vec4(color, 1.0); +} diff --git a/source/blender/gpu/shaders/gpu_shader_instance_screenspace_variying_color_vert.glsl b/source/blender/gpu/shaders/gpu_shader_instance_screenspace_variying_color_vert.glsl new file mode 100644 index 00000000000..ba0ac29fb79 --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_instance_screenspace_variying_color_vert.glsl @@ -0,0 +1,29 @@ + +uniform mat4 ViewProjectionMatrix; +uniform vec3 screen_vecs[2]; +uniform float size; +uniform float pixel_size; + +/* ---- Instanciated Attribs ---- */ +in vec2 pos; + +/* ---- Per instance Attribs ---- */ +in vec3 world_pos; +in vec3 color; + +flat out vec4 finalColor; + +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(world_pos) * pixel_size; + vec3 screen_pos = screen_vecs[0].xyz * pos.x + screen_vecs[1].xyz * pos.y; + gl_Position = ViewProjectionMatrix * vec4(world_pos + screen_pos * size * pix_size, 1.0); + finalColor = vec4(color, 1.0); +} diff --git a/source/blender/gpu/shaders/gpu_shader_instance_variying_size_variying_color_vert.glsl b/source/blender/gpu/shaders/gpu_shader_instance_variying_size_variying_color_vert.glsl new file mode 100644 index 00000000000..9ade68644fe --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_instance_variying_size_variying_color_vert.glsl @@ -0,0 +1,18 @@ + +uniform mat4 ViewProjectionMatrix; + +/* ---- Instanciated Attribs ---- */ +in vec3 pos; + +/* ---- Per instance Attribs ---- */ +in mat4 InstanceModelMatrix; +in vec3 color; +in float size; + +flat out vec4 finalColor; + +void main() +{ + gl_Position = ViewProjectionMatrix * InstanceModelMatrix * vec4(pos * size, 1.0); + finalColor = vec4(color, 1.0); +} diff --git a/source/blender/gpu/shaders/gpu_shader_instance_vert.glsl b/source/blender/gpu/shaders/gpu_shader_instance_vert.glsl new file mode 100644 index 00000000000..eac167e8045 --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_instance_vert.glsl @@ -0,0 +1,13 @@ + +uniform mat4 ViewProjectionMatrix; + +/* ---- Instanciated Attribs ---- */ +in vec3 pos; + +/* ---- Per instance Attribs ---- */ +in mat4 InstanceModelMatrix; + +void main() +{ + gl_Position = ViewProjectionMatrix * InstanceModelMatrix * vec4(pos, 1.0); +} diff --git a/source/blender/gpu/shaders/gpu_shader_keyframe_diamond_frag.glsl b/source/blender/gpu/shaders/gpu_shader_keyframe_diamond_frag.glsl new file mode 100644 index 00000000000..43a7e42153a --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_keyframe_diamond_frag.glsl @@ -0,0 +1,38 @@ + +#if __VERSION__ == 120 + varying vec4 radii; + varying vec4 finalColor; + varying vec4 finalOutlineColor; + #define fragColor gl_FragColor +#else + in vec4 radii; + in vec4 finalColor; + in vec4 finalOutlineColor; + out vec4 fragColor; +#endif + +void main() { + vec2 quad = abs(gl_PointCoord - vec2(0.5)); + float dist = quad.x + quad.y; + +// transparent outside of point +// --- 0 --- +// smooth transition +// --- 1 --- +// pure outline color +// --- 2 --- +// smooth transition +// --- 3 --- +// pure point color +// ... +// dist = 0 at center of point + + float mid_stroke = 0.5 * (radii[1] + radii[2]); + + vec4 backgroundColor = vec4(finalColor.rgb, 0.0); + + if (dist > mid_stroke) + fragColor = mix(finalOutlineColor, backgroundColor, smoothstep(radii[1], radii[0], dist)); + else + fragColor = mix(finalColor, finalOutlineColor, smoothstep(radii[3], radii[2], dist)); +} diff --git a/source/blender/gpu/shaders/gpu_shader_keyframe_diamond_vert.glsl b/source/blender/gpu/shaders/gpu_shader_keyframe_diamond_vert.glsl new file mode 100644 index 00000000000..69afefa685f --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_keyframe_diamond_vert.glsl @@ -0,0 +1,44 @@ + +uniform mat4 ModelViewProjectionMatrix; + +const float pixel_fudge = sqrt(2.0); +const float outline_width = 1.25 * pixel_fudge; + +#if __VERSION__ == 120 + attribute vec2 pos; + attribute float size; + attribute vec4 color; + attribute vec4 outlineColor; + varying vec4 finalColor; + varying vec4 finalOutlineColor; + varying vec4 radii; +#else + in vec2 pos; + in float size; + in vec4 color; + in vec4 outlineColor; + out vec4 finalColor; + out vec4 finalOutlineColor; + out vec4 radii; +#endif + +void main() { + gl_Position = ModelViewProjectionMatrix * vec4(pos, 0.0, 1.0); + + // pass through unchanged + gl_PointSize = size; + finalColor = color; + finalOutlineColor = outlineColor; + + // calculate concentric radii in pixels + float radius = 0.5 * gl_PointSize; + + // start at the outside and progress toward the center + radii[0] = radius; + radii[1] = radius - pixel_fudge; + radii[2] = radius - outline_width; + radii[3] = radius - outline_width - pixel_fudge; + + // convert to PointCoord units + radii /= size; +} diff --git a/source/blender/gpu/shaders/gpu_shader_point_uniform_color_frag.glsl b/source/blender/gpu/shaders/gpu_shader_point_uniform_color_frag.glsl new file mode 100644 index 00000000000..8e0c75db6bf --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_point_uniform_color_frag.glsl @@ -0,0 +1,21 @@ + +uniform vec4 color; + +#if __VERSION__ == 120 + #define fragColor gl_FragColor +#else + out vec4 fragColor; +#endif + +void main() +{ + vec2 centered = gl_PointCoord - vec2(0.5); + float dist_squared = dot(centered, centered); + const float rad_squared = 0.25; + + // round point with jaggy edges + if (dist_squared > rad_squared) + discard; + + fragColor = color; +} diff --git a/source/blender/gpu/shaders/gpu_shader_point_uniform_color_outline_smooth_frag.glsl b/source/blender/gpu/shaders/gpu_shader_point_uniform_color_outline_smooth_frag.glsl new file mode 100644 index 00000000000..f83785de95e --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_point_uniform_color_outline_smooth_frag.glsl @@ -0,0 +1,36 @@ + +uniform vec4 color; +uniform vec4 outlineColor; + +#if __VERSION__ == 120 + varying vec4 radii; + #define fragColor gl_FragColor +#else + in vec4 radii; + out vec4 fragColor; +#endif + +void main() { + float dist = length(gl_PointCoord - vec2(0.5)); + +// transparent outside of point +// --- 0 --- +// smooth transition +// --- 1 --- +// pure outline color +// --- 2 --- +// smooth transition +// --- 3 --- +// pure point color +// ... +// dist = 0 at center of point + + float midStroke = 0.5 * (radii[1] + radii[2]); + + if (dist > midStroke) { + fragColor.rgb = outlineColor.rgb; + fragColor.a = mix(outlineColor.a, 0.0, smoothstep(radii[1], radii[0], dist)); + } + else + fragColor = mix(color, outlineColor, smoothstep(radii[3], radii[2], dist)); +} diff --git a/source/blender/gpu/shaders/gpu_shader_point_uniform_color_smooth_frag.glsl b/source/blender/gpu/shaders/gpu_shader_point_uniform_color_smooth_frag.glsl new file mode 100644 index 00000000000..8c8d81f6997 --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_point_uniform_color_smooth_frag.glsl @@ -0,0 +1,25 @@ + +uniform vec4 color; + +#if __VERSION__ == 120 + varying vec2 radii; + #define fragColor gl_FragColor +#else + in vec2 radii; + out vec4 fragColor; +#endif + +void main() { + float dist = length(gl_PointCoord - vec2(0.5)); + +// transparent outside of point +// --- 0 --- +// smooth transition +// --- 1 --- +// pure point color +// ... +// dist = 0 at center of point + + fragColor.rgb = color.rgb; + fragColor.a = mix(color.a, 0.0, smoothstep(radii[1], radii[0], dist)); +} diff --git a/source/blender/gpu/shaders/gpu_shader_point_varying_color_frag.glsl b/source/blender/gpu/shaders/gpu_shader_point_varying_color_frag.glsl new file mode 100644 index 00000000000..91092a9f727 --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_point_varying_color_frag.glsl @@ -0,0 +1,21 @@ + +#if __VERSION__ == 120 + varying vec4 finalColor; + #define fragColor gl_FragColor +#else + in vec4 finalColor; + out vec4 fragColor; +#endif + +void main() +{ + vec2 centered = gl_PointCoord - vec2(0.5); + float dist_squared = dot(centered, centered); + const float rad_squared = 0.25; + + // round point with jaggy edges + if (dist_squared > rad_squared) + discard; + + fragColor = finalColor; +} diff --git a/source/blender/gpu/shaders/gpu_shader_point_varying_color_outline_smooth_frag.glsl b/source/blender/gpu/shaders/gpu_shader_point_varying_color_outline_smooth_frag.glsl new file mode 100644 index 00000000000..d6cbe2d9a22 --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_point_varying_color_outline_smooth_frag.glsl @@ -0,0 +1,37 @@ + +uniform vec4 outlineColor; + +#if __VERSION__ == 120 + varying vec4 radii; + varying vec4 fillColor; + #define fragColor gl_FragColor +#else + in vec4 radii; + in vec4 fillColor; + out vec4 fragColor; +#endif + +void main() { + float dist = length(gl_PointCoord - vec2(0.5)); + +// transparent outside of point +// --- 0 --- +// smooth transition +// --- 1 --- +// pure outline color +// --- 2 --- +// smooth transition +// --- 3 --- +// pure fill color +// ... +// dist = 0 at center of point + + float midStroke = 0.5 * (radii[1] + radii[2]); + + if (dist > midStroke) { + fragColor.rgb = outlineColor.rgb; + fragColor.a = mix(outlineColor.a, 0.0, smoothstep(radii[1], radii[0], dist)); + } + else + fragColor = mix(fillColor, outlineColor, smoothstep(radii[3], radii[2], dist)); +} diff --git a/source/blender/gpu/shaders/gpu_shader_simple_lighting_frag.glsl b/source/blender/gpu/shaders/gpu_shader_simple_lighting_frag.glsl new file mode 100644 index 00000000000..4eacd08d5af --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_simple_lighting_frag.glsl @@ -0,0 +1,25 @@ + +#ifndef USE_INSTANCE_COLOR +uniform vec4 color; +#endif +uniform vec3 light; + +#if __VERSION__ == 120 + varying vec3 normal; +#ifdef USE_INSTANCE_COLOR + varying vec4 finalColor; +#endif + #define fragColor gl_FragColor +#else + in vec3 normal; +#ifdef USE_INSTANCE_COLOR + flat in vec4 finalColor; + #define color finalColor +#endif + out vec4 fragColor; +#endif + +void main() +{ + fragColor = color * max(0.0, dot(normalize(normal), light)); +} diff --git a/source/blender/gpu/shaders/gpu_shader_text_frag.glsl b/source/blender/gpu/shaders/gpu_shader_text_frag.glsl new file mode 100644 index 00000000000..9283d682767 --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_text_frag.glsl @@ -0,0 +1,22 @@ + +#if __VERSION__ == 120 + flat varying vec4 color_flat; + noperspective varying vec2 texCoord_interp; + #define fragColor gl_FragColor +#else + flat in vec4 color_flat; + noperspective in vec2 texCoord_interp; + out vec4 fragColor; + #define texture2D texture +#endif + +uniform sampler2D glyph; + +void main() +{ + // input color replaces texture color + fragColor.rgb = color_flat.rgb; + + // modulate input alpha & texture alpha + fragColor.a = color_flat.a * texture2D(glyph, texCoord_interp).a; +} diff --git a/source/blender/gpu/shaders/gpu_shader_text_vert.glsl b/source/blender/gpu/shaders/gpu_shader_text_vert.glsl new file mode 100644 index 00000000000..44568f28c8e --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_text_vert.glsl @@ -0,0 +1,24 @@ + +uniform mat4 ModelViewProjectionMatrix; + +#if __VERSION__ == 120 + attribute vec2 pos; + attribute vec2 texCoord; + attribute vec4 color; + flat varying vec4 color_flat; + noperspective varying vec2 texCoord_interp; +#else + in vec2 pos; + in vec2 texCoord; + in vec4 color; + flat out vec4 color_flat; + noperspective out vec2 texCoord_interp; +#endif + +void main() +{ + gl_Position = ModelViewProjectionMatrix * vec4(pos, 0.0, 1.0); + + color_flat = color; + texCoord_interp = texCoord; +} diff --git a/source/blender/gpu/shaders/gpu_shader_uniform_color_frag.glsl b/source/blender/gpu/shaders/gpu_shader_uniform_color_frag.glsl new file mode 100644 index 00000000000..af200bf8661 --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_uniform_color_frag.glsl @@ -0,0 +1,13 @@ + +uniform vec4 color; + +#if __VERSION__ == 120 + #define fragColor gl_FragColor +#else + out vec4 fragColor; +#endif + +void main() +{ + fragColor = color; +} diff --git a/source/blender/makesdna/DNA_action_types.h b/source/blender/makesdna/DNA_action_types.h index 1083400ece2..cc64ce92881 100644 --- a/source/blender/makesdna/DNA_action_types.h +++ b/source/blender/makesdna/DNA_action_types.h @@ -238,6 +238,8 @@ typedef struct bPoseChannel { float chan_mat[4][4]; /* matrix result of loc/quat/size, and where we put deform in, see next line */ float pose_mat[4][4]; /* constraints accumulate here. in the end, pose_mat = bone->arm_mat * chan_mat * this matrix is object space */ + float disp_mat[4][4]; /* for display, pose_mat with bone length applied */ + float disp_tail_mat[4][4]; /* for display, pose_mat with bone length applied and translated to tail*/ float constinv[4][4]; /* inverse result of constraints. * doesn't include effect of restposition, parent, and local transform*/ diff --git a/source/blender/makesdna/DNA_gpencil_types.h b/source/blender/makesdna/DNA_gpencil_types.h index 0364d855f69..bb526c41049 100644 --- a/source/blender/makesdna/DNA_gpencil_types.h +++ b/source/blender/makesdna/DNA_gpencil_types.h @@ -298,6 +298,7 @@ typedef struct bGPdata { short sbuffer_sflag; /* flags for stroke that cache represents */ void *sbuffer; /* stroke buffer (can hold GP_STROKE_BUFFER_MAX) */ float scolor[4]; /* buffer color using palettes */ + float sfill[4]; /* buffer fill color */ char pad[6]; /* padding for compiler alignment error */ short sflag; /* settings for palette color */ diff --git a/source/blender/makesdna/DNA_layer_types.h b/source/blender/makesdna/DNA_layer_types.h new file mode 100644 index 00000000000..de2bd51f647 --- /dev/null +++ b/source/blender/makesdna/DNA_layer_types.h @@ -0,0 +1,177 @@ +/* + * ***** 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. + * + * Contributor(s): Dalai Felinto + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file DNA_layer_types.h + * \ingroup DNA + */ + +#ifndef __DNA_LAYER_TYPES_H__ +#define __DNA_LAYER_TYPES_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "DNA_listBase.h" + +typedef struct Base { + struct Base *next, *prev; + short flag; + short refcount; + short sx, sy; + struct Object *object; + unsigned int selcol; + unsigned int lay; + int flag_legacy; + int pad; +} Base; + +typedef struct CollectionOverride { + struct CollectionOverride *next, *prev; + char name[64]; /* MAX_NAME */ + /* TODO proper data */ +} CollectionOverride; + +typedef struct LayerCollection { + struct LayerCollection *next, *prev; + struct SceneCollection *scene_collection; + short flag; + short pad[3]; + 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 */ + ListBase mode_settings; /* CollectionModeSettings */ +} LayerCollection; + +typedef struct SceneLayer { + struct SceneLayer *next, *prev; + char name[64]; /* MAX_NAME */ + char engine[32]; /* render engine */ + short active_collection; + short flag; + short pad[2]; + ListBase object_bases; /* ObjectBase */ + struct Base *basact; + ListBase layer_collections; /* LayerCollection */ +} SceneLayer; + +typedef struct SceneCollection { + struct SceneCollection *next, *prev; + char name[64]; /* MAX_NAME */ + char filter[64]; /* MAX_NAME */ + int active_object_index; /* for UI */ + int pad; + ListBase objects; /* (Object *)LinkData->data */ + ListBase filter_objects; /* (Object *)LinkData->data */ + ListBase scene_collections; /* nested collections */ +} SceneCollection; + +/* Base->flag */ +enum { + BASE_SELECTED = (1 << 0), + BASE_VISIBLED = (1 << 1), + BASE_SELECTABLED = (1 << 2), + BASE_FROMDUPLI = (1 << 3), + BASE_DIRTY_ENGINE_SETTINGS = (1 << 4), +}; + +/* LayerCollection->flag */ +enum { + COLLECTION_VISIBLE = (1 << 0), + COLLECTION_SELECTABLE = (1 << 1), + COLLECTION_FOLDED = (1 << 2), +}; + +/* 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 CollectionEnginePropertyBool { + struct CollectionEngineProperty data; + int value; + int pad; +} CollectionEnginePropertyBool; + +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 */ + int type; /* CollectionEngineSettingsType */ + int pad; +} CollectionEngineSettings; + +/* CollectionEngineProperty->flag */ +enum { + COLLECTION_PROP_USE = (1 << 0), +}; + +/* CollectionEngineProperty.type */ +typedef enum CollectionEnginePropertyType { + COLLECTION_PROP_TYPE_FLOAT = 0, + COLLECTION_PROP_TYPE_INT = 1, + COLLECTION_PROP_TYPE_BOOL = 2, +} CollectionEnginePropertyType; + +/* CollectionEngineSettings->type */ +typedef enum CollectionEngineSettingsType { + COLLECTION_MODE_NONE = 0, + COLLECTION_MODE_OBJECT = 1, + COLLECTION_MODE_EDIT = 2, +} CollectionModeSettingsType; + +/* *************************************************************** */ + + +#ifdef __cplusplus +} +#endif + +#endif /* __DNA_LAYER_TYPES_H__ */ + 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_mesh_types.h b/source/blender/makesdna/DNA_mesh_types.h index 39e56925903..15ea3d4d37a 100644 --- a/source/blender/makesdna/DNA_mesh_types.h +++ b/source/blender/makesdna/DNA_mesh_types.h @@ -127,6 +127,7 @@ typedef struct Mesh { short totcol; struct Multires *mr DNA_DEPRECATED; /* deprecated multiresolution modeling data, only keep for loading old files */ + void *batch_cache; } Mesh; /* deprecated by MTFace, only here for file reading */ diff --git a/source/blender/makesdna/DNA_object_types.h b/source/blender/makesdna/DNA_object_types.h index d24c7faa9f5..fb0a02e92ae 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 CollectionEngineSettings; struct Path; struct Material; struct PartDeflect; @@ -223,7 +224,10 @@ typedef struct Object { float jump_speed; float fall_speed; unsigned char max_jumps; - char pad2[3]; + char pad2; + + /* Depsgraph */ + short base_flag; /* used by depsgraph, flushed from base */ /** Collision mask settings */ unsigned short col_group, col_mask; @@ -299,6 +303,8 @@ typedef struct Object { LodLevel *currentlod; struct PreviewImage *preview; + + 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_outliner_types.h b/source/blender/makesdna/DNA_outliner_types.h index 984e3334414..8c9de0665c4 100644 --- a/source/blender/makesdna/DNA_outliner_types.h +++ b/source/blender/makesdna/DNA_outliner_types.h @@ -50,11 +50,14 @@ typedef struct TreeStore { } TreeStore; /* TreeStoreElem->flag */ -#define TSE_CLOSED 1 -#define TSE_SELECTED 2 -#define TSE_TEXTBUT 4 -#define TSE_CHILDSEARCH 8 -#define TSE_SEARCHMATCH 16 +enum { + TSE_CLOSED = (1 << 0), + TSE_SELECTED = (1 << 1), + TSE_TEXTBUT = (1 << 2), + TSE_CHILDSEARCH = (1 << 3), + TSE_SEARCHMATCH = (1 << 4), + TSE_HIGHLIGHTED = (1 << 5), +}; /* TreeStoreElem->types */ #define TSE_NLA 1 /* NO ID */ @@ -96,6 +99,7 @@ typedef struct TreeStore { #define TSE_KEYMAP_ITEM 35 /* NO ID */ #define TSE_ID_BASE 36 /* NO ID */ #define TSE_GP_LAYER 37 /* NO ID */ +#define TSE_COLLECTION 38 /* NO ID */ /* Check whether given TreeStoreElem should have a real ID in its ->id member. */ diff --git a/source/blender/makesdna/DNA_scene_types.h b/source/blender/makesdna/DNA_scene_types.h index 918d0f00040..03958b004ed 100644 --- a/source/blender/makesdna/DNA_scene_types.h +++ b/source/blender/makesdna/DNA_scene_types.h @@ -47,6 +47,8 @@ extern "C" { #include "DNA_ID.h" #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; @@ -65,18 +67,13 @@ struct bGPdata; struct bGPDbrush; struct MovieClip; struct ColorSpace; +struct SceneCollection; /* ************************************************************* */ /* Scene Data */ /* Base - Wrapper for referencing Objects in a Scene */ -typedef struct Base { - struct Base *next, *prev; - unsigned int lay, selcol; - int flag; - short sx, sy; - struct Object *object; -} Base; +#define BaseLegacy Base /* ************************************************************* */ /* Output Format Data */ @@ -543,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 { @@ -1628,7 +1669,7 @@ typedef struct Scene { struct Scene *set; ListBase base; - struct Base *basact; /* active base */ + struct BaseLegacy *basact; /* active base */ struct Object *obedit; /* name replaces old G.obedit */ float cursor[3]; /* 3d cursor location */ @@ -1706,6 +1747,14 @@ typedef struct Scene { struct RigidBodyWorld *rigidbody_world; struct PreviewImage *preview; + + ListBase render_layers; + struct SceneCollection *collection; + int active_layer; + int pad4; + + ListBase engines_settings; /* RenderEngineSettings */ + int pad5[2]; } Scene; /* **************** RENDERDATA ********************* */ @@ -1895,6 +1944,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 ********************* */ @@ -1913,16 +1963,16 @@ extern const char *RE_engine_id_CYCLES; /* depricate this! */ #define TESTBASE(v3d, base) ( \ - ((base)->flag & SELECT) && \ + ((base)->flag_legacy & SELECT) && \ ((base)->lay & v3d->lay) && \ (((base)->object->restrictflag & OB_RESTRICT_VIEW) == 0)) #define TESTBASELIB(v3d, base) ( \ - ((base)->flag & SELECT) && \ + ((base)->flag_legacy & SELECT) && \ ((base)->lay & v3d->lay) && \ ((base)->object->id.lib == NULL) && \ (((base)->object->restrictflag & OB_RESTRICT_VIEW) == 0)) #define TESTBASELIB_BGMODE(v3d, scene, base) ( \ - ((base)->flag & SELECT) && \ + ((base)->flag_legacy & SELECT) && \ ((base)->lay & (v3d ? v3d->lay : scene->lay)) && \ ((base)->object->id.lib == NULL) && \ (((base)->object->restrictflag & OB_RESTRICT_VIEW) == 0)) @@ -1931,20 +1981,41 @@ extern const char *RE_engine_id_CYCLES; ((base)->object->id.lib == NULL) && \ (((base)->object->restrictflag & OB_RESTRICT_VIEW) == 0)) #define BASE_SELECTABLE(v3d, base) ( \ - (base->lay & v3d->lay) && \ - (base->object->restrictflag & (OB_RESTRICT_SELECT | OB_RESTRICT_VIEW)) == 0) + (v3d != NULL) && \ + ((base)->object->restrictflag & (OB_RESTRICT_SELECT | OB_RESTRICT_VIEW)) == 0) #define BASE_VISIBLE(v3d, base) ( \ - (base->lay & v3d->lay) && \ - (base->object->restrictflag & OB_RESTRICT_VIEW) == 0) + ((base)->lay & v3d->lay) && \ + ((base)->object->restrictflag & OB_RESTRICT_VIEW) == 0) #define BASE_VISIBLE_BGMODE(v3d, scene, base) ( \ - (base->lay & (v3d ? v3d->lay : scene->lay)) && \ - (base->object->restrictflag & OB_RESTRICT_VIEW) == 0) + ((base)->lay & (v3d ? v3d->lay : scene->lay)) && \ + ((base)->object->restrictflag & OB_RESTRICT_VIEW) == 0) + +#define TESTBASELIB_NEW(base) ( \ + (((base)->flag & BASE_SELECTED) != 0) && \ + ((base)->object->id.lib == NULL) && \ + (((base)->flag & BASE_VISIBLED) != 0)) +#define TESTBASELIB_BGMODE_NEW(base) ( \ + (((base)->flag & BASE_SELECTED) != 0) && \ + ((base)->object->id.lib == NULL) && \ + (((base)->flag & BASE_VISIBLED) != 0)) +#define BASE_EDITABLE_BGMODE_NEW(base) ( \ + ((base)->object->id.lib == NULL) && \ + (((base)->flag & BASE_VISIBLED) != 0)) +#define BASE_SELECTABLE_NEW(base) \ + (((base)->flag & BASE_SELECTABLED) != 0) +#define BASE_VISIBLE_NEW(base) ( \ + ((base)->flag & BASE_VISIBLED) != 0) #define FIRSTBASE scene->base.first #define LASTBASE scene->base.last #define BASACT (scene->basact) #define OBACT (BASACT ? BASACT->object: NULL) +#define FIRSTBASE_NEW (sl)->object_bases.first +#define LASTBASE_NEW (sl)->object_bases.last +#define BASACT_NEW ((sl)->basact) +#define OBACT_NEW (BASACT_NEW ? BASACT_NEW->object: NULL) + #define V3D_CAMERA_LOCAL(v3d) ((!(v3d)->scenelock && (v3d)->camera) ? (v3d)->camera : NULL) #define V3D_CAMERA_SCENE(scene, v3d) ((!(v3d)->scenelock && (v3d)->camera) ? (v3d)->camera : (scene)->camera) @@ -1959,7 +2030,7 @@ extern const char *RE_engine_id_CYCLES; #define TIME2FRA(a) ((((double) scene->r.frs_sec) * (double)(a)) / (double)scene->r.frs_sec_base) #define FPS (((double) scene->r.frs_sec) / (double)scene->r.frs_sec_base) -/* base->flag is in DNA_object_types.h */ +/* base->legacy_flag is in DNA_object_types.h */ /* toolsettings->snap_flag */ #define SCE_SNAP 1 diff --git a/source/blender/makesdna/DNA_screen_types.h b/source/blender/makesdna/DNA_screen_types.h index e208ef39719..ce1f8d1a7d4 100644 --- a/source/blender/makesdna/DNA_screen_types.h +++ b/source/blender/makesdna/DNA_screen_types.h @@ -76,6 +76,8 @@ typedef struct bScreen { struct wmTimer *animtimer; /* if set, screen has timer handler added in window */ void *context; /* context callback */ + + PreviewImage *preview; } bScreen; typedef struct ScrVert { @@ -265,9 +267,10 @@ typedef struct ARegion { ListBase ui_previews; /* uiPreview */ ListBase handlers; /* wmEventHandler */ ListBase panels_category; /* Panel categories runtime */ - + + struct wmManipulatorMap *manipulator_map; /* manipulator-map of this region */ struct wmTimer *regiontimer; /* blend in/out */ - + char *headerstr; /* use this string to draw info */ void *regiondata; /* XXX 2.50, need spacedata equivalent? */ } ARegion; diff --git a/source/blender/makesdna/DNA_space_types.h b/source/blender/makesdna/DNA_space_types.h index 5e015544dc9..350b9675e9e 100644 --- a/source/blender/makesdna/DNA_space_types.h +++ b/source/blender/makesdna/DNA_space_types.h @@ -181,7 +181,8 @@ typedef enum eSpaceButtons_Context { BCONTEXT_CONSTRAINT = 11, BCONTEXT_BONE_CONSTRAINT = 12, BCONTEXT_RENDER_LAYER = 13, - + BCONTEXT_COLLECTION = 14, + /* always as last... */ BCONTEXT_TOT } eSpaceButtons_Context; @@ -273,21 +274,22 @@ typedef enum eSpaceOutliner_Flag { /* SpaceOops->outlinevis */ typedef enum eSpaceOutliner_Mode { - SO_ALL_SCENES = 0, - SO_CUR_SCENE = 1, - SO_VISIBLE = 2, - SO_SELECTED = 3, - SO_ACTIVE = 4, - SO_SAME_TYPE = 5, - SO_GROUPS = 6, - SO_LIBRARIES = 7, - /* SO_VERSE_SESSION = 8, */ /* deprecated! */ - /* SO_VERSE_MS = 9, */ /* deprecated! */ - SO_SEQUENCE = 10, - SO_DATABLOCKS = 11, - SO_USERDEF = 12, - /* SO_KEYMAP = 13, */ /* deprecated! */ - SO_ID_ORPHANS = 14, + SO_ALL_SCENES = 0, + SO_CUR_SCENE = 1, + SO_VISIBLE = 2, + SO_SELECTED = 3, + SO_ACTIVE = 4, + SO_SAME_TYPE = 5, + SO_GROUPS = 6, + SO_LIBRARIES = 7, + /* SO_VERSE_SESSION = 8, */ /* deprecated! */ + /* SO_VERSE_MS = 9, */ /* deprecated! */ + SO_SEQUENCE = 10, + SO_DATABLOCKS = 11, + SO_USERDEF = 12, + /* SO_KEYMAP = 13, */ /* deprecated! */ + SO_ID_ORPHANS = 14, + SO_COLLECTIONS = 15, } eSpaceOutliner_Mode; /* SpaceOops->storeflag */ diff --git a/source/blender/makesdna/DNA_userdef_types.h b/source/blender/makesdna/DNA_userdef_types.h index 0ad4482708f..1dc6c7ab578 100644 --- a/source/blender/makesdna/DNA_userdef_types.h +++ b/source/blender/makesdna/DNA_userdef_types.h @@ -490,6 +490,7 @@ typedef struct UserDef { short tb_leftmouse, tb_rightmouse; struct SolidLight light[3]; short tw_hotspot, tw_flag, tw_handlesize, tw_size; + short manipulator_scale, pad3[3]; short textimeout, texcollectrate; short wmdrawmethod; /* removed wmpad */ short dragthreshold; @@ -782,8 +783,6 @@ typedef enum eText_Draw_Options { USER_TEXT_DISABLE_AA = (1 << 0), } eText_Draw_Options; -/* tw_flag (transform widget) */ - /* gp_settings (Grease Pencil Settings) */ typedef enum eGP_UserdefSettings { GP_PAINT_DOSMOOTH = (1 << 0), diff --git a/source/blender/makesdna/DNA_view3d_types.h b/source/blender/makesdna/DNA_view3d_types.h index 4c243507e82..f84a6c3efc8 100644 --- a/source/blender/makesdna/DNA_view3d_types.h +++ b/source/blender/makesdna/DNA_view3d_types.h @@ -45,6 +45,7 @@ struct SmoothView3DStore; struct wmTimer; struct Material; struct GPUFX; +struct GPUViewport; /* This is needed to not let VC choke on near and far... old * proprietary MS extensions... */ @@ -65,6 +66,12 @@ struct GPUFX; /* The near/far thing is a Win EXCEPTION. Thus, leave near/far in the * code, and patch for windows. */ + +typedef struct View3DDebug { + float znear, zfar; + char background; + char pad[7]; +} View3DDebug; /* Background Picture in 3D-View */ typedef struct BGpic { @@ -111,7 +118,7 @@ typedef struct RegionView3D { struct wmTimer *smooth_timer; - /* transform widget matrix */ + /* transform manipulator matrix */ float twmat[4][4]; float viewquat[4]; /* view rotation, must be kept normalized */ @@ -147,6 +154,7 @@ typedef struct RegionView3D { float rot_axis[3]; struct GPUFX *compositor; + struct GPUViewport *viewport; } RegionView3D; /* 3D ViewPort Struct */ @@ -202,7 +210,7 @@ typedef struct View3D { short gridsubdiv; /* Number of subdivisions in the grid between each highlighted grid line */ char gridflag; - /* transform widget info */ + /* transform manipulator info */ char twtype, twmode, twflag; short flag3; @@ -217,8 +225,11 @@ typedef struct View3D { char multiview_eye; /* multiview current eye - for internal use */ - /* built-in shader effects (eGPUFXFlags) */ - char pad3[4]; + /* XXX tmp flags for 2.8 viewport transition to avoid compatibility issues that would be caused by + * using usual flag bitfields (which are saved to files). Can be removed when not needed anymore. */ + char tmp_compat_flag; + + char pad3[3]; /* note, 'fx_settings.dof' is currently _not_ allocated, * instead set (temporarily) from camera */ @@ -244,6 +255,7 @@ typedef struct View3D { short prev_drawtype; short pad1; float pad2; + View3DDebug debug; } View3D; @@ -320,6 +332,20 @@ typedef struct View3D { /* View3d->flag3 (short) */ #define V3D_SHOW_WORLD (1 << 0) +/* View3d->tmp_compat_flag */ +enum { + V3D_NEW_VIEWPORT = (1 << 0), + V3D_DEBUG_SHOW_SCENE_DEPTH = (1 << 1), + V3D_DEBUG_SHOW_COMBINED_DEPTH = (1 << 2), +}; + +/* View3d->debug.background */ +enum { + V3D_DEBUG_BACKGROUND_NONE = (1 << 0), + V3D_DEBUG_BACKGROUND_GRADIENT = (1 << 1), + V3D_DEBUG_BACKGROUND_WORLD = (1 << 2), +}; + /* View3D->around */ enum { /* center of the bounding box */ diff --git a/source/blender/makesdna/intern/makesdna.c b/source/blender/makesdna/intern/makesdna.c index 2cea8715a65..b6cf3d555fa 100644 --- a/source/blender/makesdna/intern/makesdna.c +++ b/source/blender/makesdna/intern/makesdna.c @@ -130,6 +130,7 @@ static const char *includefiles[] = { "DNA_freestyle_types.h", "DNA_linestyle_types.h", "DNA_cachefile_types.h", + "DNA_layer_types.h", /* see comment above before editing! */ /* empty string to indicate end of includefiles */ @@ -1342,4 +1343,5 @@ int main(int argc, char **argv) #include "DNA_freestyle_types.h" #include "DNA_linestyle_types.h" #include "DNA_cachefile_types.h" +#include "DNA_layer_types.h" /* end of list */ diff --git a/source/blender/makesrna/RNA_access.h b/source/blender/makesrna/RNA_access.h index 66e6f30feeb..e1f3320483b 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; @@ -317,6 +318,8 @@ extern StructRNA RNA_LaplacianSmoothModifier; extern StructRNA RNA_Lattice; extern StructRNA RNA_LatticeModifier; extern StructRNA RNA_LatticePoint; +extern StructRNA RNA_LayerCollection; +extern StructRNA RNA_LayerCollectionOverride; extern StructRNA RNA_Library; extern StructRNA RNA_LimitDistanceConstraint; extern StructRNA RNA_LimitLocationConstraint; @@ -383,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; @@ -498,12 +503,15 @@ 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; extern StructRNA RNA_SPHFluidSettings; extern StructRNA RNA_Scene; extern StructRNA RNA_SceneGameData; +extern StructRNA RNA_SceneLayer; extern StructRNA RNA_SceneRenderLayer; extern StructRNA RNA_SceneSequence; extern StructRNA RNA_SceneObjects; diff --git a/source/blender/makesrna/RNA_enum_types.h b/source/blender/makesrna/RNA_enum_types.h index 1c9b3593d17..b9bb741bcde 100644 --- a/source/blender/makesrna/RNA_enum_types.h +++ b/source/blender/makesrna/RNA_enum_types.h @@ -61,6 +61,7 @@ extern EnumPropertyItem rna_enum_object_modifier_type_items[]; extern EnumPropertyItem rna_enum_constraint_type_items[]; extern EnumPropertyItem rna_enum_boidrule_type_items[]; extern EnumPropertyItem rna_enum_sequence_modifier_type_items[]; +extern EnumPropertyItem rna_enum_layer_collection_mode_settings_type_items[]; extern EnumPropertyItem rna_enum_modifier_triangulate_quad_method_items[]; extern EnumPropertyItem rna_enum_modifier_triangulate_ngon_method_items[]; 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_context.c b/source/blender/makesrna/intern/rna_context.c index d7a679e9702..27e88f592ab 100644 --- a/source/blender/makesrna/intern/rna_context.c +++ b/source/blender/makesrna/intern/rna_context.c @@ -107,6 +107,26 @@ static PointerRNA rna_Context_scene_get(PointerRNA *ptr) return rna_pointer_inherit_refine(ptr, &RNA_Scene, CTX_data_scene(C)); } +static PointerRNA rna_Context_scene_layer_get(PointerRNA *ptr) +{ + bContext *C = (bContext *)ptr->data; + return rna_pointer_inherit_refine(ptr, &RNA_SceneLayer, CTX_data_scene_layer(C)); +} + +static PointerRNA rna_Context_scene_collection_get(PointerRNA *ptr) +{ + bContext *C = (bContext *)ptr->data; + ptr->id.data = CTX_data_scene(C); + return rna_pointer_inherit_refine(ptr, &RNA_SceneCollection, CTX_data_scene_collection(C)); +} + +static PointerRNA rna_Context_layer_collection_get(PointerRNA *ptr) +{ + bContext *C = (bContext *)ptr->data; + ptr->id.data = CTX_data_scene(C); + return rna_pointer_inherit_refine(ptr, &RNA_LayerCollection, CTX_data_layer_collection(C)); +} + static PointerRNA rna_Context_tool_settings_get(PointerRNA *ptr) { bContext *C = (bContext *)ptr->data; @@ -203,6 +223,21 @@ void RNA_def_context(BlenderRNA *brna) RNA_def_property_struct_type(prop, "Scene"); RNA_def_property_pointer_funcs(prop, "rna_Context_scene_get", NULL, NULL, NULL); + prop = RNA_def_property(srna, "render_layer", PROP_POINTER, PROP_NONE); + RNA_def_property_clear_flag(prop, PROP_EDITABLE); + RNA_def_property_struct_type(prop, "SceneLayer"); + RNA_def_property_pointer_funcs(prop, "rna_Context_scene_layer_get", NULL, NULL, NULL); + + prop = RNA_def_property(srna, "scene_collection", PROP_POINTER, PROP_NONE); + RNA_def_property_clear_flag(prop, PROP_EDITABLE); + RNA_def_property_struct_type(prop, "SceneCollection"); + RNA_def_property_pointer_funcs(prop, "rna_Context_scene_collection_get", NULL, NULL, NULL); + + prop = RNA_def_property(srna, "layer_collection", PROP_POINTER, PROP_NONE); + RNA_def_property_clear_flag(prop, PROP_EDITABLE); + RNA_def_property_struct_type(prop, "LayerCollection"); + RNA_def_property_pointer_funcs(prop, "rna_Context_layer_collection_get", NULL, NULL, NULL); + prop = RNA_def_property(srna, "tool_settings", PROP_POINTER, PROP_NONE); RNA_def_property_clear_flag(prop, PROP_EDITABLE); RNA_def_property_struct_type(prop, "ToolSettings"); diff --git a/source/blender/makesrna/intern/rna_group.c b/source/blender/makesrna/intern/rna_group.c index aa02a3c159d..2a5a0011279 100644 --- a/source/blender/makesrna/intern/rna_group.c +++ b/source/blender/makesrna/intern/rna_group.c @@ -53,9 +53,9 @@ static PointerRNA rna_Group_objects_get(CollectionPropertyIterator *iter) return rna_pointer_inherit_refine(&iter->parent, &RNA_Object, ((GroupObject *)internal->link)->ob); } -static void rna_Group_objects_link(Group *group, bContext *C, ReportList *reports, Object *object) +static void rna_Group_objects_link(Group *group, ReportList *reports, Object *object) { - if (!BKE_group_object_add(group, object, CTX_data_scene(C), NULL)) { + if (!BKE_group_object_add(group, object)) { BKE_reportf(reports, RPT_ERROR, "Object '%s' already in group '%s'", object->id.name + 2, group->id.name + 2); return; } @@ -63,9 +63,9 @@ static void rna_Group_objects_link(Group *group, bContext *C, ReportList *report WM_main_add_notifier(NC_OBJECT | ND_DRAW, &object->id); } -static void rna_Group_objects_unlink(Group *group, bContext *C, ReportList *reports, Object *object) +static void rna_Group_objects_unlink(Group *group, ReportList *reports, Object *object) { - if (!BKE_group_object_unlink(group, object, CTX_data_scene(C), NULL)) { + if (!BKE_group_object_unlink(group, object)) { BKE_reportf(reports, RPT_ERROR, "Object '%s' not in group '%s'", object->id.name + 2, group->id.name + 2); return; } @@ -91,7 +91,7 @@ static void rna_def_group_objects(BlenderRNA *brna, PropertyRNA *cprop) /* add object */ func = RNA_def_function(srna, "link", "rna_Group_objects_link"); - RNA_def_function_flag(func, FUNC_USE_CONTEXT | FUNC_USE_REPORTS); + RNA_def_function_flag(func, FUNC_USE_REPORTS); RNA_def_function_ui_description(func, "Add this object to a group"); /* object to add */ parm = RNA_def_pointer(func, "object", "Object", "", "Object to add"); @@ -100,7 +100,7 @@ static void rna_def_group_objects(BlenderRNA *brna, PropertyRNA *cprop) /* remove object */ func = RNA_def_function(srna, "unlink", "rna_Group_objects_unlink"); RNA_def_function_ui_description(func, "Remove this object to a group"); - RNA_def_function_flag(func, FUNC_USE_CONTEXT | FUNC_USE_REPORTS); + RNA_def_function_flag(func, FUNC_USE_REPORTS); /* object to remove */ parm = RNA_def_pointer(func, "object", "Object", "", "Object to remove"); RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); diff --git a/source/blender/makesrna/intern/rna_image_api.c b/source/blender/makesrna/intern/rna_image_api.c index 344c1781b46..bb927603e46 100644 --- a/source/blender/makesrna/intern/rna_image_api.c +++ b/source/blender/makesrna/intern/rna_image_api.c @@ -251,6 +251,8 @@ static int rna_Image_gl_load(Image *image, ReportList *reports, int frame, int f glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, (GLint)filter); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, (GLint)mag); + /* TODO(merwin): validate input (dimensions, filter, mag) before calling OpenGL + * instead of trusting input & testing for error after */ error = glGetError(); if (error) { diff --git a/source/blender/makesrna/intern/rna_internal.h b/source/blender/makesrna/intern/rna_internal.h index 76455adbc78..b904b65a37a 100644 --- a/source/blender/makesrna/intern/rna_internal.h +++ b/source/blender/makesrna/intern/rna_internal.h @@ -279,7 +279,7 @@ void RNA_api_material(StructRNA *srna); void RNA_api_mesh(struct StructRNA *srna); void RNA_api_meta(struct StructRNA *srna); void RNA_api_object(struct StructRNA *srna); -void RNA_api_object_base(struct StructRNA *srna); +void RNA_api_object_base_legacy(struct StructRNA *srna); void RNA_api_pose(struct StructRNA *srna); void RNA_api_pose_channel(struct StructRNA *srna); void RNA_api_scene(struct StructRNA *srna); diff --git a/source/blender/makesrna/intern/rna_main_api.c b/source/blender/makesrna/intern/rna_main_api.c index c110dbff6c4..244820f5a49 100644 --- a/source/blender/makesrna/intern/rna_main_api.c +++ b/source/blender/makesrna/intern/rna_main_api.c @@ -1587,6 +1587,7 @@ void RNA_def_main_particles(BlenderRNA *brna, PropertyRNA *cprop) RNA_def_property_clear_flag(prop, PROP_EDITABLE); RNA_def_property_boolean_funcs(prop, "rna_Main_particles_is_updated_get", NULL); } + void RNA_def_main_palettes(BlenderRNA *brna, PropertyRNA *cprop) { StructRNA *srna; 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_object.c b/source/blender/makesrna/intern/rna_object.c index 0cffba47f16..f8b3bdd62e9 100644 --- a/source/blender/makesrna/intern/rna_object.c +++ b/source/blender/makesrna/intern/rna_object.c @@ -297,23 +297,14 @@ static void rna_Object_dependency_update(Main *bmain, Scene *UNUSED(scene), Poin } /* when changing the selection flag the scene needs updating */ -static void rna_Object_select_update(Main *UNUSED(bmain), Scene *scene, PointerRNA *ptr) -{ - if (scene) { - Object *ob = (Object *)ptr->id.data; - short mode = (ob->flag & SELECT) ? BA_SELECT : BA_DESELECT; - ED_base_object_select(BKE_scene_base_find(scene, ob), mode); - } -} - static void rna_Base_select_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr) { - Base *base = (Base *)ptr->data; - short mode = (base->flag & BA_SELECT) ? BA_SELECT : BA_DESELECT; + BaseLegacy *base = (BaseLegacy *)ptr->data; + short mode = (base->flag_legacy & BA_SELECT) ? BA_SELECT : BA_DESELECT; ED_base_object_select(base, mode); } -static void rna_Object_layer_update__internal(Main *bmain, Scene *scene, Base *base, Object *ob) +static void rna_Object_layer_update__internal(Main *bmain, Scene *scene, BaseLegacy *base, Object *ob) { /* try to avoid scene sort */ if (scene == NULL) { @@ -335,7 +326,7 @@ static void rna_Object_layer_update__internal(Main *bmain, Scene *scene, Base *b static void rna_Object_layer_update(Main *bmain, Scene *scene, PointerRNA *ptr) { Object *ob = (Object *)ptr->id.data; - Base *base; + BaseLegacy *base; base = scene ? BKE_scene_base_find(scene, ob) : NULL; if (!base) @@ -351,7 +342,7 @@ static void rna_Object_layer_update(Main *bmain, Scene *scene, PointerRNA *ptr) static void rna_Base_layer_update(Main *bmain, Scene *scene, PointerRNA *ptr) { - Base *base = (Base *)ptr->data; + BaseLegacy *base = (BaseLegacy *)ptr->data; Object *ob = (Object *)base->object; rna_Object_layer_update__internal(bmain, scene, base, ob); @@ -1120,7 +1111,7 @@ static void rna_Object_layer_set(PointerRNA *ptr, const int *values) static void rna_Base_layer_set(PointerRNA *ptr, const int *values) { - Base *base = (Base *)ptr->data; + BaseLegacy *base = (BaseLegacy *)ptr->data; unsigned int lay; lay = rna_Object_layer_validate__internal(values, base->lay); @@ -2246,11 +2237,6 @@ static void rna_def_object(BlenderRNA *brna) RNA_def_property_clear_flag(prop, PROP_EDITABLE); RNA_def_property_ui_text(prop, "Local View Layers", "3D local view layers the object is on"); - prop = RNA_def_property(srna, "select", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_sdna(prop, NULL, "flag", SELECT); - RNA_def_property_ui_text(prop, "Select", "Object selection state"); - RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, "rna_Object_select_update"); - /* for data access */ prop = RNA_def_property(srna, "bound_box", PROP_FLOAT, PROP_NONE); RNA_def_property_multi_array(prop, 2, boundbox_dimsize); @@ -2895,14 +2881,14 @@ static void rna_def_dupli_object(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Dupli Type", "Duplicator type that generated this dupli object"); } -static void rna_def_object_base(BlenderRNA *brna) +static void rna_def_object_base_legacy(BlenderRNA *brna) { StructRNA *srna; PropertyRNA *prop; - srna = RNA_def_struct(brna, "ObjectBase", NULL); + srna = RNA_def_struct(brna, "ObjectBaseLegacy", NULL); RNA_def_struct_sdna(srna, "Base"); - RNA_def_struct_ui_text(srna, "Object Base", "An object instance in a scene"); + RNA_def_struct_ui_text(srna, "Object Base Legacy", "An object instance in a scene (deprecated)"); RNA_def_struct_ui_icon(srna, ICON_OBJECT_DATA); prop = RNA_def_property(srna, "object", PROP_POINTER, PROP_NONE); @@ -2922,13 +2908,13 @@ static void rna_def_object_base(BlenderRNA *brna) RNA_def_property_array(prop, 8); RNA_def_property_clear_flag(prop, PROP_EDITABLE); RNA_def_property_ui_text(prop, "Local View Layers", "3D local view layers the object base is on"); - + prop = RNA_def_property(srna, "select", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_sdna(prop, NULL, "flag", BA_SELECT); + RNA_def_property_boolean_sdna(prop, NULL, "flag_legacy", BA_SELECT); RNA_def_property_ui_text(prop, "Select", "Object base selection state"); RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, "rna_Base_select_update"); - - RNA_api_object_base(srna); + + RNA_api_object_base_legacy(srna); } void RNA_def_object(BlenderRNA *brna) @@ -2937,7 +2923,7 @@ void RNA_def_object(BlenderRNA *brna) RNA_define_animate_sdna(false); rna_def_object_game_settings(brna); - rna_def_object_base(brna); + rna_def_object_base_legacy(brna); rna_def_vertex_group(brna); rna_def_material_slot(brna); rna_def_dupli_object(brna); diff --git a/source/blender/makesrna/intern/rna_object_api.c b/source/blender/makesrna/intern/rna_object_api.c index c680abe71a4..0390ba04223 100644 --- a/source/blender/makesrna/intern/rna_object_api.c +++ b/source/blender/makesrna/intern/rna_object_api.c @@ -40,10 +40,12 @@ #include "RNA_define.h" #include "DNA_constraint_types.h" +#include "DNA_layer_types.h" #include "DNA_modifier_types.h" #include "DNA_object_types.h" #include "BKE_depsgraph.h" +#include "BKE_layer.h" #include "rna_internal.h" /* own include */ @@ -90,6 +92,62 @@ static EnumPropertyItem space_items[] = { #include "DEG_depsgraph.h" +static void rna_Object_select_set(Object *ob, bContext *C, ReportList *reports, int action) +{ + SceneLayer *sl = CTX_data_scene_layer(C); + Base *base = BKE_scene_layer_base_find(sl, ob); + + if (!base) { + BKE_reportf(reports, RPT_ERROR, "Object '%s' not in Render Layer '%s'!", ob->id.name + 2, sl->name); + return; + } + + if (action == 2) { /* TOGGLE */ + if ((base->flag & BASE_SELECTED) != 0) { + action = 1; /* DESELECT */ + } + else { + action = 0; /* SELECT */ + } + } + + switch (action) { + case 1: /* DESELECT */ + base->flag &= ~BASE_SELECTED; + break; + case 0: /* SELECT */ + default: + BKE_scene_layer_base_select(sl, base); + break; + } +} + +static int rna_Object_select_get(Object *ob, bContext *C, ReportList *reports) +{ + SceneLayer *sl = CTX_data_scene_layer(C); + Base *base = BKE_scene_layer_base_find(sl, ob); + + if (!base) { + BKE_reportf(reports, RPT_ERROR, "Object '%s' not in Render Layer '%s'!", ob->id.name + 2, sl->name); + return -1; + } + + return ((base->flag & BASE_SELECTED) != 0) ? 1 : 0; +} + +static int rna_Object_visible_get(Object *ob, bContext *C, ReportList *reports) +{ + SceneLayer *sl = CTX_data_scene_layer(C); + Base *base = BKE_scene_layer_base_find(sl, ob); + + if (!base) { + BKE_reportf(reports, RPT_ERROR, "Object '%s' not in Render Layer '%s'!", ob->id.name + 2, sl->name); + return -1; + } + + return ((base->flag & BASE_VISIBLED) != 0) ? 1 : 0; +} + /* Convert a given matrix from a space to another (using the object and/or a bone as reference). */ static void rna_Scene_mat_convert_space(Object *ob, ReportList *reports, bPoseChannel *pchan, float *mat, float *mat_ret, int from, int to) @@ -413,9 +471,9 @@ finally: free_bvhtree_from_mesh(&treeData); } -/* ObjectBase */ +/* ObjectBaseLegacy */ -static void rna_ObjectBase_layers_from_view(Base *base, View3D *v3d) +static void rna_ObjectBaseLegacy_layers_from_view(BaseLegacy *base, View3D *v3d) { base->lay = base->object->lay = v3d->lay; } @@ -504,6 +562,32 @@ void RNA_api_object(StructRNA *srna) }; #endif + static EnumPropertyItem object_select_items[] = { + {0, "SELECT", 0, "Select", "Select object from the active render layer"}, + {1, "DESELECT", 0, "Deselect", "Deselect object from the active render layer"}, + {2, "TOGGLE", 0, "Toggle", "Toggle object selection from the active render layer"}, + {0, NULL, 0, NULL, NULL} + }; + + /* Special wrapper to access the base selection value */ + func = RNA_def_function(srna, "select_set", "rna_Object_select_set"); + RNA_def_function_ui_description(func, "Select the object (for the active render layer)"); + RNA_def_function_flag(func, FUNC_USE_CONTEXT | FUNC_USE_REPORTS); + parm = RNA_def_enum(func, "action", object_select_items, 0, "Action", "Select mode"); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); + + func = RNA_def_function(srna, "select_get", "rna_Object_select_get"); + RNA_def_function_ui_description(func, "Get the object selection for the active render layer"); + RNA_def_function_flag(func, FUNC_USE_CONTEXT | FUNC_USE_REPORTS); + parm = RNA_def_boolean(func, "result", 0, "", "Object selected"); + RNA_def_function_return(func, parm); + + func = RNA_def_function(srna, "visible_get", "rna_Object_visible_get"); + RNA_def_function_ui_description(func, "Get the object visibility for the active render layer"); + RNA_def_function_flag(func, FUNC_USE_CONTEXT | FUNC_USE_REPORTS); + parm = RNA_def_boolean(func, "result", 0, "", "Object visible"); + RNA_def_function_return(func, parm); + /* Matrix space conversion */ func = RNA_def_function(srna, "convert_space", "rna_Scene_mat_convert_space"); RNA_def_function_ui_description(func, "Convert (transform) the given matrix from one space to another"); @@ -707,12 +791,12 @@ void RNA_api_object(StructRNA *srna) } -void RNA_api_object_base(StructRNA *srna) +void RNA_api_object_base_legacy(StructRNA *srna) { FunctionRNA *func; PropertyRNA *parm; - func = RNA_def_function(srna, "layers_from_view", "rna_ObjectBase_layers_from_view"); + func = RNA_def_function(srna, "layers_from_view", "rna_ObjectBaseLegacy_layers_from_view"); RNA_def_function_ui_description(func, "Sets the object layers from a 3D View (use when adding an object in local view)"); parm = RNA_def_pointer(func, "view", "SpaceView3D", "", ""); diff --git a/source/blender/makesrna/intern/rna_object_force.c b/source/blender/makesrna/intern/rna_object_force.c index 1d89f7535c4..5fd4762e5be 100644 --- a/source/blender/makesrna/intern/rna_object_force.c +++ b/source/blender/makesrna/intern/rna_object_force.c @@ -605,7 +605,7 @@ static void rna_EffectorWeight_update(Main *UNUSED(bmain), Scene *UNUSED(scene), if (id && GS(id->name) == ID_SCE) { Scene *scene = (Scene *)id; - Base *base; + BaseLegacy *base; for (base = scene->base.first; base; base = base->next) { BKE_ptcache_object_reset(scene, base->object, PTCACHE_RESET_DEPSGRAPH); 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 8ee49045bc5..211063fa03b 100644 --- a/source/blender/makesrna/intern/rna_scene.c +++ b/source/blender/makesrna/intern/rna_scene.c @@ -32,6 +32,7 @@ #include "DNA_particle_types.h" #include "DNA_rigidbody_types.h" #include "DNA_scene_types.h" +#include "DNA_layer_types.h" #include "DNA_linestyle_types.h" #include "DNA_userdef_types.h" #include "DNA_world_types.h" @@ -47,8 +48,12 @@ #include "BKE_editmesh.h" #include "BKE_paint.h" +#include "ED_object.h" + #include "GPU_extensions.h" +#include "DRW_engine.h" + #include "RNA_define.h" #include "RNA_enum_types.h" @@ -77,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", ""}, @@ -431,6 +438,12 @@ EnumPropertyItem rna_enum_gpencil_interpolation_mode_items[] = { {0, NULL, 0, NULL, NULL} }; +EnumPropertyItem rna_enum_layer_collection_mode_settings_type_items[] = { + {COLLECTION_MODE_OBJECT, "OBJECT", 0, "Object", ""}, + {COLLECTION_MODE_EDIT, "EDIT", 0, "Edit", ""}, + {0, NULL, 0, NULL, NULL} +}; + #ifdef RNA_RUNTIME #include "DNA_anim_types.h" @@ -445,10 +458,12 @@ EnumPropertyItem rna_enum_gpencil_interpolation_mode_items[] = { #include "MEM_guardedalloc.h" #include "BKE_brush.h" +#include "BKE_collection.h" #include "BKE_colortools.h" #include "BKE_context.h" #include "BKE_global.h" #include "BKE_image.h" +#include "BKE_layer.h" #include "BKE_main.h" #include "BKE_node.h" #include "BKE_pointcache.h" @@ -606,11 +621,11 @@ static void rna_SpaceImageEditor_uv_sculpt_update(Main *bmain, Scene *scene, Poi static int rna_Scene_object_bases_lookup_string(PointerRNA *ptr, const char *key, PointerRNA *r_ptr) { Scene *scene = (Scene *)ptr->data; - Base *base; + BaseLegacy *base; for (base = scene->base.first; base; base = base->next) { if (STREQLEN(base->object->id.name + 2, key, sizeof(base->object->id.name) - 2)) { - *r_ptr = rna_pointer_inherit_refine(ptr, &RNA_ObjectBase, base); + *r_ptr = rna_pointer_inherit_refine(ptr, &RNA_ObjectBaseLegacy, base); return true; } } @@ -623,13 +638,13 @@ static PointerRNA rna_Scene_objects_get(CollectionPropertyIterator *iter) ListBaseIterator *internal = &iter->internal.listbase; /* we are actually iterating a Base list, so override get */ - return rna_pointer_inherit_refine(&iter->parent, &RNA_Object, ((Base *)internal->link)->object); + return rna_pointer_inherit_refine(&iter->parent, &RNA_Object, ((BaseLegacy *)internal->link)->object); } -static Base *rna_Scene_object_link(Scene *scene, bContext *C, ReportList *reports, Object *ob) +static BaseLegacy *rna_Scene_object_link(Scene *scene, bContext *C, ReportList *reports, Object *ob) { Scene *scene_act = CTX_data_scene(C); - Base *base; + BaseLegacy *base; if (BKE_scene_base_find(scene, ob)) { BKE_reportf(reports, RPT_ERROR, "Object '%s' is already in scene '%s'", ob->id.name + 2, scene->id.name + 2); @@ -660,7 +675,7 @@ static Base *rna_Scene_object_link(Scene *scene, bContext *C, ReportList *report static void rna_Scene_object_unlink(Scene *scene, ReportList *reports, Object *ob) { - Base *base = BKE_scene_base_find(scene, ob); + BaseLegacy *base = BKE_scene_base_find(scene, ob); if (!base) { BKE_reportf(reports, RPT_ERROR, "Object '%s' is not in this scene '%s'", ob->id.name + 2, scene->id.name + 2); return; @@ -1728,7 +1743,7 @@ static void rna_Scene_use_nodes_update(bContext *C, PointerRNA *ptr) static void rna_Physics_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr) { Scene *scene = (Scene *)ptr->id.data; - Base *base; + BaseLegacy *base; for (base = scene->base.first; base; base = base->next) BKE_ptcache_object_reset(scene, base->object, PTCACHE_RESET_DEPSGRAPH); @@ -1799,7 +1814,7 @@ static void rna_Scene_use_simplify_update(Main *bmain, Scene *UNUSED(scene), Poi { Scene *sce = ptr->id.data; Scene *sce_iter; - Base *base; + BaseLegacy *base; BKE_main_id_tag_listbase(&bmain->object, LIB_TAG_DOIT, true); for (SETLOOPER(sce, sce_iter, base)) @@ -1888,6 +1903,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"); @@ -2206,6 +2258,608 @@ static int rna_gpu_is_hq_supported_get(PointerRNA *UNUSED(ptr)) return GPU_instanced_drawing_support() && GPU_geometry_shader_support(); } +static void rna_SceneCollection_name_set(PointerRNA *ptr, const char *value) +{ + Scene *scene = (Scene *)ptr->id.data; + SceneCollection *sc = (SceneCollection *)ptr->data; + SceneCollection *sc_master = BKE_collection_master(scene); + + BLI_strncpy_utf8(sc->name, value, sizeof(sc->name)); + BLI_uniquename(&sc_master->scene_collections, sc, DATA_("SceneCollection"), '.', offsetof(SceneCollection, name), sizeof(sc->name)); +} + +static void rna_SceneCollection_filter_set(PointerRNA *ptr, const char *value) +{ + Scene *scene = (Scene *)ptr->id.data; + SceneCollection *sc = (SceneCollection *)ptr->data; + BLI_strncpy_utf8(sc->filter, value, sizeof(sc->filter)); + + TODO_LAYER_SYNC_FILTER; + (void)scene; +} + +static PointerRNA rna_SceneCollection_objects_get(CollectionPropertyIterator *iter) +{ + ListBaseIterator *internal = &iter->internal.listbase; + + /* we are actually iterating a LinkData list, so override get */ + return rna_pointer_inherit_refine(&iter->parent, &RNA_Object, ((LinkData *)internal->link)->data); +} + +static SceneCollection *rna_SceneCollection_new(ID *id, SceneCollection *sc_parent, const char *name) +{ + Scene *scene = (Scene *)id; + SceneCollection *sc = BKE_collection_add(scene, sc_parent, name); + + DAG_id_tag_update(&scene->id, 0); + WM_main_add_notifier(NC_SCENE | ND_LAYER, NULL); + + return sc; +} + +static void rna_SceneCollection_remove( + ID *id, SceneCollection *sc_parent, ReportList *reports, PointerRNA *sc_ptr) +{ + Scene *scene = (Scene *)id; + SceneCollection *sc = sc_ptr->data; + + const int index = BLI_findindex(&sc_parent->scene_collections, sc); + if (index == -1) { + BKE_reportf(reports, RPT_ERROR, "Collection '%s' is not a sub-collection of '%s'", + sc->name, sc_parent->name); + return; + } + + if (!BKE_collection_remove(scene, sc)) { + BKE_reportf(reports, RPT_ERROR, "Collection '%s' could not be removed from collection '%s'", + sc->name, sc_parent->name); + return; + } + + RNA_POINTER_INVALIDATE(sc_ptr); + + DAG_id_tag_update(&scene->id, 0); + WM_main_add_notifier(NC_SCENE | ND_LAYER, NULL); +} + +static int rna_SceneCollection_objects_active_index_get(PointerRNA *ptr) +{ + SceneCollection *sc = (SceneCollection *)ptr->data; + return sc->active_object_index; +} + +static void rna_SceneCollection_objects_active_index_set(PointerRNA *ptr, int value) +{ + SceneCollection *sc = (SceneCollection *)ptr->data; + sc->active_object_index = value; +} + +static void rna_SceneCollection_objects_active_index_range( + PointerRNA *ptr, int *min, int *max, int *UNUSED(softmin), int *UNUSED(softmax)) +{ + SceneCollection *sc = (SceneCollection *)ptr->data; + *min = 0; + *max = max_ii(0, BLI_listbase_count(&sc->objects) - 1); +} + +void rna_SceneCollection_object_link( + ID *id, SceneCollection *sc, Main *bmain, ReportList *reports, Object *ob) +{ + Scene *scene = (Scene *)id; + + if (BLI_findptr(&sc->objects, ob, offsetof(LinkData, data))) { + BKE_reportf(reports, RPT_ERROR, "Object '%s' is already in collection '%s'", ob->id.name + 2, sc->name); + return; + } + + BKE_collection_object_add(scene, sc, ob); + + /* TODO(sergey): Only update relations for the current scene. */ + DAG_relations_tag_update(bmain); + DAG_id_tag_update(&ob->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME); + + WM_main_add_notifier(NC_SCENE | ND_LAYER | ND_OB_ACTIVE, scene); +} + +static void rna_SceneCollection_object_unlink( + ID *id, SceneCollection *sc, Main *bmain, ReportList *reports, Object *ob) +{ + Scene *scene = (Scene *)id; + + if (!BLI_findptr(&sc->objects, ob, offsetof(LinkData, data))) { + BKE_reportf(reports, RPT_ERROR, "Object '%s' is not in collection '%s'", ob->id.name + 2, sc->name); + return; + } + + BKE_collection_object_remove(bmain, scene, sc, ob, false); + + /* needed otherwise the depgraph will contain freed objects which can crash, see [#20958] */ + DAG_relations_tag_update(bmain); + + 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; +} + +static StructRNA *rna_CollectionModeSettings_refine(struct PointerRNA *ptr) +{ + CollectionEngineSettings *ces = (CollectionEngineSettings *)ptr->data; + + switch(ces->type) { + case COLLECTION_MODE_OBJECT: + return &RNA_CollectionModeSettingsObject; + break; + case COLLECTION_MODE_EDIT: + return &RNA_CollectionModeSettingsEdit; + break; + } + + return &RNA_CollectionModeSettings; +} + +/****** clay engine settings *******/ + +#define RNA_LAYER_ENGINE_USE_GET_SET(_ENGINE_, _NAME_) \ + static int rna_LayerEngineSettings_##_ENGINE_##_##_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_##_ENGINE_##_##_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_, _ENGINE_, _MODE_, _NAME_) \ +static _TYPE_ rna_LayerEngineSettings_##_ENGINE_##_##_NAME_##_get(PointerRNA *ptr) \ +{ \ + CollectionEngineSettings *ces = (CollectionEngineSettings *)ptr->data; \ + return BKE_collection_engine_property_value_get_##_TYPE_(ces, #_NAME_); \ +} \ + \ +static void rna_LayerEngineSettings_##_ENGINE_##_##_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(_ENGINE_, _NAME_) + +#define RNA_LAYER_ENGINE_CLAY_GET_SET_FLOAT(_NAME_) \ + RNA_LAYER_ENGINE_GET_SET(float, Clay, COLLECTION_MODE_NONE, _NAME_) + +#define RNA_LAYER_ENGINE_CLAY_GET_SET_INT(_NAME_) \ + RNA_LAYER_ENGINE_GET_SET(int, Clay, COLLECTION_MODE_NONE, _NAME_) + +#define RNA_LAYER_ENGINE_CLAY_GET_SET_BOOL(_NAME_) \ + RNA_LAYER_ENGINE_GET_SET(bool, Clay, COLLECTION_MODE_NONE, _NAME_) + +/* mode engines */ + +#define RNA_LAYER_MODE_OBJECT_GET_SET_FLOAT(_NAME_) \ + RNA_LAYER_ENGINE_GET_SET(float, ObjectMode, COLLECTION_MODE_OBJECT, _NAME_) + +#define RNA_LAYER_MODE_OBJECT_GET_SET_INT(_NAME_) \ + RNA_LAYER_ENGINE_GET_SET(int, ObjectMode, COLLECTION_MODE_OBJECT, _NAME_) + +#define RNA_LAYER_MODE_OBJECT_GET_SET_BOOL(_NAME_) \ + RNA_LAYER_ENGINE_GET_SET(bool, ObjectMode, COLLECTION_MODE_OBJECT, _NAME_) + +#define RNA_LAYER_MODE_EDIT_GET_SET_FLOAT(_NAME_) \ + RNA_LAYER_ENGINE_GET_SET(float, EditMode, COLLECTION_MODE_EDIT, _NAME_) + +#define RNA_LAYER_MODE_EDIT_GET_SET_INT(_NAME_) \ + RNA_LAYER_ENGINE_GET_SET(int, EditMode, COLLECTION_MODE_EDIT, _NAME_) + +#define RNA_LAYER_MODE_EDIT_GET_SET_BOOL(_NAME_) \ + RNA_LAYER_ENGINE_GET_SET(bool, EditMode, COLLECTION_MODE_EDIT, _NAME_) + +/* clay engine */ +RNA_LAYER_ENGINE_CLAY_GET_SET_INT(type) +RNA_LAYER_ENGINE_CLAY_GET_SET_INT(matcap_icon) +RNA_LAYER_ENGINE_CLAY_GET_SET_FLOAT(matcap_rotation) +RNA_LAYER_ENGINE_CLAY_GET_SET_FLOAT(matcap_hue) +RNA_LAYER_ENGINE_CLAY_GET_SET_FLOAT(matcap_saturation) +RNA_LAYER_ENGINE_CLAY_GET_SET_FLOAT(matcap_value) +RNA_LAYER_ENGINE_CLAY_GET_SET_FLOAT(ssao_factor_cavity) +RNA_LAYER_ENGINE_CLAY_GET_SET_FLOAT(ssao_factor_edge) +RNA_LAYER_ENGINE_CLAY_GET_SET_FLOAT(ssao_distance) +RNA_LAYER_ENGINE_CLAY_GET_SET_FLOAT(ssao_attenuation) + +/* object engine */ +RNA_LAYER_MODE_OBJECT_GET_SET_BOOL(show_wire) +RNA_LAYER_MODE_OBJECT_GET_SET_BOOL(show_backface_culling) + +/* mesh engine */ +RNA_LAYER_MODE_EDIT_GET_SET_BOOL(show_occlude_wire) + +#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); + LayerCollection *lc = CTX_data_layer_collection(C); + BKE_scene_layer_engine_settings_collection_recalculate(sl, lc); +} + +/***********************************/ + +static void rna_LayerCollection_name_get(PointerRNA *ptr, char *value) +{ + SceneCollection *sc = ((LayerCollection *)ptr->data)->scene_collection; + strcpy(value, sc->name); +} + +static int rna_LayerCollection_name_length(PointerRNA *ptr) +{ + SceneCollection *sc = ((LayerCollection *)ptr->data)->scene_collection; + return strnlen(sc->name, sizeof(sc->name)); +} + +static void rna_LayerCollection_name_set(PointerRNA *ptr, const char *value) +{ + Scene *scene = (Scene *)ptr->id.data; + SceneCollection *sc = ((LayerCollection *)ptr->data)->scene_collection; + SceneCollection *sc_master = BKE_collection_master(scene); + + BLI_strncpy_utf8(sc->name, value, sizeof(sc->name)); + BLI_uniquename(&sc_master->scene_collections, sc, DATA_("SceneCollection"), '.', offsetof(SceneCollection, name), sizeof(sc->name)); +} + +static PointerRNA rna_LayerCollection_objects_get(CollectionPropertyIterator *iter) +{ + ListBaseIterator *internal = &iter->internal.listbase; + Base *base = ((LinkData *)internal->link)->data; + 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, COLLECTION_MODE_NONE, engine_name); + RNA_pointer_create(NULL, &RNA_CollectionEngineSettings, ces, &ptr); + return rna_pointer_inherit_refine(&ptr, &RNA_CollectionEngineSettings, ces); +} + +static PointerRNA rna_LayerCollection_mode_settings_get(ID *UNUSED(id), LayerCollection *lc, bContext *C, int type) +{ + if (type == COLLECTION_MODE_NONE) { + /* temporarily get mode from active object */ + Object *ob = CTX_data_active_object(C); + + if (ob) { + switch (ob->mode) { + case OB_MODE_OBJECT: + type = COLLECTION_MODE_OBJECT; + break; + case OB_MODE_EDIT: + type = COLLECTION_MODE_EDIT; + break; + } + } + } + + PointerRNA ptr; + CollectionEngineSettings *ces = BKE_layer_collection_engine_get(lc, type, ""); + RNA_pointer_create(NULL, &RNA_CollectionEngineSettings, ces, &ptr); + return rna_pointer_inherit_refine(&ptr, &RNA_CollectionModeSettings, ces); +} + +static void rna_LayerCollection_hide_update(bContext *C, PointerRNA *ptr) +{ + Scene *scene = CTX_data_scene(C); + LayerCollection *lc = ptr->data; + SceneLayer *sl = BKE_scene_layer_find_from_collection(scene, lc); + + /* hide and deselect bases that are directly influenced by this LayerCollection */ + BKE_scene_layer_base_flag_recalculate(sl); + BKE_scene_layer_engine_settings_collection_recalculate(sl, lc); + WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene); +} + +static void rna_LayerCollection_hide_select_update(bContext *C, PointerRNA *ptr) +{ + LayerCollection *lc = ptr->data; + + if ((lc->flag & COLLECTION_SELECTABLE) == 0) { + Scene *scene = CTX_data_scene(C); + SceneLayer *sl = BKE_scene_layer_find_from_collection(scene, lc); + + /* deselect bases that are directly influenced by this LayerCollection */ + BKE_scene_layer_base_flag_recalculate(sl); + WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, CTX_data_scene(C)); + } +} + +static int rna_LayerCollections_active_collection_index_get(PointerRNA *ptr) +{ + SceneLayer *sl = (SceneLayer *)ptr->data; + return sl->active_collection; +} + +static void rna_LayerCollections_active_collection_index_set(PointerRNA *ptr, int value) +{ + SceneLayer *sl = (SceneLayer *)ptr->data; + int num_collections = BKE_layer_collection_count(sl); + sl->active_collection = min_ff(value, num_collections - 1); +} + +static void rna_LayerCollections_active_collection_index_range( + PointerRNA *ptr, int *min, int *max, int *UNUSED(softmin), int *UNUSED(softmax)) +{ + SceneLayer *sl = (SceneLayer *)ptr->data; + *min = 0; + *max = max_ii(0, BKE_layer_collection_count(sl) - 1); +} + +static PointerRNA rna_LayerCollections_active_collection_get(PointerRNA *ptr) +{ + SceneLayer *sl = (SceneLayer *)ptr->data; + LayerCollection *lc = BKE_layer_collection_active(sl); + return rna_pointer_inherit_refine(ptr, &RNA_LayerCollection, lc); +} + +static void rna_LayerCollections_active_collection_set(PointerRNA *ptr, PointerRNA value) +{ + SceneLayer *sl = (SceneLayer *)ptr->data; + LayerCollection *lc = (LayerCollection *)value.data; + const int index = BKE_layer_collection_findindex(sl, lc); + if (index != -1) sl->active_collection = index; +} + +LayerCollection * rna_SceneLayer_collection_link( + ID *id, SceneLayer *sl, Main *bmain, SceneCollection *sc) +{ + Scene *scene = (Scene *)id; + LayerCollection *lc = BKE_collection_link(sl, sc); + + /* TODO(sergey/dfelinto): Only update relations for the current scenelayer. */ + DAG_relations_tag_update(bmain); + WM_main_add_notifier(NC_SCENE | ND_LAYER, scene); + + return lc; +} + +static void rna_SceneLayer_collection_unlink( + ID *id, SceneLayer *sl, Main *bmain, ReportList *reports, LayerCollection *lc) +{ + Scene *scene = (Scene *)id; + + if (BLI_findindex(&sl->layer_collections, lc) == -1) { + BKE_reportf(reports, RPT_ERROR, "Layer collection '%s' is not in '%s'", lc->scene_collection->name, sl->name); + return; + } + + BKE_collection_unlink(sl, lc); + + /* needed otherwise the depgraph will contain freed objects which can crash, see [#20958] */ + /* TODO(sergey/dfelinto): Only update relations for the current scenelayer. */ + DAG_relations_tag_update(bmain); + + WM_main_add_notifier(NC_SCENE | ND_LAYER | ND_OB_ACTIVE, scene); +} + +static PointerRNA rna_LayerObjects_active_object_get(PointerRNA *ptr) +{ + SceneLayer *sl = (SceneLayer *)ptr->data; + return rna_pointer_inherit_refine(ptr, &RNA_Object, sl->basact ? sl->basact->object : NULL); +} + +static void rna_LayerObjects_active_object_set(PointerRNA *ptr, PointerRNA value) +{ + SceneLayer *sl = (SceneLayer *)ptr->data; + if (value.data) + sl->basact = BKE_scene_layer_base_find(sl, (Object *)value.data); + else + sl->basact = NULL; +} + +static void rna_SceneLayer_name_set(PointerRNA *ptr, const char *value) +{ + Scene *scene = (Scene *)ptr->id.data; + SceneLayer *sl = (SceneLayer *)ptr->data; + char oldname[sizeof(sl->name)]; + + BLI_strncpy(oldname, sl->name, sizeof(sl->name)); + + BLI_strncpy_utf8(sl->name, value, sizeof(sl->name)); + BLI_uniquename(&scene->render_layers, sl, DATA_("SceneLayer"), '.', offsetof(SceneLayer, name), sizeof(sl->name)); + + if (scene->nodetree) { + bNode *node; + int index = BLI_findindex(&scene->render_layers, sl); + + for (node = scene->nodetree->nodes.first; node; node = node->next) { + if (node->type == CMP_NODE_R_LAYERS && node->id == NULL) { + if (node->custom1 == index) + BLI_strncpy(node->name, sl->name, NODE_MAXSTR); + } + } + } +} + +static PointerRNA rna_SceneLayer_objects_get(CollectionPropertyIterator *iter) +{ + ListBaseIterator *internal = &iter->internal.listbase; + + /* we are actually iterating a ObjectBase list, so override get */ + Base *base = (Base *)internal->link; + return rna_pointer_inherit_refine(&iter->parent, &RNA_Object, base->object); +} + +static int rna_SceneLayer_objects_selected_skip(CollectionPropertyIterator *iter, void *UNUSED(data)) +{ + ListBaseIterator *internal = &iter->internal.listbase; + Base *base = (Base *)internal->link; + + if ((base->flag & BASE_SELECTED) != 0) { + return 0; + } + + return 1; +}; + +static void rna_LayerObjects_selected_begin(CollectionPropertyIterator *iter, PointerRNA *ptr) +{ + SceneLayer *sl = (SceneLayer *)ptr->data; + rna_iterator_listbase_begin(iter, &sl->object_bases, rna_SceneLayer_objects_selected_skip); +} + +static void rna_SceneLayer_engine_set(PointerRNA *ptr, int value) +{ + SceneLayer *sl = (SceneLayer *)ptr->data; + RenderEngineType *type = BLI_findlink(&R_engines, value); + + if (type) + BKE_scene_layer_engine_set(sl, type->idname); +} + +static EnumPropertyItem *rna_SceneLayer_engine_itemf( + bContext *UNUSED(C), PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), bool *r_free) +{ + RenderEngineType *type; + EnumPropertyItem *item = NULL; + EnumPropertyItem tmp = {0, "", 0, "", ""}; + int a = 0, totitem = 0; + + for (type = R_engines.first; type; type = type->next, a++) { + tmp.value = a; + tmp.identifier = type->idname; + tmp.name = type->name; + RNA_enum_item_add(&item, &totitem, &tmp); + } + + RNA_enum_item_end(&item, &totitem); + *r_free = true; + + return item; +} + +static int rna_SceneLayer_engine_get(PointerRNA *ptr) +{ + SceneLayer *sl = (SceneLayer *)ptr->data; + RenderEngineType *type; + int a = 0; + + for (type = R_engines.first; type; type = type->next, a++) + if (STREQ(type->idname, sl->engine)) + return a; + + return 0; +} + +static void rna_SceneLayer_engine_update(Main *bmain, Scene *UNUSED(unused), PointerRNA *UNUSED(ptr)) +{ + ED_render_engine_changed(bmain); +} + +static int rna_SceneLayer_multiple_engines_get(PointerRNA *UNUSED(ptr)) +{ + return (BLI_listbase_count(&R_engines) > 1); +} + +static int rna_SceneLayer_active_layer_index_get(PointerRNA *ptr) +{ + Scene *scene = (Scene *)ptr->data; + return scene->active_layer; +} + +static void rna_SceneLayer_active_layer_index_set(PointerRNA *ptr, int value) +{ + Scene *scene = (Scene *)ptr->data; + int num_layers = BLI_listbase_count(&scene->render_layers); + scene->active_layer = min_ff(value, num_layers - 1); +} + +static void rna_SceneLayer_active_layer_index_range( + PointerRNA *ptr, int *min, int *max, int *UNUSED(softmin), int *UNUSED(softmax)) +{ + Scene *scene = (Scene *)ptr->data; + + *min = 0; + *max = max_ii(0, BLI_listbase_count(&scene->render_layers) - 1); +} + +static PointerRNA rna_SceneLayer_active_layer_get(PointerRNA *ptr) +{ + Scene *scene = (Scene *)ptr->data; + SceneLayer *sl = BLI_findlink(&scene->render_layers, scene->active_layer); + + return rna_pointer_inherit_refine(ptr, &RNA_SceneLayer, sl); +} + +static void rna_SceneLayer_active_layer_set(PointerRNA *ptr, PointerRNA value) +{ + Scene *scene = (Scene *)ptr->data; + SceneLayer *sl = (SceneLayer *)value.data; + const int index = BLI_findindex(&scene->render_layers, sl); + if (index != -1) scene->active_layer = index; +} + +static SceneLayer *rna_SceneLayer_new(ID *id, Scene *UNUSED(sce), const char *name) +{ + Scene *scene = (Scene *)id; + SceneLayer *sl = BKE_scene_layer_add(scene, name); + + DAG_id_tag_update(&scene->id, 0); + WM_main_add_notifier(NC_SCENE | ND_LAYER, NULL); + + return sl; +} + +static void rna_SceneLayer_remove( + ID *id, Scene *UNUSED(sce), Main *bmain, ReportList *reports, PointerRNA *sl_ptr) +{ + Scene *scene = (Scene *)id; + SceneLayer *sl = sl_ptr->data; + + if (!BKE_scene_layer_remove(bmain, scene, sl)) { + BKE_reportf(reports, RPT_ERROR, "Render layer '%s' could not be removed from scene '%s'", + sl->name, scene->id.name + 2); + return; + } + + RNA_POINTER_INVALIDATE(sl_ptr); + + DAG_id_tag_update(&scene->id, 0); + WM_main_add_notifier(NC_SCENE | ND_LAYER, NULL); +} + +static void rna_ObjectBase_select_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr) +{ + Base *base = (Base *)ptr->data; + short mode = (base->flag & BASE_SELECTED) ? BA_SELECT : BA_DESELECT; + ED_object_base_select(base, mode); +} + #else /* Grease Pencil Interpolation tool settings */ @@ -5067,6 +5721,632 @@ static void rna_def_gpu_fx(BlenderRNA *brna) RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, "rna_GPUFXSettings_fx_update"); } +/* Render Layers and Collections */ + +static void rna_def_scene_collections(BlenderRNA *brna, PropertyRNA *cprop) +{ + StructRNA *srna; + FunctionRNA *func; + PropertyRNA *parm; + + RNA_def_property_srna(cprop, "SceneCollections"); + srna = RNA_def_struct(brna, "SceneCollections", NULL); + RNA_def_struct_sdna(srna, "SceneCollection"); + RNA_def_struct_ui_text(srna, "Scene Collection", "Collection of scene collections"); + + func = RNA_def_function(srna, "new", "rna_SceneCollection_new"); + RNA_def_function_ui_description(func, "Add a collection to scene"); + RNA_def_function_flag(func, FUNC_USE_SELF_ID); + parm = RNA_def_string(func, "name", "SceneCollection", 0, "", "New name for the collection (not unique)"); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); + parm = RNA_def_pointer(func, "result", "SceneCollection", "", "Newly created collection"); + RNA_def_function_return(func, parm); + + func = RNA_def_function(srna, "remove", "rna_SceneCollection_remove"); + RNA_def_function_ui_description(func, "Remove a collection layer"); + RNA_def_function_flag(func, FUNC_USE_REPORTS | FUNC_USE_SELF_ID); + parm = RNA_def_pointer(func, "layer", "SceneCollection", "", "Collection to remove"); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR); + RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0); +} + +static void rna_def_collection_objects(BlenderRNA *brna, PropertyRNA *cprop) +{ + StructRNA *srna; + FunctionRNA *func; + PropertyRNA *parm; + PropertyRNA *prop; + + RNA_def_property_srna(cprop, "CollectionObjects"); + srna = RNA_def_struct(brna, "CollectionObjects", NULL); + RNA_def_struct_sdna(srna, "SceneCollection"); + RNA_def_struct_ui_text(srna, "Collection Objects", "Objects of a collection"); + + prop = RNA_def_property(srna, "active_index", PROP_INT, PROP_UNSIGNED); + RNA_def_property_int_funcs(prop, "rna_SceneCollection_objects_active_index_get", + "rna_SceneCollection_objects_active_index_set", + "rna_SceneCollection_objects_active_index_range"); + RNA_def_property_ui_text(prop, "Active Object Index", "Active index in collection objects array"); + RNA_def_property_update(prop, NC_SCENE | ND_LAYER_CONTENT, NULL); + + func = RNA_def_function(srna, "link", "rna_SceneCollection_object_link"); + RNA_def_function_ui_description(func, "Link an object to collection"); + RNA_def_function_flag(func, FUNC_USE_SELF_ID | FUNC_USE_MAIN | FUNC_USE_REPORTS); + parm = RNA_def_pointer(func, "object", "Object", "", "Object to add to collection"); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED); + + func = RNA_def_function(srna, "unlink", "rna_SceneCollection_object_unlink"); + RNA_def_function_ui_description(func, "Unlink object from collection"); + RNA_def_function_flag(func, FUNC_USE_SELF_ID | FUNC_USE_MAIN | FUNC_USE_REPORTS); + parm = RNA_def_pointer(func, "object", "Object", "", "Object to remove from collection"); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED); +} + +static void rna_def_scene_collection(BlenderRNA *brna) +{ + StructRNA *srna; + PropertyRNA *prop; + + srna = RNA_def_struct(brna, "SceneCollection", NULL); + RNA_def_struct_ui_text(srna, "Scene Collection", "Collection"); + + prop = RNA_def_property(srna, "name", PROP_STRING, PROP_NONE); + RNA_def_property_string_funcs(prop, NULL, NULL, "rna_SceneCollection_name_set"); + RNA_def_property_ui_text(prop, "Name", "Collection name"); + RNA_def_struct_name_property(srna, prop); + RNA_def_property_update(prop, NC_SCENE | ND_LAYER_CONTENT, NULL); + + prop = RNA_def_property(srna, "filter", PROP_STRING, PROP_NONE); + RNA_def_property_string_funcs(prop, NULL, NULL, "rna_SceneCollection_filter_set"); + RNA_def_property_ui_text(prop, "Filter", "Filter to dynamically include objects based on their names (e.g., CHAR_*)"); + RNA_def_property_update(prop, NC_SCENE | ND_LAYER_CONTENT, NULL); + + prop = RNA_def_property(srna, "collections", PROP_COLLECTION, PROP_NONE); + RNA_def_property_collection_sdna(prop, NULL, "scene_collections", NULL); + RNA_def_property_struct_type(prop, "SceneCollection"); + RNA_def_property_ui_text(prop, "SceneCollections", ""); + rna_def_scene_collections(brna, prop); + + prop = RNA_def_property(srna, "objects", PROP_COLLECTION, PROP_NONE); + RNA_def_property_collection_sdna(prop, NULL, "objects", NULL); + RNA_def_property_struct_type(prop, "Object"); + RNA_def_property_collection_funcs(prop, NULL, NULL, NULL, "rna_SceneCollection_objects_get", NULL, NULL, NULL, NULL); + RNA_def_property_ui_text(prop, "Objects", "All the objects directly added to this collection (not including sub-collection objects)"); + rna_def_collection_objects(brna, prop); + + prop = RNA_def_property(srna, "filters_objects", PROP_COLLECTION, PROP_NONE); + RNA_def_property_collection_sdna(prop, NULL, "filter_objects", NULL); + RNA_def_property_struct_type(prop, "Object"); + RNA_def_property_collection_funcs(prop, NULL, NULL, NULL, "rna_SceneCollection_objects_get", NULL, NULL, NULL, NULL); + RNA_def_property_ui_text(prop, "Filter Objects", "All the objects dynamically added to this collection via the filter"); +} + +static void rna_def_layer_collection_override(BlenderRNA *brna) +{ + StructRNA *srna; + PropertyRNA *prop; + + srna = RNA_def_struct(brna, "LayerCollectionOverride", NULL); + RNA_def_struct_sdna(srna, "CollectionOverride"); + RNA_def_struct_ui_text(srna, "Collection Override", "Collection Override"); + + prop = RNA_def_property(srna, "name", PROP_STRING, PROP_NONE); + RNA_def_property_ui_text(prop, "Name", "Collection name"); + RNA_def_struct_name_property(srna, prop); + RNA_def_property_update(prop, NC_SCENE | ND_LAYER_CONTENT, NULL); +} + +#define RNA_LAYER_ENGINE_USE(_ENGINE_, _NAME_) \ + prop = RNA_def_property(srna, #_NAME_"_use", PROP_BOOLEAN, PROP_NONE); \ + RNA_def_property_boolean_funcs(prop, \ + "rna_LayerEngineSettings_"#_ENGINE_"_"#_NAME_"_use_get", \ + "rna_LayerEngineSettings_"#_ENGINE_"_"#_NAME_"_use_set"); \ + RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE); \ + RNA_def_property_update(prop, NC_SCENE | ND_LAYER_CONTENT, "rna_CollectionEngineSettings_update"); + +#define RNA_LAYER_ENGINE_CLAY_USE(_NAME_) \ + RNA_LAYER_ENGINE_USE(Clay, _NAME_) + +#define RNA_LAYER_MODE_OBJECT_USE(_NAME_) \ + RNA_LAYER_ENGINE_USE(ObjectMode, _NAME_) + +#define RNA_LAYER_MODE_EDIT_USE(_NAME_) \ + RNA_LAYER_ENGINE_USE(EditMode, _NAME_) + +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_Clay_type_get", "rna_LayerEngineSettings_Clay_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_CLAY_USE(type) + + prop = RNA_def_property(srna, "matcap_icon", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_funcs(prop, "rna_LayerEngineSettings_Clay_matcap_icon_get", "rna_LayerEngineSettings_Clay_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_CLAY_USE(matcap_icon) + + prop = RNA_def_property(srna, "matcap_rotation", PROP_FLOAT, PROP_FACTOR); + RNA_def_property_float_funcs(prop, "rna_LayerEngineSettings_Clay_matcap_rotation_get", "rna_LayerEngineSettings_Clay_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_CLAY_USE(matcap_rotation) + + prop = RNA_def_property(srna, "matcap_hue", PROP_FLOAT, PROP_FACTOR); + RNA_def_property_float_funcs(prop, "rna_LayerEngineSettings_Clay_matcap_hue_get", "rna_LayerEngineSettings_Clay_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_CLAY_USE(matcap_hue) + + prop = RNA_def_property(srna, "matcap_saturation", PROP_FLOAT, PROP_FACTOR); + RNA_def_property_float_funcs(prop, "rna_LayerEngineSettings_Clay_matcap_saturation_get", "rna_LayerEngineSettings_Clay_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_CLAY_USE(matcap_saturation) + + prop = RNA_def_property(srna, "matcap_value", PROP_FLOAT, PROP_FACTOR); + RNA_def_property_float_funcs(prop, "rna_LayerEngineSettings_Clay_matcap_value_get", "rna_LayerEngineSettings_Clay_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_CLAY_USE(matcap_value) + + prop = RNA_def_property(srna, "ssao_factor_cavity", PROP_FLOAT, PROP_NONE); + RNA_def_property_float_funcs(prop, "rna_LayerEngineSettings_Clay_ssao_factor_cavity_get", "rna_LayerEngineSettings_Clay_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_CLAY_USE(ssao_factor_cavity) + + prop = RNA_def_property(srna, "ssao_factor_edge", PROP_FLOAT, PROP_NONE); + RNA_def_property_float_funcs(prop, "rna_LayerEngineSettings_Clay_ssao_factor_edge_get", "rna_LayerEngineSettings_Clay_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_CLAY_USE(ssao_factor_edge) + + prop = RNA_def_property(srna, "ssao_distance", PROP_FLOAT, PROP_NONE); + RNA_def_property_float_funcs(prop, "rna_LayerEngineSettings_Clay_ssao_distance_get", "rna_LayerEngineSettings_Clay_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_CLAY_USE(ssao_distance) + + prop = RNA_def_property(srna, "ssao_attenuation", PROP_FLOAT, PROP_NONE); + RNA_def_property_float_funcs(prop, "rna_LayerEngineSettings_Clay_ssao_attenuation_get", "rna_LayerEngineSettings_Clay_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_CLAY_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); +} + +static void rna_def_layer_collection_mode_settings_object(BlenderRNA *brna) +{ + StructRNA *srna; + PropertyRNA *prop; + + srna = RNA_def_struct(brna, "CollectionModeSettingsObject", NULL); + RNA_def_struct_sdna(srna, "CollectionEngineSettings"); + RNA_def_struct_ui_text(srna, "Collections Object Mode Settings", "Object Mode specific settings for this collection"); + + /* see RNA_LAYER_ENGINE_GET_SET macro */ + + prop = RNA_def_property(srna, "show_wire", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_ui_text(prop, "Wire", "Add the object's wireframe over solid drawing"); + RNA_def_property_boolean_funcs(prop, "rna_LayerEngineSettings_ObjectMode_show_wire_get", "rna_LayerEngineSettings_ObjectMode_show_wire_set"); + RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE); + RNA_def_property_update(prop, NC_SCENE | ND_LAYER_CONTENT, "rna_CollectionEngineSettings_update"); + RNA_LAYER_MODE_OBJECT_USE(show_wire) + + prop = RNA_def_property(srna, "show_backface_culling", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_ui_text(prop, "Backface Culling", ""); + RNA_def_property_boolean_funcs(prop, "rna_LayerEngineSettings_ObjectMode_show_backface_culling_get", "rna_LayerEngineSettings_ObjectMode_show_backface_culling_set"); + RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE); + RNA_def_property_update(prop, NC_SCENE | ND_LAYER_CONTENT, "rna_CollectionEngineSettings_update"); + RNA_LAYER_MODE_OBJECT_USE(show_backface_culling) +} + +static void rna_def_layer_collection_mode_settings_edit(BlenderRNA *brna) +{ + StructRNA *srna; + PropertyRNA *prop; + + srna = RNA_def_struct(brna, "CollectionModeSettingsEdit", NULL); + RNA_def_struct_sdna(srna, "CollectionEngineSettings"); + RNA_def_struct_ui_text(srna, "Collections Edit Mode Settings", "Edit Mode specific settings for this collection"); + + /* see RNA_LAYER_ENGINE_GET_SET macro */ + + prop = RNA_def_property(srna, "show_occlude_wire", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_ui_text(prop, "Hidden Wire", ""); + RNA_def_property_boolean_funcs(prop, "rna_LayerEngineSettings_EditMode_show_occlude_wire_get", "rna_LayerEngineSettings_EditMode_show_occlude_wire_set"); + RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE); + RNA_def_property_update(prop, NC_SCENE | ND_LAYER_CONTENT, "rna_CollectionEngineSettings_update"); + RNA_LAYER_MODE_EDIT_USE(show_occlude_wire) +} + +static void rna_def_layer_collection_mode_settings(BlenderRNA *brna) +{ + StructRNA *srna; + PropertyRNA *prop; + + srna = RNA_def_struct(brna, "CollectionModeSettings", NULL); + RNA_def_struct_sdna(srna, "CollectionEngineSettings"); + RNA_def_struct_ui_text(srna, "Collections Mode Settings", "Mode specific settings for this collection"); + RNA_def_struct_refine_func(srna, "rna_CollectionModeSettings_refine"); + + prop = RNA_def_property(srna, "type", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_sdna(prop, NULL, "type"); + RNA_def_property_enum_items(prop, rna_enum_layer_collection_mode_settings_type_items); + RNA_def_property_ui_text(prop, "Type", ""); + RNA_def_property_clear_flag(prop, PROP_EDITABLE); + + /* the modes specific structs */ + rna_def_layer_collection_mode_settings_object(brna); + rna_def_layer_collection_mode_settings_edit(brna); +} + +#undef RNA_LAYER_MODE_EDIT_USE +#undef RNA_LAYER_MODE_OBJECT_USE +#undef RNA_LAYER_ENGINE_CLAY_USE +#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"); + + prop = RNA_def_property(srna, "name", PROP_STRING, PROP_NONE); + RNA_def_property_string_funcs(prop, "rna_LayerCollection_name_get", "rna_LayerCollection_name_length", "rna_LayerCollection_name_set"); + RNA_def_property_ui_text(prop, "Name", "Collection name"); + RNA_def_struct_name_property(srna, prop); + RNA_def_property_update(prop, NC_SCENE | ND_LAYER_CONTENT, NULL); + + prop = RNA_def_property(srna, "collection", PROP_POINTER, PROP_NONE); + RNA_def_property_flag(prop, PROP_NEVER_NULL); + RNA_def_property_pointer_sdna(prop, NULL, "scene_collection"); + RNA_def_property_struct_type(prop, "SceneCollection"); + RNA_def_property_ui_text(prop, "Collection", "Collection this layer collection is wrapping"); + + prop = RNA_def_property(srna, "collections", PROP_COLLECTION, PROP_NONE); + RNA_def_property_collection_sdna(prop, NULL, "layer_collections", NULL); + RNA_def_property_struct_type(prop, "LayerCollection"); + RNA_def_property_ui_text(prop, "Layer Collections", ""); + + prop = RNA_def_property(srna, "objects", PROP_COLLECTION, PROP_NONE); + RNA_def_property_collection_sdna(prop, NULL, "object_bases", NULL); + RNA_def_property_struct_type(prop, "Object"); + RNA_def_property_collection_funcs(prop, NULL, NULL, NULL, "rna_LayerCollection_objects_get", NULL, NULL, NULL, NULL); + RNA_def_property_ui_text(prop, "Objects", "All the objects directly or indirectly added to this collection (not including sub-collection objects)"); + + prop = RNA_def_property(srna, "overrides", PROP_COLLECTION, PROP_NONE); + RNA_def_property_collection_sdna(prop, NULL, "overrides", NULL); + 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); + + func = RNA_def_function(srna, "get_mode_settings", "rna_LayerCollection_mode_settings_get"); + RNA_def_function_ui_description(func, "Return the mode settings for this collection"); + RNA_def_function_flag(func, FUNC_USE_SELF_ID | FUNC_USE_CONTEXT); + parm = RNA_def_enum(func, "type", rna_enum_layer_collection_mode_settings_type_items, COLLECTION_MODE_NONE, "Mode", "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); + RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE); + RNA_def_property_ui_icon(prop, ICON_RESTRICT_VIEW_OFF, 1); + RNA_def_property_ui_text(prop, "Hide", "Restrict visiblity"); + RNA_def_property_update(prop, NC_SCENE | ND_LAYER_CONTENT, "rna_LayerCollection_hide_update"); + + prop = RNA_def_property(srna, "hide_select", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", COLLECTION_SELECTABLE); + RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE); + RNA_def_property_ui_icon(prop, ICON_RESTRICT_SELECT_OFF, 1); + RNA_def_property_ui_text(prop, "Hide Selectable", "Restrict selection"); + RNA_def_property_update(prop, NC_SCENE | ND_LAYER_CONTENT, "rna_LayerCollection_hide_select_update"); + + prop = RNA_def_property(srna, "is_unfolded", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", COLLECTION_FOLDED); + RNA_def_property_ui_icon(prop, ICON_RIGHTARROW, 1); + RNA_def_property_ui_text(prop, "Folded", "Folded collection"); + RNA_def_property_update(prop, NC_SCENE | ND_LAYER_CONTENT, NULL); + + /* TODO_LAYER_OVERRIDE */ +} + +static void rna_def_layer_collections(BlenderRNA *brna, PropertyRNA *cprop) +{ + StructRNA *srna; + FunctionRNA *func; + PropertyRNA *prop; + PropertyRNA *parm; + + RNA_def_property_srna(cprop, "LayerCollections"); + srna = RNA_def_struct(brna, "LayerCollections", NULL); + RNA_def_struct_sdna(srna, "SceneLayer"); + RNA_def_struct_ui_text(srna, "Layer Collections", "Collections of render layer"); + + prop = RNA_def_property(srna, "active_index", PROP_INT, PROP_UNSIGNED); + RNA_def_property_int_sdna(prop, NULL, "active_collection"); + RNA_def_property_int_funcs(prop, "rna_LayerCollections_active_collection_index_get", + "rna_LayerCollections_active_collection_index_set", + "rna_LayerCollections_active_collection_index_range"); + RNA_def_property_ui_text(prop, "Active Collection Index", "Active index in layer collection array"); + RNA_def_property_update(prop, NC_SCENE | ND_LAYER, NULL); + + prop = RNA_def_property(srna, "active", PROP_POINTER, PROP_NONE); + RNA_def_property_struct_type(prop, "LayerCollection"); + RNA_def_property_pointer_funcs(prop, "rna_LayerCollections_active_collection_get", + "rna_LayerCollections_active_collection_set", NULL, NULL); + RNA_def_property_flag(prop, PROP_EDITABLE | PROP_NEVER_NULL); + RNA_def_property_ui_text(prop, "Active Layer Collection", "Active Layer Collection"); + RNA_def_property_update(prop, NC_SCENE | ND_LAYER, NULL); + + func = RNA_def_function(srna, "link", "rna_SceneLayer_collection_link"); + RNA_def_function_ui_description(func, "Link a collection to render layer"); + RNA_def_function_flag(func, FUNC_USE_SELF_ID | FUNC_USE_MAIN); + parm = RNA_def_pointer(func, "scene_collection", "SceneCollection", "", "Collection to add to render layer"); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED); + parm = RNA_def_pointer(func, "result", "LayerCollection", "", "Newly created layer collection"); + RNA_def_function_return(func, parm); + + func = RNA_def_function(srna, "unlink", "rna_SceneLayer_collection_unlink"); + RNA_def_function_ui_description(func, "Unlink a collection from render layer"); + RNA_def_function_flag(func, FUNC_USE_SELF_ID | FUNC_USE_MAIN | FUNC_USE_REPORTS); + parm = RNA_def_pointer(func, "layer_collection", "LayerCollection", "", "Layer collection to remove from render layer"); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED); +} + +static void rna_def_layer_objects(BlenderRNA *brna, PropertyRNA *cprop) +{ + StructRNA *srna; + PropertyRNA *prop; + + RNA_def_property_srna(cprop, "LayerObjects"); + srna = RNA_def_struct(brna, "LayerObjects", NULL); + RNA_def_struct_sdna(srna, "SceneLayer"); + RNA_def_struct_ui_text(srna, "Layer Objects", "Collections of objects"); + + prop = RNA_def_property(srna, "active", PROP_POINTER, PROP_NONE); + RNA_def_property_struct_type(prop, "Object"); + RNA_def_property_pointer_funcs(prop, "rna_LayerObjects_active_object_get", "rna_LayerObjects_active_object_set", NULL, NULL); + RNA_def_property_flag(prop, PROP_EDITABLE | PROP_NEVER_UNLINK); + RNA_def_property_ui_text(prop, "Active Object", "Active object for this layer"); + /* Could call: ED_base_object_activate(C, rl->basact); + * but would be a bad level call and it seems the notifier is enough */ + RNA_def_property_update(prop, NC_SCENE | ND_OB_ACTIVE, NULL); + + prop = RNA_def_property(srna, "selected", PROP_COLLECTION, PROP_NONE); + RNA_def_property_collection_sdna(prop, NULL, "object_bases", NULL); + RNA_def_property_struct_type(prop, "Object"); + RNA_def_property_collection_funcs(prop, "rna_LayerObjects_selected_begin", "rna_iterator_listbase_next", + "rna_iterator_listbase_end", "rna_SceneLayer_objects_get", + NULL, NULL, NULL, NULL); + RNA_def_property_ui_text(prop, "Selected Objects", "All the selected objects of this layer"); +} + +static void rna_def_scene_layer(BlenderRNA *brna) +{ + StructRNA *srna; + PropertyRNA *prop; + + static EnumPropertyItem engine_items[] = { + {0, "BLENDER_RENDER", 0, "Blender Render", "Use the Blender internal rendering engine for rendering"}, + {0, NULL, 0, NULL, NULL} + }; + + srna = RNA_def_struct(brna, "SceneLayer", NULL); + RNA_def_struct_ui_text(srna, "Render Layer", "Render layer"); + RNA_def_struct_ui_icon(srna, ICON_RENDERLAYERS); + + prop = RNA_def_property(srna, "name", PROP_STRING, PROP_NONE); + RNA_def_property_string_funcs(prop, NULL, NULL, "rna_SceneLayer_name_set"); + RNA_def_property_ui_text(prop, "Name", "Render layer name"); + RNA_def_struct_name_property(srna, prop); + RNA_def_property_update(prop, NC_SCENE | ND_LAYER_CONTENT, NULL); + + prop = RNA_def_property(srna, "collections", PROP_COLLECTION, PROP_NONE); + RNA_def_property_collection_sdna(prop, NULL, "layer_collections", NULL); + RNA_def_property_struct_type(prop, "LayerCollection"); + RNA_def_property_ui_text(prop, "Layer Collections", ""); + rna_def_layer_collections(brna, prop); + + prop = RNA_def_property(srna, "objects", PROP_COLLECTION, PROP_NONE); + RNA_def_property_collection_sdna(prop, NULL, "object_bases", NULL); + RNA_def_property_struct_type(prop, "Object"); + RNA_def_property_collection_funcs(prop, NULL, NULL, NULL, "rna_SceneLayer_objects_get", NULL, NULL, NULL, NULL); + RNA_def_property_ui_text(prop, "Objects", "All the objects in this layer"); + rna_def_layer_objects(brna, prop); + + /* layer options */ + prop = RNA_def_property(srna, "use", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", SCENE_LAYER_RENDER); + RNA_def_property_ui_text(prop, "Enabled", "Disable or enable the render layer"); + RNA_def_property_update(prop, NC_SCENE | ND_LAYER, NULL); + + /* engine */ + prop = RNA_def_property(srna, "engine", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_items(prop, engine_items); + RNA_def_property_enum_funcs(prop, "rna_SceneLayer_engine_get", "rna_SceneLayer_engine_set", + "rna_SceneLayer_engine_itemf"); + RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); + RNA_def_property_ui_text(prop, "Engine", "Engine to use for rendering"); + RNA_def_property_update(prop, NC_WINDOW, "rna_SceneLayer_engine_update"); + + prop = RNA_def_property(srna, "has_multiple_engines", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_funcs(prop, "rna_SceneLayer_multiple_engines_get", NULL); + RNA_def_property_clear_flag(prop, PROP_EDITABLE); + RNA_def_property_ui_text(prop, "Multiple Engines", "More than one rendering engine is available"); +} + +static void rna_def_scene_layers(BlenderRNA *brna, PropertyRNA *cprop) +{ + StructRNA *srna; + FunctionRNA *func; + PropertyRNA *parm; + PropertyRNA *prop; + + RNA_def_property_srna(cprop, "SceneLayers"); + srna = RNA_def_struct(brna, "SceneLayers", NULL); + RNA_def_struct_sdna(srna, "Scene"); + RNA_def_struct_ui_text(srna, "Render Layers", "Collection of render layers"); + + prop = RNA_def_property(srna, "active_index", PROP_INT, PROP_UNSIGNED); + RNA_def_property_int_sdna(prop, NULL, "active_layer"); + RNA_def_property_int_funcs(prop, "rna_SceneLayer_active_layer_index_get", + "rna_SceneLayer_active_layer_index_set", + "rna_SceneLayer_active_layer_index_range"); + RNA_def_property_ui_text(prop, "Active Layer Index", "Active index in render layer array"); + RNA_def_property_update(prop, NC_SCENE | ND_LAYER, NULL); + + prop = RNA_def_property(srna, "active", PROP_POINTER, PROP_NONE); + RNA_def_property_struct_type(prop, "SceneLayer"); + RNA_def_property_pointer_funcs(prop, "rna_SceneLayer_active_layer_get", + "rna_SceneLayer_active_layer_set", NULL, NULL); + RNA_def_property_flag(prop, PROP_EDITABLE | PROP_NEVER_NULL); + RNA_def_property_ui_text(prop, "Active Render Layer", "Active Render Layer"); + RNA_def_property_update(prop, NC_SCENE | ND_LAYER, NULL); + + func = RNA_def_function(srna, "new", "rna_SceneLayer_new"); + RNA_def_function_ui_description(func, "Add a render layer to scene"); + RNA_def_function_flag(func, FUNC_USE_SELF_ID); + parm = RNA_def_string(func, "name", "SceneLayer", 0, "", "New name for the render layer (not unique)"); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); + parm = RNA_def_pointer(func, "result", "SceneLayer", "", "Newly created render layer"); + RNA_def_function_return(func, parm); + + func = RNA_def_function(srna, "remove", "rna_SceneLayer_remove"); + RNA_def_function_ui_description(func, "Remove a render layer"); + RNA_def_function_flag(func, FUNC_USE_MAIN | FUNC_USE_REPORTS | FUNC_USE_SELF_ID); + parm = RNA_def_pointer(func, "layer", "SceneLayer", "", "Render layer to remove"); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR); + RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0); +} + +static void rna_def_object_base(BlenderRNA *brna) +{ + StructRNA *srna; + PropertyRNA *prop; + + srna = RNA_def_struct(brna, "ObjectBase", NULL); + RNA_def_struct_sdna(srna, "Base"); + RNA_def_struct_ui_text(srna, "Object Base", "An object instance in a render layer"); + RNA_def_struct_ui_icon(srna, ICON_OBJECT_DATA); + + prop = RNA_def_property(srna, "object", PROP_POINTER, PROP_NONE); + RNA_def_property_pointer_sdna(prop, NULL, "object"); + RNA_def_property_ui_text(prop, "Object", "Object this base links to"); + + prop = RNA_def_property(srna, "select", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", BASE_SELECTED); + RNA_def_property_ui_text(prop, "Select", "Object base selection state"); + RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, "rna_ObjectBase_select_update"); +} + +/* TODO LAYERS: legacy SceneRenderLayers, to be removed */ static void rna_def_scene_render_layer(BlenderRNA *brna) { @@ -5795,6 +7075,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; @@ -6781,7 +8170,7 @@ static void rna_def_scene_objects(BlenderRNA *brna, PropertyRNA *cprop) RNA_def_function_flag(func, FUNC_USE_CONTEXT | FUNC_USE_REPORTS); parm = RNA_def_pointer(func, "object", "Object", "", "Object to add to scene"); RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED); - parm = RNA_def_pointer(func, "base", "ObjectBase", "", "The newly created base"); + parm = RNA_def_pointer(func, "base", "ObjectBaseLegacy", "", "The newly created base"); RNA_def_function_return(func, parm); func = RNA_def_function(srna, "unlink", "rna_Scene_object_unlink"); @@ -6816,7 +8205,7 @@ static void rna_def_scene_bases(BlenderRNA *brna, PropertyRNA *cprop) RNA_def_struct_ui_text(srna, "Scene Bases", "Collection of scene bases"); prop = RNA_def_property(srna, "active", PROP_POINTER, PROP_NONE); - RNA_def_property_struct_type(prop, "ObjectBase"); + RNA_def_property_struct_type(prop, "ObjectBaseLegacy"); RNA_def_property_pointer_sdna(prop, NULL, "basact"); RNA_def_property_flag(prop, PROP_EDITABLE); RNA_def_property_ui_text(prop, "Active Base", "Active object base in the scene"); @@ -7060,7 +8449,7 @@ void RNA_def_scene(BlenderRNA *brna) /* Bases/Objects */ prop = RNA_def_property(srna, "object_bases", PROP_COLLECTION, PROP_NONE); RNA_def_property_collection_sdna(prop, NULL, "base", NULL); - RNA_def_property_struct_type(prop, "ObjectBase"); + RNA_def_property_struct_type(prop, "ObjectBaseLegacy"); RNA_def_property_ui_text(prop, "Bases", ""); RNA_def_property_collection_funcs(prop, NULL, NULL, NULL, NULL, NULL, NULL, "rna_Scene_object_bases_lookup_string", NULL); @@ -7309,7 +8698,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"); @@ -7425,6 +8824,19 @@ void RNA_def_scene(BlenderRNA *brna) RNA_def_property_struct_type(prop, "Depsgraph"); RNA_def_property_ui_text(prop, "Dependency Graph", "Dependencies in the scene data"); + /* Layer and Collections */ + prop = RNA_def_property(srna, "render_layers", PROP_COLLECTION, PROP_NONE); + RNA_def_property_collection_sdna(prop, NULL, "render_layers", NULL); + RNA_def_property_struct_type(prop, "SceneLayer"); + RNA_def_property_ui_text(prop, "Render Layers", ""); + rna_def_scene_layers(brna, prop); + + prop = RNA_def_property(srna, "master_collection", PROP_POINTER, PROP_NONE); + RNA_def_property_flag(prop, PROP_NEVER_NULL); + RNA_def_property_pointer_sdna(prop, NULL, "collection"); + RNA_def_property_struct_type(prop, "SceneCollection"); + RNA_def_property_ui_text(prop, "Master Collection", "Collection that contains all other collections"); + /* Nestled Data */ /* *** Non-Animated *** */ RNA_define_animate_sdna(false); @@ -7440,9 +8852,17 @@ void RNA_def_scene(BlenderRNA *brna) rna_def_transform_orientation(brna); rna_def_selected_uv_element(brna); rna_def_display_safe_areas(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_layer_collection_mode_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); @@ -7452,3 +8872,5 @@ void RNA_def_scene(BlenderRNA *brna) } #endif + +#undef NO_ENGINE diff --git a/source/blender/makesrna/intern/rna_space.c b/source/blender/makesrna/intern/rna_space.c index 5e364a3adf1..07a1a73358d 100644 --- a/source/blender/makesrna/intern/rna_space.c +++ b/source/blender/makesrna/intern/rna_space.c @@ -208,6 +208,7 @@ static EnumPropertyItem buttons_context_items[] = { {BCONTEXT_TEXTURE, "TEXTURE", ICON_TEXTURE, "Texture", "Texture"}, {BCONTEXT_PARTICLE, "PARTICLES", ICON_PARTICLES, "Particles", "Particle"}, {BCONTEXT_PHYSICS, "PHYSICS", ICON_PHYSICS, "Physics", "Physics"}, + {BCONTEXT_COLLECTION, "COLLECTION", ICON_COLLAPSEMENU, "Collection", "Collection"}, {0, NULL, 0, NULL, NULL} }; @@ -1076,6 +1077,10 @@ static EnumPropertyItem *rna_SpaceProperties_context_itemf(bContext *UNUSED(C), RNA_enum_items_add_value(&item, &totitem, buttons_context_items, BCONTEXT_SCENE); } + if (sbuts->pathflag & (1 << BCONTEXT_COLLECTION)) { + RNA_enum_items_add_value(&item, &totitem, buttons_context_items, BCONTEXT_COLLECTION); + } + if (sbuts->pathflag & (1 << BCONTEXT_WORLD)) { RNA_enum_items_add_value(&item, &totitem, buttons_context_items, BCONTEXT_WORLD); } @@ -2100,6 +2105,7 @@ static void rna_def_space_outliner(BlenderRNA *brna) {SO_USERDEF, "USER_PREFERENCES", 0, "User Preferences", "Display user preference data"}, {SO_ID_ORPHANS, "ORPHAN_DATA", 0, "Orphan Data", "Display data-blocks which are unused and/or will be lost when the file is reloaded"}, + {SO_COLLECTIONS, "COLLECTIONS", 0, "Collections", "Display the collections of the active render layer"}, {0, NULL, 0, NULL, NULL} }; @@ -2389,6 +2395,13 @@ static void rna_def_space_view3d(BlenderRNA *brna) {0, NULL, 0, NULL, NULL} }; + static EnumPropertyItem debug_background_items[] = { + {V3D_DEBUG_BACKGROUND_NONE, "NONE", 0, "None", ""}, + {V3D_DEBUG_BACKGROUND_GRADIENT, "GRADIENT", 0, "Gradient", ""}, + {V3D_DEBUG_BACKGROUND_WORLD, "WORLD", 0, "World", ""}, + {0, NULL, 0, NULL, NULL} + }; + srna = RNA_def_struct(brna, "SpaceView3D", "Space"); RNA_def_struct_sdna(srna, "View3D"); RNA_def_struct_ui_text(srna, "3D View Space", "3D View space data"); @@ -2781,6 +2794,42 @@ static void rna_def_space_view3d(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Volume Alpha", "Opacity (alpha) of the cameras' frustum volume"); RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL); + /* *** Blender 2.8 Viewport temporary *** */ + prop = RNA_def_property(srna, "use_modern_viewport", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "tmp_compat_flag", V3D_NEW_VIEWPORT); + RNA_def_property_ui_text(prop, "Modern Viewport", "Use modern viewport"); + RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL); + + prop = RNA_def_property(srna, "show_scene_depth", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "tmp_compat_flag", V3D_DEBUG_SHOW_SCENE_DEPTH); + RNA_def_property_ui_text(prop, "Show Scene Depth", "Debug option to show the depth in the viewport"); + RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL); + + prop = RNA_def_property(srna, "show_combined_depth", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "tmp_compat_flag", V3D_DEBUG_SHOW_COMBINED_DEPTH); + RNA_def_property_ui_text(prop, "Show Combined Depth", "Debug option to show the depth in the viewport"); + RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL); + + prop = RNA_def_property(srna, "debug_near", PROP_FLOAT, PROP_DISTANCE); + RNA_def_property_float_sdna(prop, NULL, "debug.znear"); + RNA_def_property_ui_text(prop, "Near", "Near distance for depth debugging"); + RNA_def_property_range(prop, 1e-6f, FLT_MAX); + RNA_def_property_ui_range(prop, 0.001f, FLT_MAX, 10, 3); + RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL); + + prop = RNA_def_property(srna, "debug_far", PROP_FLOAT, PROP_DISTANCE); + RNA_def_property_float_sdna(prop, NULL, "debug.zfar"); + RNA_def_property_range(prop, 1e-6f, FLT_MAX); + RNA_def_property_ui_range(prop, 0.001f, FLT_MAX, 10, 3); + RNA_def_property_ui_text(prop, "Far", "Far distance for depth debugging"); + RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL); + + prop = RNA_def_property(srna, "debug_background", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_sdna(prop, NULL, "debug.background"); + RNA_def_property_enum_items(prop, debug_background_items); + RNA_def_property_ui_text(prop, "Background", ""); + RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL); + /* *** Animated *** */ RNA_define_animate_sdna(true); /* region */ diff --git a/source/blender/modifiers/CMakeLists.txt b/source/blender/modifiers/CMakeLists.txt index bacfc177432..b8ebb375a48 100644 --- a/source/blender/modifiers/CMakeLists.txt +++ b/source/blender/modifiers/CMakeLists.txt @@ -113,10 +113,6 @@ set(SRC intern/MOD_weightvg_util.h ) -if(WITH_LEGACY_DEPSGRAPH) - add_definitions(-DWITH_LEGACY_DEPSGRAPH) -endif() - if(WITH_ALEMBIC) add_definitions(-DWITH_ALEMBIC) list(APPEND INC diff --git a/source/blender/modifiers/intern/MOD_armature.c b/source/blender/modifiers/intern/MOD_armature.c index 2400dbcb898..8aee7b66916 100644 --- a/source/blender/modifiers/intern/MOD_armature.c +++ b/source/blender/modifiers/intern/MOD_armature.c @@ -99,22 +99,6 @@ static void foreachObjectLink( walk(userData, ob, &amd->object, IDWALK_CB_NOP); } -static void updateDepgraph(ModifierData *md, DagForest *forest, - struct Main *UNUSED(bmain), - struct Scene *UNUSED(scene), - Object *UNUSED(ob), - DagNode *obNode) -{ - ArmatureModifierData *amd = (ArmatureModifierData *) md; - - if (amd->object) { - DagNode *curNode = dag_get_node(forest, amd->object); - - dag_add_relation(forest, curNode, obNode, - DAG_RL_DATA_DATA | DAG_RL_OB_DATA, "Armature Modifier"); - } -} - static void updateDepsgraph(ModifierData *md, struct Main *UNUSED(bmain), struct Scene *UNUSED(scene), @@ -221,7 +205,6 @@ ModifierTypeInfo modifierType_Armature = { /* requiredDataMask */ requiredDataMask, /* freeData */ NULL, /* isDisabled */ isDisabled, - /* updateDepgraph */ updateDepgraph, /* updateDepsgraph */ updateDepsgraph, /* dependsOnTime */ NULL, /* dependsOnNormals */ NULL, diff --git a/source/blender/modifiers/intern/MOD_array.c b/source/blender/modifiers/intern/MOD_array.c index 2b739dc0093..61ac4d5692f 100644 --- a/source/blender/modifiers/intern/MOD_array.c +++ b/source/blender/modifiers/intern/MOD_array.c @@ -101,40 +101,6 @@ static void foreachObjectLink( walk(userData, ob, &amd->offset_ob, IDWALK_CB_NOP); } -static void updateDepgraph(ModifierData *md, DagForest *forest, - struct Main *UNUSED(bmain), - struct Scene *UNUSED(scene), - Object *UNUSED(ob), DagNode *obNode) -{ - ArrayModifierData *amd = (ArrayModifierData *) md; - - if (amd->start_cap) { - DagNode *curNode = dag_get_node(forest, amd->start_cap); - - dag_add_relation(forest, curNode, obNode, - DAG_RL_DATA_DATA | DAG_RL_OB_DATA, "Array Modifier"); - } - if (amd->end_cap) { - DagNode *curNode = dag_get_node(forest, amd->end_cap); - - dag_add_relation(forest, curNode, obNode, - DAG_RL_DATA_DATA | DAG_RL_OB_DATA, "Array Modifier"); - } - if (amd->curve_ob) { - DagNode *curNode = dag_get_node(forest, amd->curve_ob); - curNode->eval_flags |= DAG_EVAL_NEED_CURVE_PATH; - - dag_add_relation(forest, curNode, obNode, - DAG_RL_DATA_DATA | DAG_RL_OB_DATA, "Array Modifier"); - } - if (amd->offset_ob) { - DagNode *curNode = dag_get_node(forest, amd->offset_ob); - - dag_add_relation(forest, curNode, obNode, - DAG_RL_DATA_DATA | DAG_RL_OB_DATA, "Array Modifier"); - } -} - static void updateDepsgraph(ModifierData *md, struct Main *UNUSED(bmain), struct Scene *scene, @@ -797,7 +763,6 @@ ModifierTypeInfo modifierType_Array = { /* requiredDataMask */ NULL, /* freeData */ NULL, /* isDisabled */ NULL, - /* updateDepgraph */ updateDepgraph, /* updateDepsgraph */ updateDepsgraph, /* dependsOnTime */ NULL, /* dependsOnNormals */ NULL, diff --git a/source/blender/modifiers/intern/MOD_bevel.c b/source/blender/modifiers/intern/MOD_bevel.c index 5874029ae08..17b0cd4d7f5 100644 --- a/source/blender/modifiers/intern/MOD_bevel.c +++ b/source/blender/modifiers/intern/MOD_bevel.c @@ -213,7 +213,6 @@ ModifierTypeInfo modifierType_Bevel = { /* requiredDataMask */ requiredDataMask, /* freeData */ NULL, /* isDisabled */ NULL, - /* updateDepgraph */ NULL, /* updateDepsgraph */ NULL, /* dependsOnTime */ NULL, /* dependsOnNormals */ dependsOnNormals, diff --git a/source/blender/modifiers/intern/MOD_boolean.c b/source/blender/modifiers/intern/MOD_boolean.c index f828bc68857..51020566de6 100644 --- a/source/blender/modifiers/intern/MOD_boolean.c +++ b/source/blender/modifiers/intern/MOD_boolean.c @@ -104,22 +104,6 @@ static void foreachObjectLink( walk(userData, ob, &bmd->object, IDWALK_CB_NOP); } -static void updateDepgraph(ModifierData *md, DagForest *forest, - struct Main *UNUSED(bmain), - struct Scene *UNUSED(scene), - Object *UNUSED(ob), - DagNode *obNode) -{ - BooleanModifierData *bmd = (BooleanModifierData *) md; - - if (bmd->object) { - DagNode *curNode = dag_get_node(forest, bmd->object); - - dag_add_relation(forest, curNode, obNode, - DAG_RL_DATA_DATA | DAG_RL_OB_DATA, "Boolean Modifier"); - } -} - static void updateDepsgraph(ModifierData *md, struct Main *UNUSED(bmain), struct Scene *UNUSED(scene), @@ -459,7 +443,6 @@ ModifierTypeInfo modifierType_Boolean = { /* requiredDataMask */ requiredDataMask, /* freeData */ NULL, /* isDisabled */ isDisabled, - /* updateDepgraph */ updateDepgraph, /* updateDepsgraph */ updateDepsgraph, /* dependsOnTime */ NULL, /* dependsOnNormals */ NULL, diff --git a/source/blender/modifiers/intern/MOD_build.c b/source/blender/modifiers/intern/MOD_build.c index a364eef2974..d2467a8fc4a 100644 --- a/source/blender/modifiers/intern/MOD_build.c +++ b/source/blender/modifiers/intern/MOD_build.c @@ -322,7 +322,6 @@ ModifierTypeInfo modifierType_Build = { /* requiredDataMask */ NULL, /* freeData */ NULL, /* isDisabled */ NULL, - /* updateDepgraph */ NULL, /* updateDepsgraph */ NULL, /* dependsOnTime */ dependsOnTime, /* dependsOnNormals */ NULL, diff --git a/source/blender/modifiers/intern/MOD_cast.c b/source/blender/modifiers/intern/MOD_cast.c index ddcf1852dc6..9e718eab639 100644 --- a/source/blender/modifiers/intern/MOD_cast.c +++ b/source/blender/modifiers/intern/MOD_cast.c @@ -105,22 +105,6 @@ static void foreachObjectLink( walk(userData, ob, &cmd->object, IDWALK_CB_NOP); } -static void updateDepgraph(ModifierData *md, DagForest *forest, - struct Main *UNUSED(bmain), - struct Scene *UNUSED(scene), - Object *UNUSED(ob), - DagNode *obNode) -{ - CastModifierData *cmd = (CastModifierData *) md; - - if (cmd->object) { - DagNode *curNode = dag_get_node(forest, cmd->object); - - dag_add_relation(forest, curNode, obNode, DAG_RL_OB_DATA, - "Cast Modifier"); - } -} - static void updateDepsgraph(ModifierData *md, struct Main *UNUSED(bmain), struct Scene *UNUSED(scene), @@ -513,7 +497,6 @@ ModifierTypeInfo modifierType_Cast = { /* requiredDataMask */ requiredDataMask, /* freeData */ NULL, /* isDisabled */ isDisabled, - /* updateDepgraph */ updateDepgraph, /* updateDepsgraph */ updateDepsgraph, /* dependsOnTime */ NULL, /* dependsOnNormals */ NULL, diff --git a/source/blender/modifiers/intern/MOD_cloth.c b/source/blender/modifiers/intern/MOD_cloth.c index e8c39770a14..59eb00207df 100644 --- a/source/blender/modifiers/intern/MOD_cloth.c +++ b/source/blender/modifiers/intern/MOD_cloth.c @@ -117,26 +117,6 @@ static void deformVerts(ModifierData *md, Object *ob, DerivedMesh *derivedData, dm->release(dm); } -static void updateDepgraph(ModifierData *md, DagForest *forest, - struct Main *UNUSED(bmain), - Scene *scene, Object *ob, DagNode *obNode) -{ - ClothModifierData *clmd = (ClothModifierData *) md; - - if (clmd) { - /* Actual code uses get_collisionobjects */ -#ifdef WITH_LEGACY_DEPSGRAPH - dag_add_collision_relations(forest, scene, ob, obNode, clmd->coll_parms->group, ob->lay|scene->lay, eModifierType_Collision, NULL, true, "Cloth Collision"); - dag_add_forcefield_relations(forest, scene, ob, obNode, clmd->sim_parms->effector_weights, true, 0, "Cloth Field"); -#else - (void)forest; - (void)scene; - (void)ob; - (void)obNode; -#endif - } -} - static void updateDepsgraph(ModifierData *md, struct Main *UNUSED(bmain), struct Scene *scene, @@ -262,7 +242,6 @@ ModifierTypeInfo modifierType_Cloth = { /* requiredDataMask */ requiredDataMask, /* freeData */ freeData, /* isDisabled */ NULL, - /* updateDepgraph */ updateDepgraph, /* updateDepsgraph */ updateDepsgraph, /* dependsOnTime */ dependsOnTime, /* dependsOnNormals */ NULL, diff --git a/source/blender/modifiers/intern/MOD_collision.c b/source/blender/modifiers/intern/MOD_collision.c index e7ff0a90fbc..a2a4b2e1274 100644 --- a/source/blender/modifiers/intern/MOD_collision.c +++ b/source/blender/modifiers/intern/MOD_collision.c @@ -265,7 +265,6 @@ ModifierTypeInfo modifierType_Collision = { /* requiredDataMask */ NULL, /* freeData */ freeData, /* isDisabled */ NULL, - /* updateDepgraph */ NULL, /* updateDepsgraph */ NULL, /* dependsOnTime */ dependsOnTime, /* dependsOnNormals */ NULL, diff --git a/source/blender/modifiers/intern/MOD_correctivesmooth.c b/source/blender/modifiers/intern/MOD_correctivesmooth.c index 77fd84a2948..0718b0f85fa 100644 --- a/source/blender/modifiers/intern/MOD_correctivesmooth.c +++ b/source/blender/modifiers/intern/MOD_correctivesmooth.c @@ -759,7 +759,6 @@ ModifierTypeInfo modifierType_CorrectiveSmooth = { /* requiredDataMask */ requiredDataMask, /* freeData */ freeData, /* isDisabled */ NULL, - /* updateDepgraph */ NULL, /* updateDepsgraph */ NULL, /* dependsOnTime */ NULL, /* dependsOnNormals */ NULL, diff --git a/source/blender/modifiers/intern/MOD_curve.c b/source/blender/modifiers/intern/MOD_curve.c index 09444476bfe..6f3dbe841aa 100644 --- a/source/blender/modifiers/intern/MOD_curve.c +++ b/source/blender/modifiers/intern/MOD_curve.c @@ -92,23 +92,6 @@ static void foreachObjectLink( walk(userData, ob, &cmd->object, IDWALK_CB_NOP); } -static void updateDepgraph(ModifierData *md, DagForest *forest, - struct Main *UNUSED(bmain), - Scene *UNUSED(scene), - Object *UNUSED(ob), - DagNode *obNode) -{ - CurveModifierData *cmd = (CurveModifierData *) md; - - if (cmd->object) { - DagNode *curNode = dag_get_node(forest, cmd->object); - curNode->eval_flags |= DAG_EVAL_NEED_CURVE_PATH; - - dag_add_relation(forest, curNode, obNode, - DAG_RL_DATA_DATA | DAG_RL_OB_DATA, "Curve Modifier"); - } -} - static void updateDepsgraph(ModifierData *md, struct Main *UNUSED(bmain), struct Scene *scene, @@ -178,7 +161,6 @@ ModifierTypeInfo modifierType_Curve = { /* requiredDataMask */ requiredDataMask, /* freeData */ NULL, /* isDisabled */ isDisabled, - /* updateDepgraph */ updateDepgraph, /* updateDepsgraph */ updateDepsgraph, /* dependsOnTime */ NULL, /* dependsOnNormals */ NULL, diff --git a/source/blender/modifiers/intern/MOD_datatransfer.c b/source/blender/modifiers/intern/MOD_datatransfer.c index a2210893602..3bddbc7ee2b 100644 --- a/source/blender/modifiers/intern/MOD_datatransfer.c +++ b/source/blender/modifiers/intern/MOD_datatransfer.c @@ -127,22 +127,6 @@ static void foreachObjectLink( walk(userData, ob, &dtmd->ob_source, IDWALK_CB_NOP); } -static void updateDepgraph(ModifierData *md, DagForest *forest, - struct Main *UNUSED(bmain), - struct Scene *UNUSED(scene), - Object *UNUSED(ob), DagNode *obNode) -{ - DataTransferModifierData *dtmd = (DataTransferModifierData *) md; - DagNode *curNode; - - if (dtmd->ob_source) { - curNode = dag_get_node(forest, dtmd->ob_source); - - dag_add_relation(forest, curNode, obNode, DAG_RL_DATA_DATA | DAG_RL_OB_DATA, - "DataTransfer Modifier"); - } -} - static void updateDepsgraph(ModifierData *md, struct Main *UNUSED(bmain), struct Scene *UNUSED(scene), @@ -254,7 +238,6 @@ ModifierTypeInfo modifierType_DataTransfer = { /* requiredDataMask */ requiredDataMask, /* freeData */ NULL, /* isDisabled */ isDisabled, - /* updateDepgraph */ updateDepgraph, /* updateDepsgraph */ updateDepsgraph, /* dependsOnTime */ NULL, /* dependsOnNormals */ dependsOnNormals, diff --git a/source/blender/modifiers/intern/MOD_decimate.c b/source/blender/modifiers/intern/MOD_decimate.c index 617ae5a89f3..bcb52e4e0ca 100644 --- a/source/blender/modifiers/intern/MOD_decimate.c +++ b/source/blender/modifiers/intern/MOD_decimate.c @@ -227,7 +227,6 @@ ModifierTypeInfo modifierType_Decimate = { /* requiredDataMask */ requiredDataMask, /* freeData */ NULL, /* isDisabled */ NULL, - /* updateDepgraph */ NULL, /* updateDepsgraph */ NULL, /* dependsOnTime */ NULL, /* dependsOnNormals */ NULL, diff --git a/source/blender/modifiers/intern/MOD_displace.c b/source/blender/modifiers/intern/MOD_displace.c index 18f60bab490..4f875bbf35f 100644 --- a/source/blender/modifiers/intern/MOD_displace.c +++ b/source/blender/modifiers/intern/MOD_displace.c @@ -159,31 +159,6 @@ static bool isDisabled(ModifierData *md, int UNUSED(useRenderParams)) return ((!dmd->texture && dmd->direction == MOD_DISP_DIR_RGB_XYZ) || dmd->strength == 0.0f); } -static void updateDepgraph(ModifierData *md, DagForest *forest, - struct Main *UNUSED(bmain), - struct Scene *UNUSED(scene), - Object *UNUSED(ob), - DagNode *obNode) -{ - DisplaceModifierData *dmd = (DisplaceModifierData *) md; - - if (dmd->map_object && dmd->texmapping == MOD_DISP_MAP_OBJECT) { - DagNode *curNode = dag_get_node(forest, dmd->map_object); - - dag_add_relation(forest, curNode, obNode, - DAG_RL_DATA_DATA | DAG_RL_OB_DATA, "Displace Modifier"); - } - - - if (dmd->texmapping == MOD_DISP_MAP_GLOBAL || - (ELEM(dmd->direction, MOD_DISP_DIR_X, MOD_DISP_DIR_Y, MOD_DISP_DIR_Z, MOD_DISP_DIR_RGB_XYZ) && - dmd->space == MOD_DISP_SPACE_GLOBAL)) - { - dag_add_relation(forest, obNode, obNode, - DAG_RL_DATA_DATA | DAG_RL_OB_DATA, "Displace Modifier"); - } -} - static void updateDepsgraph(ModifierData *md, struct Main *UNUSED(bmain), struct Scene *UNUSED(scene), @@ -448,7 +423,6 @@ ModifierTypeInfo modifierType_Displace = { /* requiredDataMask */ requiredDataMask, /* freeData */ freeData, /* isDisabled */ isDisabled, - /* updateDepgraph */ updateDepgraph, /* updateDepsgraph */ updateDepsgraph, /* dependsOnTime */ dependsOnTime, /* dependsOnNormals */ dependsOnNormals, diff --git a/source/blender/modifiers/intern/MOD_dynamicpaint.c b/source/blender/modifiers/intern/MOD_dynamicpaint.c index 05068b9b597..794d8bf6951 100644 --- a/source/blender/modifiers/intern/MOD_dynamicpaint.c +++ b/source/blender/modifiers/intern/MOD_dynamicpaint.c @@ -119,34 +119,6 @@ static bool is_brush_cb(Object *UNUSED(ob), ModifierData *pmd) return ((DynamicPaintModifierData*)pmd)->brush != NULL; } -static void updateDepgraph(ModifierData *md, DagForest *forest, - struct Main *UNUSED(bmain), - struct Scene *scene, - Object *ob, - DagNode *obNode) -{ - DynamicPaintModifierData *pmd = (DynamicPaintModifierData *) md; - - /* add relation from canvases to all brush objects */ - if (pmd && pmd->canvas) { -#ifdef WITH_LEGACY_DEPSGRAPH - for (DynamicPaintSurface *surface = pmd->canvas->surfaces.first; surface; surface = surface->next) { - if (surface->effect & MOD_DPAINT_EFFECT_DO_DRIP) { - dag_add_forcefield_relations(forest, scene, ob, obNode, surface->effector_weights, true, 0, "Dynamic Paint Field"); - } - - /* Actual code uses custom loop over group/scene without layer checks in dynamicPaint_doStep */ - dag_add_collision_relations(forest, scene, ob, obNode, surface->brush_group, -1, eModifierType_DynamicPaint, is_brush_cb, false, "Dynamic Paint Brush"); - } -#else - (void)forest; - (void)scene; - (void)ob; - (void)obNode; -#endif - } -} - static void updateDepsgraph(ModifierData *md, struct Main *UNUSED(bmain), struct Scene *scene, @@ -221,7 +193,6 @@ ModifierTypeInfo modifierType_DynamicPaint = { /* requiredDataMask */ requiredDataMask, /* freeData */ freeData, /* isDisabled */ NULL, - /* updateDepgraph */ updateDepgraph, /* updateDepsgraph */ updateDepsgraph, /* dependsOnTime */ dependsOnTime, /* dependsOnNormals */ NULL, diff --git a/source/blender/modifiers/intern/MOD_edgesplit.c b/source/blender/modifiers/intern/MOD_edgesplit.c index 4441edb299b..f239807a7d3 100644 --- a/source/blender/modifiers/intern/MOD_edgesplit.c +++ b/source/blender/modifiers/intern/MOD_edgesplit.c @@ -157,7 +157,6 @@ ModifierTypeInfo modifierType_EdgeSplit = { /* requiredDataMask */ NULL, /* freeData */ NULL, /* isDisabled */ NULL, - /* updateDepgraph */ NULL, /* updateDepsgraph */ NULL, /* dependsOnTime */ NULL, /* dependsOnNormals */ NULL, diff --git a/source/blender/modifiers/intern/MOD_explode.c b/source/blender/modifiers/intern/MOD_explode.c index ca7b3ce8039..24ce2e3cc8e 100644 --- a/source/blender/modifiers/intern/MOD_explode.c +++ b/source/blender/modifiers/intern/MOD_explode.c @@ -1059,7 +1059,6 @@ ModifierTypeInfo modifierType_Explode = { /* requiredDataMask */ requiredDataMask, /* freeData */ freeData, /* isDisabled */ NULL, - /* updateDepgraph */ NULL, /* updateDepsgraph */ NULL, /* dependsOnTime */ dependsOnTime, /* dependsOnNormals */ NULL, diff --git a/source/blender/modifiers/intern/MOD_fluidsim.c b/source/blender/modifiers/intern/MOD_fluidsim.c index c202c5e1cb4..9e91a76ecb8 100644 --- a/source/blender/modifiers/intern/MOD_fluidsim.c +++ b/source/blender/modifiers/intern/MOD_fluidsim.c @@ -41,6 +41,7 @@ #include "BKE_cdderivedmesh.h" +#include "BKE_layer.h" #include "BKE_modifier.h" #include "depsgraph_private.h" @@ -100,33 +101,6 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *ob, return result ? result : dm; } -static void updateDepgraph( - ModifierData *md, DagForest *forest, - struct Main *UNUSED(bmain), Scene *scene, - Object *ob, DagNode *obNode) -{ - FluidsimModifierData *fluidmd = (FluidsimModifierData *) md; - Base *base; - - if (fluidmd && fluidmd->fss) { - if (fluidmd->fss->type == OB_FLUIDSIM_DOMAIN) { - for (base = scene->base.first; base; base = base->next) { - Object *ob1 = base->object; - if (ob1 != ob) { - FluidsimModifierData *fluidmdtmp = - (FluidsimModifierData *)modifiers_findByType(ob1, eModifierType_Fluidsim); - - /* only put dependencies from NON-DOMAIN fluids in here */ - if (fluidmdtmp && fluidmdtmp->fss && (fluidmdtmp->fss->type != OB_FLUIDSIM_DOMAIN)) { - DagNode *curNode = dag_get_node(forest, ob1); - dag_add_relation(forest, curNode, obNode, DAG_RL_DATA_DATA | DAG_RL_OB_DATA, "Fluidsim Object"); - } - } - } - } - } -} - static void updateDepsgraph(ModifierData *md, struct Main *UNUSED(bmain), struct Scene *scene, @@ -136,9 +110,8 @@ static void updateDepsgraph(ModifierData *md, FluidsimModifierData *fluidmd = (FluidsimModifierData *) md; if (fluidmd && fluidmd->fss) { if (fluidmd->fss->type == OB_FLUIDSIM_DOMAIN) { - Base *base; - for (base = scene->base.first; base; base = base->next) { - Object *ob1 = base->object; + FOREACH_SCENE_OBJECT(scene, ob1) + { if (ob1 != ob) { FluidsimModifierData *fluidmdtmp = (FluidsimModifierData *)modifiers_findByType(ob1, eModifierType_Fluidsim); @@ -149,6 +122,7 @@ static void updateDepsgraph(ModifierData *md, } } } + FOREACH_SCENE_OBJECT_END } } } @@ -180,7 +154,6 @@ ModifierTypeInfo modifierType_Fluidsim = { /* requiredDataMask */ NULL, /* freeData */ freeData, /* isDisabled */ NULL, - /* updateDepgraph */ updateDepgraph, /* updateDepsgraph */ updateDepsgraph, /* dependsOnTime */ dependsOnTime, /* dependsOnNormals */ NULL, diff --git a/source/blender/modifiers/intern/MOD_hook.c b/source/blender/modifiers/intern/MOD_hook.c index 56c494ff3c0..210e91d159a 100644 --- a/source/blender/modifiers/intern/MOD_hook.c +++ b/source/blender/modifiers/intern/MOD_hook.c @@ -118,24 +118,6 @@ static void foreachObjectLink( walk(userData, ob, &hmd->object, IDWALK_CB_NOP); } -static void updateDepgraph(ModifierData *md, DagForest *forest, - struct Main *UNUSED(bmain), - struct Scene *UNUSED(scene), - Object *UNUSED(ob), - DagNode *obNode) -{ - HookModifierData *hmd = (HookModifierData *) md; - - if (hmd->object) { - DagNode *curNode = dag_get_node(forest, hmd->object); - - if (hmd->subtarget[0]) - dag_add_relation(forest, curNode, obNode, DAG_RL_OB_DATA | DAG_RL_DATA_DATA, "Hook Modifier"); - else - dag_add_relation(forest, curNode, obNode, DAG_RL_OB_DATA, "Hook Modifier"); - } -} - static void updateDepsgraph(ModifierData *md, struct Main *UNUSED(bmain), struct Scene *UNUSED(scene), @@ -427,7 +409,6 @@ ModifierTypeInfo modifierType_Hook = { /* requiredDataMask */ requiredDataMask, /* freeData */ freeData, /* isDisabled */ isDisabled, - /* updateDepgraph */ updateDepgraph, /* updateDepsgraph */ updateDepsgraph, /* dependsOnTime */ NULL, /* dependsOnNormals */ NULL, diff --git a/source/blender/modifiers/intern/MOD_laplaciandeform.c b/source/blender/modifiers/intern/MOD_laplaciandeform.c index ce3fdc4bbe8..56a2e217a2a 100644 --- a/source/blender/modifiers/intern/MOD_laplaciandeform.c +++ b/source/blender/modifiers/intern/MOD_laplaciandeform.c @@ -775,7 +775,6 @@ ModifierTypeInfo modifierType_LaplacianDeform = { /* requiredDataMask */ requiredDataMask, /* freeData */ freeData, /* isDisabled */ isDisabled, - /* updateDepgraph */ NULL, /* updateDepsgraph */ NULL, /* dependsOnTime */ NULL, /* dependsOnNormals */ NULL, diff --git a/source/blender/modifiers/intern/MOD_laplaciansmooth.c b/source/blender/modifiers/intern/MOD_laplaciansmooth.c index f1216ff462a..1295a75d9e7 100644 --- a/source/blender/modifiers/intern/MOD_laplaciansmooth.c +++ b/source/blender/modifiers/intern/MOD_laplaciansmooth.c @@ -561,7 +561,6 @@ ModifierTypeInfo modifierType_LaplacianSmooth = { /* requiredDataMask */ required_data_mask, /* freeData */ NULL, /* isDisabled */ is_disabled, - /* updateDepgraph */ NULL, /* updateDepsgraph */ NULL, /* dependsOnTime */ NULL, /* dependsOnNormals */ NULL, diff --git a/source/blender/modifiers/intern/MOD_lattice.c b/source/blender/modifiers/intern/MOD_lattice.c index dc246084dca..2e02ab29d5f 100644 --- a/source/blender/modifiers/intern/MOD_lattice.c +++ b/source/blender/modifiers/intern/MOD_lattice.c @@ -91,22 +91,6 @@ static void foreachObjectLink( walk(userData, ob, &lmd->object, IDWALK_CB_NOP); } -static void updateDepgraph(ModifierData *md, DagForest *forest, - struct Main *UNUSED(bmain), - struct Scene *UNUSED(scene), - Object *UNUSED(ob), - DagNode *obNode) -{ - LatticeModifierData *lmd = (LatticeModifierData *) md; - - if (lmd->object) { - DagNode *latNode = dag_get_node(forest, lmd->object); - - dag_add_relation(forest, latNode, obNode, - DAG_RL_DATA_DATA | DAG_RL_OB_DATA, "Lattice Modifier"); - } -} - static void updateDepsgraph(ModifierData *md, struct Main *UNUSED(bmain), struct Scene *UNUSED(scene), @@ -169,7 +153,6 @@ ModifierTypeInfo modifierType_Lattice = { /* requiredDataMask */ requiredDataMask, /* freeData */ NULL, /* isDisabled */ isDisabled, - /* updateDepgraph */ updateDepgraph, /* updateDepsgraph */ updateDepsgraph, /* dependsOnTime */ NULL, /* dependsOnNormals */ NULL, diff --git a/source/blender/modifiers/intern/MOD_mask.c b/source/blender/modifiers/intern/MOD_mask.c index dcc7fe4d4f1..1c4406e1a4f 100644 --- a/source/blender/modifiers/intern/MOD_mask.c +++ b/source/blender/modifiers/intern/MOD_mask.c @@ -77,24 +77,6 @@ static void foreachObjectLink( walk(userData, ob, &mmd->ob_arm, IDWALK_CB_NOP); } -static void updateDepgraph(ModifierData *md, DagForest *forest, - struct Main *UNUSED(bmain), - struct Scene *UNUSED(scene), - Object *UNUSED(ob), - DagNode *obNode) -{ - MaskModifierData *mmd = (MaskModifierData *)md; - - if (mmd->ob_arm) { - bArmature *arm = (bArmature *)mmd->ob_arm->data; - DagNode *armNode = dag_get_node(forest, mmd->ob_arm); - - /* tag relationship in depsgraph, but also on the armature */ - dag_add_relation(forest, armNode, obNode, DAG_RL_DATA_DATA | DAG_RL_OB_DATA, "Mask Modifier"); - arm->flag |= ARM_HAS_VIZ_DEPS; - } -} - static void updateDepsgraph(ModifierData *md, struct Main *UNUSED(bmain), struct Scene *UNUSED(scene), @@ -401,7 +383,6 @@ ModifierTypeInfo modifierType_Mask = { /* requiredDataMask */ requiredDataMask, /* freeData */ NULL, /* isDisabled */ NULL, - /* updateDepgraph */ updateDepgraph, /* updateDepsgraph */ updateDepsgraph, /* dependsOnTime */ NULL, /* dependsOnNormals */ NULL, diff --git a/source/blender/modifiers/intern/MOD_meshcache.c b/source/blender/modifiers/intern/MOD_meshcache.c index aa3e3ebcf7e..0d96032c515 100644 --- a/source/blender/modifiers/intern/MOD_meshcache.c +++ b/source/blender/modifiers/intern/MOD_meshcache.c @@ -313,7 +313,6 @@ ModifierTypeInfo modifierType_MeshCache = { /* requiredDataMask */ NULL, /* freeData */ NULL, /* isDisabled */ isDisabled, - /* updateDepgraph */ NULL, /* updateDepsgraph */ NULL, /* dependsOnTime */ dependsOnTime, /* dependsOnNormals */ NULL, diff --git a/source/blender/modifiers/intern/MOD_meshdeform.c b/source/blender/modifiers/intern/MOD_meshdeform.c index 406ce398ee0..ed1f5e8938b 100644 --- a/source/blender/modifiers/intern/MOD_meshdeform.c +++ b/source/blender/modifiers/intern/MOD_meshdeform.c @@ -122,23 +122,6 @@ static void foreachObjectLink( walk(userData, ob, &mmd->object, IDWALK_CB_NOP); } -static void updateDepgraph(ModifierData *md, DagForest *forest, - struct Main *UNUSED(bmain), - struct Scene *UNUSED(scene), - Object *UNUSED(ob), - DagNode *obNode) -{ - MeshDeformModifierData *mmd = (MeshDeformModifierData *) md; - - if (mmd->object) { - DagNode *curNode = dag_get_node(forest, mmd->object); - - dag_add_relation(forest, curNode, obNode, - DAG_RL_DATA_DATA | DAG_RL_OB_DATA | DAG_RL_DATA_OB | DAG_RL_OB_OB, - "Mesh Deform Modifier"); - } -} - static void updateDepsgraph(ModifierData *md, struct Main *UNUSED(bmain), struct Scene *UNUSED(scene), @@ -534,7 +517,6 @@ ModifierTypeInfo modifierType_MeshDeform = { /* requiredDataMask */ requiredDataMask, /* freeData */ freeData, /* isDisabled */ isDisabled, - /* updateDepgraph */ updateDepgraph, /* updateDepsgraph */ updateDepsgraph, /* dependsOnTime */ NULL, /* dependsOnNormals */ NULL, diff --git a/source/blender/modifiers/intern/MOD_meshsequencecache.c b/source/blender/modifiers/intern/MOD_meshsequencecache.c index d956763fc1f..0b9298a26a6 100644 --- a/source/blender/modifiers/intern/MOD_meshsequencecache.c +++ b/source/blender/modifiers/intern/MOD_meshsequencecache.c @@ -155,23 +155,6 @@ static void foreachIDLink(ModifierData *md, Object *ob, } -static void updateDepgraph(ModifierData *md, DagForest *forest, - struct Main *bmain, - struct Scene *scene, - Object *ob, DagNode *obNode) -{ - MeshSeqCacheModifierData *mcmd = (MeshSeqCacheModifierData *) md; - - if (mcmd->cache_file != NULL) { - DagNode *curNode = dag_get_node(forest, mcmd->cache_file); - - dag_add_relation(forest, curNode, obNode, - DAG_RL_DATA_DATA | DAG_RL_OB_DATA, "Cache File Modifier"); - } - - UNUSED_VARS(bmain, scene, ob); -} - static void updateDepsgraph(ModifierData *md, struct Main *bmain, struct Scene *scene, @@ -205,7 +188,6 @@ ModifierTypeInfo modifierType_MeshSequenceCache = { /* requiredDataMask */ NULL, /* freeData */ freeData, /* isDisabled */ isDisabled, - /* updateDepgraph */ updateDepgraph, /* updateDepsgraph */ updateDepsgraph, /* dependsOnTime */ dependsOnTime, /* dependsOnNormals */ NULL, diff --git a/source/blender/modifiers/intern/MOD_mirror.c b/source/blender/modifiers/intern/MOD_mirror.c index dd127cc255c..8c01c560e75 100644 --- a/source/blender/modifiers/intern/MOD_mirror.c +++ b/source/blender/modifiers/intern/MOD_mirror.c @@ -75,21 +75,6 @@ static void foreachObjectLink( walk(userData, ob, &mmd->mirror_ob, IDWALK_CB_NOP); } -static void updateDepgraph(ModifierData *md, DagForest *forest, - struct Main *UNUSED(bmain), - struct Scene *UNUSED(scene), - Object *UNUSED(ob), - DagNode *obNode) -{ - MirrorModifierData *mmd = (MirrorModifierData *) md; - - if (mmd->mirror_ob) { - DagNode *latNode = dag_get_node(forest, mmd->mirror_ob); - - dag_add_relation(forest, latNode, obNode, DAG_RL_OB_DATA, "Mirror Modifier"); - } -} - static void updateDepsgraph(ModifierData *md, struct Main *UNUSED(bmain), struct Scene *UNUSED(scene), @@ -375,7 +360,6 @@ ModifierTypeInfo modifierType_Mirror = { /* requiredDataMask */ NULL, /* freeData */ NULL, /* isDisabled */ NULL, - /* updateDepgraph */ updateDepgraph, /* updateDepsgraph */ updateDepsgraph, /* dependsOnTime */ NULL, /* dependsOnNormals */ NULL, diff --git a/source/blender/modifiers/intern/MOD_multires.c b/source/blender/modifiers/intern/MOD_multires.c index 90ad1bdfdc2..aba184b7d40 100644 --- a/source/blender/modifiers/intern/MOD_multires.c +++ b/source/blender/modifiers/intern/MOD_multires.c @@ -161,7 +161,6 @@ ModifierTypeInfo modifierType_Multires = { /* requiredDataMask */ NULL, /* freeData */ NULL, /* isDisabled */ NULL, - /* updateDepgraph */ NULL, /* updateDepsgraph */ NULL, /* dependsOnTime */ NULL, /* dependsOnNormals */ NULL, diff --git a/source/blender/modifiers/intern/MOD_none.c b/source/blender/modifiers/intern/MOD_none.c index d9d9ba2966d..3fb780f566d 100644 --- a/source/blender/modifiers/intern/MOD_none.c +++ b/source/blender/modifiers/intern/MOD_none.c @@ -67,7 +67,6 @@ ModifierTypeInfo modifierType_None = { /* requiredDataMask */ NULL, /* freeData */ NULL, /* isDisabled */ isDisabled, - /* updateDepgraph */ NULL, /* updateDepsgraph */ NULL, /* dependsOnTime */ NULL, /* dependsOnNormals */ NULL, diff --git a/source/blender/modifiers/intern/MOD_normal_edit.c b/source/blender/modifiers/intern/MOD_normal_edit.c index 20eae751ca4..b73f1074bc1 100644 --- a/source/blender/modifiers/intern/MOD_normal_edit.c +++ b/source/blender/modifiers/intern/MOD_normal_edit.c @@ -511,20 +511,6 @@ static bool isDisabled(ModifierData *md, int UNUSED(useRenderParams)) return !is_valid_target(enmd); } -static void updateDepgraph(ModifierData *md, DagForest *forest, - struct Main *UNUSED(bmain), - struct Scene *UNUSED(scene), - Object *UNUSED(ob), DagNode *obNode) -{ - NormalEditModifierData *enmd = (NormalEditModifierData *) md; - - if (enmd->target) { - DagNode *Node = dag_get_node(forest, enmd->target); - - dag_add_relation(forest, Node, obNode, DAG_RL_OB_DATA, "NormalEdit Modifier"); - } -} - static void updateDepsgraph(ModifierData *md, struct Main *UNUSED(bmain), struct Scene *UNUSED(scene), @@ -562,7 +548,6 @@ ModifierTypeInfo modifierType_NormalEdit = { /* requiredDataMask */ requiredDataMask, /* freeData */ NULL, /* isDisabled */ isDisabled, - /* updateDepgraph */ updateDepgraph, /* updateDepsgraph */ updateDepsgraph, /* dependsOnTime */ NULL, /* dependsOnNormals */ dependsOnNormals, diff --git a/source/blender/modifiers/intern/MOD_ocean.c b/source/blender/modifiers/intern/MOD_ocean.c index e77cc655c16..1be603c7ab5 100644 --- a/source/blender/modifiers/intern/MOD_ocean.c +++ b/source/blender/modifiers/intern/MOD_ocean.c @@ -597,7 +597,6 @@ ModifierTypeInfo modifierType_Ocean = { /* requiredDataMask */ requiredDataMask, /* freeData */ freeData, /* isDisabled */ NULL, - /* updateDepgraph */ NULL, /* updateDepsgraph */ NULL, /* dependsOnTime */ NULL, /* dependsOnNormals */ dependsOnNormals, diff --git a/source/blender/modifiers/intern/MOD_particleinstance.c b/source/blender/modifiers/intern/MOD_particleinstance.c index fbf5a958254..9d8e1e181a4 100644 --- a/source/blender/modifiers/intern/MOD_particleinstance.c +++ b/source/blender/modifiers/intern/MOD_particleinstance.c @@ -110,24 +110,6 @@ static bool isDisabled(ModifierData *md, int useRenderParams) return false; } - -static void updateDepgraph(ModifierData *md, DagForest *forest, - struct Main *UNUSED(bmain), - struct Scene *UNUSED(scene), - Object *UNUSED(ob), - DagNode *obNode) -{ - ParticleInstanceModifierData *pimd = (ParticleInstanceModifierData *) md; - - if (pimd->ob) { - DagNode *curNode = dag_get_node(forest, pimd->ob); - - dag_add_relation(forest, curNode, obNode, - DAG_RL_DATA_DATA | DAG_RL_OB_DATA, - "Particle Instance Modifier"); - } -} - static void updateDepsgraph(ModifierData *md, struct Main *UNUSED(bmain), struct Scene *UNUSED(scene), @@ -460,7 +442,6 @@ ModifierTypeInfo modifierType_ParticleInstance = { /* requiredDataMask */ NULL, /* freeData */ NULL, /* isDisabled */ isDisabled, - /* updateDepgraph */ updateDepgraph, /* updateDepsgraph */ updateDepsgraph, /* dependsOnTime */ NULL, /* dependsOnNormals */ NULL, diff --git a/source/blender/modifiers/intern/MOD_particlesystem.c b/source/blender/modifiers/intern/MOD_particlesystem.c index d8cccca415c..a3b9d808b17 100644 --- a/source/blender/modifiers/intern/MOD_particlesystem.c +++ b/source/blender/modifiers/intern/MOD_particlesystem.c @@ -231,7 +231,6 @@ ModifierTypeInfo modifierType_ParticleSystem = { /* requiredDataMask */ requiredDataMask, /* freeData */ freeData, /* isDisabled */ NULL, - /* updateDepgraph */ NULL, /* updateDepsgraph */ NULL, /* dependsOnTime */ NULL, /* dependsOnNormals */ NULL, diff --git a/source/blender/modifiers/intern/MOD_remesh.c b/source/blender/modifiers/intern/MOD_remesh.c index b85898c07e9..fb5c12399a4 100644 --- a/source/blender/modifiers/intern/MOD_remesh.c +++ b/source/blender/modifiers/intern/MOD_remesh.c @@ -231,7 +231,6 @@ ModifierTypeInfo modifierType_Remesh = { /* requiredDataMask */ NULL, /* freeData */ NULL, /* isDisabled */ NULL, - /* updateDepgraph */ NULL, /* updateDepsgraph */ NULL, /* dependsOnTime */ NULL, /* dependsOnNormals */ NULL, diff --git a/source/blender/modifiers/intern/MOD_screw.c b/source/blender/modifiers/intern/MOD_screw.c index 87859cd240a..1273a3a6e09 100644 --- a/source/blender/modifiers/intern/MOD_screw.c +++ b/source/blender/modifiers/intern/MOD_screw.c @@ -1057,24 +1057,6 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *ob, return result; } - -static void updateDepgraph(ModifierData *md, DagForest *forest, - struct Main *UNUSED(bmain), - struct Scene *UNUSED(scene), - Object *UNUSED(ob), - DagNode *obNode) -{ - ScrewModifierData *ltmd = (ScrewModifierData *) md; - - if (ltmd->ob_axis) { - DagNode *curNode = dag_get_node(forest, ltmd->ob_axis); - - dag_add_relation(forest, curNode, obNode, - DAG_RL_DATA_DATA | DAG_RL_OB_DATA, - "Screw Modifier"); - } -} - static void updateDepsgraph(ModifierData *md, struct Main *UNUSED(bmain), struct Scene *UNUSED(scene), @@ -1118,7 +1100,6 @@ ModifierTypeInfo modifierType_Screw = { /* requiredDataMask */ NULL, /* freeData */ NULL, /* isDisabled */ NULL, - /* updateDepgraph */ updateDepgraph, /* updateDepsgraph */ updateDepsgraph, /* dependsOnTime */ NULL, /* dependsOnNormals */ NULL, diff --git a/source/blender/modifiers/intern/MOD_shapekey.c b/source/blender/modifiers/intern/MOD_shapekey.c index 97aae733532..6c8bd06c196 100644 --- a/source/blender/modifiers/intern/MOD_shapekey.c +++ b/source/blender/modifiers/intern/MOD_shapekey.c @@ -138,7 +138,6 @@ ModifierTypeInfo modifierType_ShapeKey = { /* requiredDataMask */ NULL, /* freeData */ NULL, /* isDisabled */ NULL, - /* updateDepgraph */ NULL, /* updateDepsgraph */ NULL, /* dependsOnTime */ NULL, /* dependsOnNormals */ NULL, diff --git a/source/blender/modifiers/intern/MOD_shrinkwrap.c b/source/blender/modifiers/intern/MOD_shrinkwrap.c index a14747bc153..d6d8c931c35 100644 --- a/source/blender/modifiers/intern/MOD_shrinkwrap.c +++ b/source/blender/modifiers/intern/MOD_shrinkwrap.c @@ -143,23 +143,6 @@ static void deformVertsEM(ModifierData *md, Object *ob, struct BMEditMesh *editD dm->release(dm); } -static void updateDepgraph(ModifierData *md, DagForest *forest, - struct Main *UNUSED(bmain), - struct Scene *UNUSED(scene), - Object *UNUSED(ob), - DagNode *obNode) -{ - ShrinkwrapModifierData *smd = (ShrinkwrapModifierData *) md; - - if (smd->target) - dag_add_relation(forest, dag_get_node(forest, smd->target), obNode, - DAG_RL_OB_DATA | DAG_RL_DATA_DATA, "Shrinkwrap Modifier"); - - if (smd->auxTarget) - dag_add_relation(forest, dag_get_node(forest, smd->auxTarget), obNode, - DAG_RL_OB_DATA | DAG_RL_DATA_DATA, "Shrinkwrap Modifier"); -} - static void updateDepsgraph(ModifierData *md, struct Main *UNUSED(bmain), struct Scene *UNUSED(scene), @@ -209,7 +192,6 @@ ModifierTypeInfo modifierType_Shrinkwrap = { /* requiredDataMask */ requiredDataMask, /* freeData */ NULL, /* isDisabled */ isDisabled, - /* updateDepgraph */ updateDepgraph, /* updateDepsgraph */ updateDepsgraph, /* dependsOnTime */ NULL, /* dependsOnNormals */ dependsOnNormals, diff --git a/source/blender/modifiers/intern/MOD_simpledeform.c b/source/blender/modifiers/intern/MOD_simpledeform.c index 379eaea5b0c..7c12de9059e 100644 --- a/source/blender/modifiers/intern/MOD_simpledeform.c +++ b/source/blender/modifiers/intern/MOD_simpledeform.c @@ -293,18 +293,6 @@ static void foreachObjectLink( walk(userData, ob, &smd->origin, IDWALK_CB_NOP); } -static void updateDepgraph(ModifierData *md, DagForest *forest, - struct Main *UNUSED(bmain), - struct Scene *UNUSED(scene), - Object *UNUSED(ob), - DagNode *obNode) -{ - SimpleDeformModifierData *smd = (SimpleDeformModifierData *)md; - - if (smd->origin) - dag_add_relation(forest, dag_get_node(forest, smd->origin), obNode, DAG_RL_OB_DATA, "SimpleDeform Modifier"); -} - static void updateDepsgraph(ModifierData *md, struct Main *UNUSED(bmain), struct Scene *UNUSED(scene), @@ -381,7 +369,6 @@ ModifierTypeInfo modifierType_SimpleDeform = { /* requiredDataMask */ requiredDataMask, /* freeData */ NULL, /* isDisabled */ NULL, - /* updateDepgraph */ updateDepgraph, /* updateDepsgraph */ updateDepsgraph, /* dependsOnTime */ NULL, /* dependsOnNormals */ NULL, diff --git a/source/blender/modifiers/intern/MOD_skin.c b/source/blender/modifiers/intern/MOD_skin.c index 8ed623734be..4b84aeb335a 100644 --- a/source/blender/modifiers/intern/MOD_skin.c +++ b/source/blender/modifiers/intern/MOD_skin.c @@ -1950,7 +1950,6 @@ ModifierTypeInfo modifierType_Skin = { /* requiredDataMask */ requiredDataMask, /* freeData */ NULL, /* isDisabled */ NULL, - /* updateDepgraph */ NULL, /* updateDepsgraph */ NULL, /* dependsOnTime */ NULL, /* dependsOnNormals */ NULL, diff --git a/source/blender/modifiers/intern/MOD_smoke.c b/source/blender/modifiers/intern/MOD_smoke.c index c105a3ab3a7..8ba39819b5e 100644 --- a/source/blender/modifiers/intern/MOD_smoke.c +++ b/source/blender/modifiers/intern/MOD_smoke.c @@ -129,28 +129,6 @@ static bool is_coll_cb(Object *UNUSED(ob), ModifierData *md) return (smd->type & MOD_SMOKE_TYPE_COLL) && smd->coll; } -static void updateDepgraph(ModifierData *md, DagForest *forest, - struct Main *UNUSED(bmain), - struct Scene *scene, struct Object *ob, - DagNode *obNode) -{ - SmokeModifierData *smd = (SmokeModifierData *) md; - - if (smd && (smd->type & MOD_SMOKE_TYPE_DOMAIN) && smd->domain) { - /* Actual code uses get_collisionobjects */ -#ifdef WITH_LEGACY_DEPSGRAPH - dag_add_collision_relations(forest, scene, ob, obNode, smd->domain->fluid_group, ob->lay|scene->lay, eModifierType_Smoke, is_flow_cb, true, "Smoke Flow"); - dag_add_collision_relations(forest, scene, ob, obNode, smd->domain->coll_group, ob->lay|scene->lay, eModifierType_Smoke, is_coll_cb, true, "Smoke Coll"); - dag_add_forcefield_relations(forest, scene, ob, obNode, smd->domain->effector_weights, true, PFIELD_SMOKEFLOW, "Smoke Force Field"); -#else - (void)forest; - (void)scene; - (void)ob; - (void)obNode; -#endif - } -} - static void updateDepsgraph(ModifierData *md, struct Main *UNUSED(bmain), struct Scene *scene, @@ -208,7 +186,6 @@ ModifierTypeInfo modifierType_Smoke = { /* requiredDataMask */ requiredDataMask, /* freeData */ freeData, /* isDisabled */ NULL, - /* updateDepgraph */ updateDepgraph, /* updateDepsgraph */ updateDepsgraph, /* dependsOnTime */ dependsOnTime, /* dependsOnNormals */ NULL, diff --git a/source/blender/modifiers/intern/MOD_smooth.c b/source/blender/modifiers/intern/MOD_smooth.c index d45c8528510..f0f20acb8ea 100644 --- a/source/blender/modifiers/intern/MOD_smooth.c +++ b/source/blender/modifiers/intern/MOD_smooth.c @@ -261,7 +261,6 @@ ModifierTypeInfo modifierType_Smooth = { /* requiredDataMask */ requiredDataMask, /* freeData */ NULL, /* isDisabled */ isDisabled, - /* updateDepgraph */ NULL, /* updateDepsgraph */ NULL, /* dependsOnTime */ NULL, /* dependsOnNormals */ NULL, diff --git a/source/blender/modifiers/intern/MOD_softbody.c b/source/blender/modifiers/intern/MOD_softbody.c index a0bbe5da04a..412f0a3ce53 100644 --- a/source/blender/modifiers/intern/MOD_softbody.c +++ b/source/blender/modifiers/intern/MOD_softbody.c @@ -62,25 +62,6 @@ static bool dependsOnTime(ModifierData *UNUSED(md)) return true; } -static void updateDepgraph(ModifierData *UNUSED(md), DagForest *forest, - struct Main *UNUSED(bmain), - Scene *scene, Object *ob, DagNode *obNode) -{ - if (ob->soft) { -#ifdef WITH_LEGACY_DEPSGRAPH - /* Actual code uses ccd_build_deflector_hash */ - dag_add_collision_relations(forest, scene, ob, obNode, ob->soft->collision_group, ob->lay, eModifierType_Collision, NULL, false, "Softbody Collision"); - - dag_add_forcefield_relations(forest, scene, ob, obNode, ob->soft->effector_weights, true, 0, "Softbody Field"); -#else - (void)forest; - (void)scene; - (void)ob; - (void)obNode; -#endif - } -} - static void updateDepsgraph(ModifierData *UNUSED(md), struct Main *UNUSED(bmain), struct Scene *scene, @@ -116,7 +97,6 @@ ModifierTypeInfo modifierType_Softbody = { /* requiredDataMask */ NULL, /* freeData */ NULL, /* isDisabled */ NULL, - /* updateDepgraph */ updateDepgraph, /* updateDepsgraph */ updateDepsgraph, /* dependsOnTime */ dependsOnTime, /* dependsOnNormals */ NULL, diff --git a/source/blender/modifiers/intern/MOD_solidify.c b/source/blender/modifiers/intern/MOD_solidify.c index 911b6997058..e589cb7d713 100644 --- a/source/blender/modifiers/intern/MOD_solidify.c +++ b/source/blender/modifiers/intern/MOD_solidify.c @@ -973,7 +973,6 @@ ModifierTypeInfo modifierType_Solidify = { /* requiredDataMask */ requiredDataMask, /* freeData */ NULL, /* isDisabled */ NULL, - /* updateDepgraph */ NULL, /* updateDepsgraph */ NULL, /* dependsOnTime */ NULL, /* dependsOnNormals */ dependsOnNormals, diff --git a/source/blender/modifiers/intern/MOD_subsurf.c b/source/blender/modifiers/intern/MOD_subsurf.c index 8711384e1ee..af3ffb820c1 100644 --- a/source/blender/modifiers/intern/MOD_subsurf.c +++ b/source/blender/modifiers/intern/MOD_subsurf.c @@ -211,7 +211,6 @@ ModifierTypeInfo modifierType_Subsurf = { /* requiredDataMask */ NULL, /* freeData */ freeData, /* isDisabled */ isDisabled, - /* updateDepgraph */ NULL, /* updateDepsgraph */ NULL, /* dependsOnTime */ NULL, /* dependsOnNormals */ dependsOnNormals, diff --git a/source/blender/modifiers/intern/MOD_surface.c b/source/blender/modifiers/intern/MOD_surface.c index 68987a1d28e..fc02a2e1327 100644 --- a/source/blender/modifiers/intern/MOD_surface.c +++ b/source/blender/modifiers/intern/MOD_surface.c @@ -185,7 +185,6 @@ ModifierTypeInfo modifierType_Surface = { /* requiredDataMask */ NULL, /* freeData */ freeData, /* isDisabled */ NULL, - /* updateDepgraph */ NULL, /* updateDepsgraph */ NULL, /* dependsOnTime */ dependsOnTime, /* dependsOnNormals */ NULL, diff --git a/source/blender/modifiers/intern/MOD_triangulate.c b/source/blender/modifiers/intern/MOD_triangulate.c index 6fad2756f82..a5d826a69ba 100644 --- a/source/blender/modifiers/intern/MOD_triangulate.c +++ b/source/blender/modifiers/intern/MOD_triangulate.c @@ -118,7 +118,6 @@ ModifierTypeInfo modifierType_Triangulate = { /* requiredDataMask */ NULL, //requiredDataMask, /* freeData */ NULL, /* isDisabled */ NULL, - /* updateDepgraph */ NULL, /* updateDepsgraph */ NULL, /* dependsOnTime */ NULL, /* dependsOnNormals */ NULL, diff --git a/source/blender/modifiers/intern/MOD_uvproject.c b/source/blender/modifiers/intern/MOD_uvproject.c index 78dc1ea8bcb..fdbf4f47ce8 100644 --- a/source/blender/modifiers/intern/MOD_uvproject.c +++ b/source/blender/modifiers/intern/MOD_uvproject.c @@ -105,25 +105,6 @@ static void foreachIDLink(ModifierData *md, Object *ob, foreachObjectLink(md, ob, (ObjectWalkFunc)walk, userData); } -static void updateDepgraph(ModifierData *md, DagForest *forest, - struct Main *UNUSED(bmain), - struct Scene *UNUSED(scene), - Object *UNUSED(ob), - DagNode *obNode) -{ - UVProjectModifierData *umd = (UVProjectModifierData *) md; - int i; - - for (i = 0; i < umd->num_projectors; ++i) { - if (umd->projectors[i]) { - DagNode *curNode = dag_get_node(forest, umd->projectors[i]); - - dag_add_relation(forest, curNode, obNode, - DAG_RL_DATA_DATA | DAG_RL_OB_DATA, "UV Project Modifier"); - } - } -} - static void updateDepsgraph(ModifierData *md, struct Main *UNUSED(bmain), struct Scene *UNUSED(scene), @@ -385,7 +366,6 @@ ModifierTypeInfo modifierType_UVProject = { /* requiredDataMask */ requiredDataMask, /* freeData */ NULL, /* isDisabled */ NULL, - /* updateDepgraph */ updateDepgraph, /* updateDepsgraph */ updateDepsgraph, /* dependsOnTime */ NULL, /* dependsOnNormals */ NULL, diff --git a/source/blender/modifiers/intern/MOD_uvwarp.c b/source/blender/modifiers/intern/MOD_uvwarp.c index b3fc3842635..00ef6dd9733 100644 --- a/source/blender/modifiers/intern/MOD_uvwarp.c +++ b/source/blender/modifiers/intern/MOD_uvwarp.c @@ -225,7 +225,7 @@ static void foreachObjectLink(ModifierData *md, Object *ob, ObjectWalkFunc walk, walk(userData, ob, &umd->object_src, IDWALK_CB_NOP); } -static void uv_warp_deps_object_bone(DagForest *forest, DagNode *obNode, +static void UNUSED_FUNCTION(uv_warp_deps_object_bone)(DagForest *forest, DagNode *obNode, Object *obj, const char *bonename) { if (obj) { @@ -238,18 +238,6 @@ static void uv_warp_deps_object_bone(DagForest *forest, DagNode *obNode, } } -static void updateDepgraph(ModifierData *md, DagForest *forest, - struct Main *UNUSED(bmain), - struct Scene *UNUSED(scene), - Object *UNUSED(ob), - DagNode *obNode) -{ - UVWarpModifierData *umd = (UVWarpModifierData *) md; - - uv_warp_deps_object_bone(forest, obNode, umd->object_src, umd->bone_src); - uv_warp_deps_object_bone(forest, obNode, umd->object_dst, umd->bone_dst); -} - static void uv_warp_deps_object_bone_new(struct DepsNodeHandle *node, Object *object, const char *bonename) @@ -293,7 +281,6 @@ ModifierTypeInfo modifierType_UVWarp = { /* requiredDataMask */ requiredDataMask, /* freeData */ NULL, /* isDisabled */ NULL, - /* updateDepgraph */ updateDepgraph, /* updateDepsgraph */ updateDepsgraph, /* dependsOnTime */ NULL, /* dependsOnNormals */ NULL, diff --git a/source/blender/modifiers/intern/MOD_warp.c b/source/blender/modifiers/intern/MOD_warp.c index 92d44257d03..8c6b94e5c79 100644 --- a/source/blender/modifiers/intern/MOD_warp.c +++ b/source/blender/modifiers/intern/MOD_warp.c @@ -135,27 +135,6 @@ static void foreachTexLink(ModifierData *md, Object *ob, TexWalkFunc walk, void walk(userData, ob, md, "texture"); } -static void updateDepgraph(ModifierData *md, DagForest *forest, - struct Main *UNUSED(bmain), - struct Scene *UNUSED(scene), - Object *UNUSED(ob), DagNode *obNode) -{ - WarpModifierData *wmd = (WarpModifierData *) md; - - if (wmd->object_from && wmd->object_to) { - DagNode *fromNode = dag_get_node(forest, wmd->object_from); - DagNode *toNode = dag_get_node(forest, wmd->object_to); - - dag_add_relation(forest, fromNode, obNode, DAG_RL_DATA_DATA | DAG_RL_OB_DATA, "Warp Modifier1"); - dag_add_relation(forest, toNode, obNode, DAG_RL_DATA_DATA | DAG_RL_OB_DATA, "Warp Modifier2"); - } - - if ((wmd->texmapping == MOD_DISP_MAP_OBJECT) && wmd->map_object) { - DagNode *curNode = dag_get_node(forest, wmd->map_object); - dag_add_relation(forest, curNode, obNode, DAG_RL_DATA_DATA | DAG_RL_OB_DATA, "Warp Modifier3"); - } -} - static void updateDepsgraph(ModifierData *md, struct Main *UNUSED(bmain), struct Scene *UNUSED(scene), @@ -387,7 +366,6 @@ ModifierTypeInfo modifierType_Warp = { /* requiredDataMask */ requiredDataMask, /* freeData */ freeData, /* isDisabled */ isDisabled, - /* updateDepgraph */ updateDepgraph, /* updateDepsgraph */ updateDepsgraph, /* dependsOnTime */ dependsOnTime, /* dependsOnNormals */ NULL, diff --git a/source/blender/modifiers/intern/MOD_wave.c b/source/blender/modifiers/intern/MOD_wave.c index f0c4940816e..a60607cf372 100644 --- a/source/blender/modifiers/intern/MOD_wave.c +++ b/source/blender/modifiers/intern/MOD_wave.c @@ -131,29 +131,6 @@ static void foreachTexLink(ModifierData *md, Object *ob, walk(userData, ob, md, "texture"); } -static void updateDepgraph(ModifierData *md, DagForest *forest, - struct Main *UNUSED(bmain), - Scene *UNUSED(scene), - Object *UNUSED(ob), - DagNode *obNode) -{ - WaveModifierData *wmd = (WaveModifierData *) md; - - if (wmd->objectcenter) { - DagNode *curNode = dag_get_node(forest, wmd->objectcenter); - - dag_add_relation(forest, curNode, obNode, DAG_RL_OB_DATA, - "Wave Modifier"); - } - - if (wmd->map_object) { - DagNode *curNode = dag_get_node(forest, wmd->map_object); - - dag_add_relation(forest, curNode, obNode, DAG_RL_OB_DATA, - "Wave Modifer"); - } -} - static void updateDepsgraph(ModifierData *md, struct Main *UNUSED(bmain), struct Scene *UNUSED(scene), @@ -397,7 +374,6 @@ ModifierTypeInfo modifierType_Wave = { /* requiredDataMask */ requiredDataMask, /* freeData */ freeData, /* isDisabled */ NULL, - /* updateDepgraph */ updateDepgraph, /* updateDepsgraph */ updateDepsgraph, /* dependsOnTime */ dependsOnTime, /* dependsOnNormals */ NULL, diff --git a/source/blender/modifiers/intern/MOD_weightvgedit.c b/source/blender/modifiers/intern/MOD_weightvgedit.c index 2a822ac07b5..57a10a24411 100644 --- a/source/blender/modifiers/intern/MOD_weightvgedit.c +++ b/source/blender/modifiers/intern/MOD_weightvgedit.c @@ -143,26 +143,6 @@ static void foreachTexLink(ModifierData *md, Object *ob, TexWalkFunc walk, void walk(userData, ob, md, "mask_texture"); } -static void updateDepgraph(ModifierData *md, DagForest *forest, - struct Main *UNUSED(bmain), - struct Scene *UNUSED(scene), - Object *UNUSED(ob), DagNode *obNode) -{ - WeightVGEditModifierData *wmd = (WeightVGEditModifierData *) md; - DagNode *curNode; - - if (wmd->mask_tex_map_obj && wmd->mask_tex_mapping == MOD_DISP_MAP_OBJECT) { - curNode = dag_get_node(forest, wmd->mask_tex_map_obj); - - dag_add_relation(forest, curNode, obNode, DAG_RL_DATA_DATA | DAG_RL_OB_DATA, - "WeightVGEdit Modifier"); - } - - if (wmd->mask_tex_mapping == MOD_DISP_MAP_GLOBAL) - dag_add_relation(forest, obNode, obNode, DAG_RL_DATA_DATA | DAG_RL_OB_DATA, - "WeightVGEdit Modifier"); -} - static void updateDepsgraph(ModifierData *md, struct Main *UNUSED(bmain), struct Scene *UNUSED(scene), @@ -307,7 +287,6 @@ ModifierTypeInfo modifierType_WeightVGEdit = { /* requiredDataMask */ requiredDataMask, /* freeData */ freeData, /* isDisabled */ isDisabled, - /* updateDepgraph */ updateDepgraph, /* updateDepsgraph */ updateDepsgraph, /* dependsOnTime */ dependsOnTime, /* dependsOnNormals */ NULL, diff --git a/source/blender/modifiers/intern/MOD_weightvgmix.c b/source/blender/modifiers/intern/MOD_weightvgmix.c index 9bff7bf11f1..9ab8fb4e0ff 100644 --- a/source/blender/modifiers/intern/MOD_weightvgmix.c +++ b/source/blender/modifiers/intern/MOD_weightvgmix.c @@ -192,26 +192,6 @@ static void foreachTexLink(ModifierData *md, Object *ob, TexWalkFunc walk, void walk(userData, ob, md, "mask_texture"); } -static void updateDepgraph(ModifierData *md, DagForest *forest, - struct Main *UNUSED(bmain), - struct Scene *UNUSED(scene), - Object *UNUSED(ob), DagNode *obNode) -{ - WeightVGMixModifierData *wmd = (WeightVGMixModifierData *) md; - DagNode *curNode; - - if (wmd->mask_tex_map_obj && wmd->mask_tex_mapping == MOD_DISP_MAP_OBJECT) { - curNode = dag_get_node(forest, wmd->mask_tex_map_obj); - - dag_add_relation(forest, curNode, obNode, DAG_RL_DATA_DATA | DAG_RL_OB_DATA, - "WeightVGMix Modifier"); - } - - if (wmd->mask_tex_mapping == MOD_DISP_MAP_GLOBAL) - dag_add_relation(forest, obNode, obNode, DAG_RL_DATA_DATA | DAG_RL_OB_DATA, - "WeightVGMix Modifier"); -} - static void updateDepsgraph(ModifierData *md, struct Main *UNUSED(bmain), struct Scene *UNUSED(scene), @@ -439,7 +419,6 @@ ModifierTypeInfo modifierType_WeightVGMix = { /* requiredDataMask */ requiredDataMask, /* freeData */ freeData, /* isDisabled */ isDisabled, - /* updateDepgraph */ updateDepgraph, /* updateDepsgraph */ updateDepsgraph, /* dependsOnTime */ dependsOnTime, /* dependsOnNormals */ NULL, diff --git a/source/blender/modifiers/intern/MOD_weightvgproximity.c b/source/blender/modifiers/intern/MOD_weightvgproximity.c index 2c87838aeab..126a1f951ca 100644 --- a/source/blender/modifiers/intern/MOD_weightvgproximity.c +++ b/source/blender/modifiers/intern/MOD_weightvgproximity.c @@ -343,32 +343,6 @@ static void foreachTexLink(ModifierData *md, Object *ob, TexWalkFunc walk, void walk(userData, ob, md, "mask_texture"); } -static void updateDepgraph(ModifierData *md, DagForest *forest, - struct Main *UNUSED(bmain), - struct Scene *UNUSED(scene), - Object *UNUSED(ob), DagNode *obNode) -{ - WeightVGProximityModifierData *wmd = (WeightVGProximityModifierData *) md; - DagNode *curNode; - - if (wmd->proximity_ob_target) { - curNode = dag_get_node(forest, wmd->proximity_ob_target); - dag_add_relation(forest, curNode, obNode, DAG_RL_DATA_DATA | DAG_RL_OB_DATA, - "WeightVGProximity Modifier"); - } - - if (wmd->mask_tex_map_obj && wmd->mask_tex_mapping == MOD_DISP_MAP_OBJECT) { - curNode = dag_get_node(forest, wmd->mask_tex_map_obj); - - dag_add_relation(forest, curNode, obNode, DAG_RL_DATA_DATA | DAG_RL_OB_DATA, - "WeightVGProximity Modifier"); - } - - if (wmd->mask_tex_mapping == MOD_DISP_MAP_GLOBAL) - dag_add_relation(forest, obNode, obNode, DAG_RL_DATA_DATA | DAG_RL_OB_DATA, - "WeightVGProximity Modifier"); -} - static void updateDepsgraph(ModifierData *md, struct Main *UNUSED(bmain), struct Scene *UNUSED(scene), @@ -617,7 +591,6 @@ ModifierTypeInfo modifierType_WeightVGProximity = { /* requiredDataMask */ requiredDataMask, /* freeData */ freeData, /* isDisabled */ isDisabled, - /* updateDepgraph */ updateDepgraph, /* updateDepsgraph */ updateDepsgraph, /* dependsOnTime */ dependsOnTime, /* dependsOnNormals */ NULL, diff --git a/source/blender/modifiers/intern/MOD_wireframe.c b/source/blender/modifiers/intern/MOD_wireframe.c index adadd4834d4..0c295f91012 100644 --- a/source/blender/modifiers/intern/MOD_wireframe.c +++ b/source/blender/modifiers/intern/MOD_wireframe.c @@ -132,7 +132,6 @@ ModifierTypeInfo modifierType_Wireframe = { /* requiredDataMask */ requiredDataMask, /* freeData */ NULL, /* isDisabled */ isDisabled, - /* updateDepgraph */ NULL, /* updateDepsgraph */ NULL, /* dependsOnTime */ NULL, /* dependsOnNormals */ dependsOnNormals, diff --git a/source/blender/python/generic/bgl.c b/source/blender/python/generic/bgl.c index 3ea10228ad4..1fc575480dc 100644 --- a/source/blender/python/generic/bgl.c +++ b/source/blender/python/generic/bgl.c @@ -1687,9 +1687,6 @@ static void py_module_dict_add_method(PyObject *submodule, PyObject *dict, PyMet } } -/* TODO, expose to users */ -static bool use_deprecated = true; - PyObject *BPyInit_bgl(void) { PyObject *submodule, *dict; @@ -1764,268 +1761,6 @@ PyObject *BPyInit_bgl(void) PY_MOD_ADD_METHOD(TexParameteriv); PY_MOD_ADD_METHOD(Viewport); } - /* adding in GL_VERSION_1_0 removed from core profile */ - if (use_deprecated == true) { - PY_MOD_ADD_METHOD(Accum); - PY_MOD_ADD_METHOD(AlphaFunc); - PY_MOD_ADD_METHOD(Begin); - PY_MOD_ADD_METHOD(Bitmap); - PY_MOD_ADD_METHOD(CallList); - PY_MOD_ADD_METHOD(CallLists); - PY_MOD_ADD_METHOD(ClearAccum); - PY_MOD_ADD_METHOD(ClearIndex); - PY_MOD_ADD_METHOD(ClipPlane); - PY_MOD_ADD_METHOD(Color3b); - PY_MOD_ADD_METHOD(Color3bv); - PY_MOD_ADD_METHOD(Color3d); - PY_MOD_ADD_METHOD(Color3dv); - PY_MOD_ADD_METHOD(Color3f); - PY_MOD_ADD_METHOD(Color3fv); - PY_MOD_ADD_METHOD(Color3i); - PY_MOD_ADD_METHOD(Color3iv); - PY_MOD_ADD_METHOD(Color3s); - PY_MOD_ADD_METHOD(Color3sv); - PY_MOD_ADD_METHOD(Color3ub); - PY_MOD_ADD_METHOD(Color3ubv); - PY_MOD_ADD_METHOD(Color3ui); - PY_MOD_ADD_METHOD(Color3uiv); - PY_MOD_ADD_METHOD(Color3us); - PY_MOD_ADD_METHOD(Color3usv); - PY_MOD_ADD_METHOD(Color4b); - PY_MOD_ADD_METHOD(Color4bv); - PY_MOD_ADD_METHOD(Color4d); - PY_MOD_ADD_METHOD(Color4dv); - PY_MOD_ADD_METHOD(Color4f); - PY_MOD_ADD_METHOD(Color4fv); - PY_MOD_ADD_METHOD(Color4i); - PY_MOD_ADD_METHOD(Color4iv); - PY_MOD_ADD_METHOD(Color4s); - PY_MOD_ADD_METHOD(Color4sv); - PY_MOD_ADD_METHOD(Color4ub); - PY_MOD_ADD_METHOD(Color4ubv); - PY_MOD_ADD_METHOD(Color4ui); - PY_MOD_ADD_METHOD(Color4uiv); - PY_MOD_ADD_METHOD(Color4us); - PY_MOD_ADD_METHOD(Color4usv); - PY_MOD_ADD_METHOD(ColorMaterial); - PY_MOD_ADD_METHOD(CopyPixels); - PY_MOD_ADD_METHOD(DeleteLists); - PY_MOD_ADD_METHOD(DrawPixels); - PY_MOD_ADD_METHOD(EdgeFlag); - PY_MOD_ADD_METHOD(EdgeFlagv); - PY_MOD_ADD_METHOD(End); - PY_MOD_ADD_METHOD(EndList); - PY_MOD_ADD_METHOD(EvalCoord1d); - PY_MOD_ADD_METHOD(EvalCoord1dv); - PY_MOD_ADD_METHOD(EvalCoord1f); - PY_MOD_ADD_METHOD(EvalCoord1fv); - PY_MOD_ADD_METHOD(EvalCoord2d); - PY_MOD_ADD_METHOD(EvalCoord2dv); - PY_MOD_ADD_METHOD(EvalCoord2f); - PY_MOD_ADD_METHOD(EvalCoord2fv); - PY_MOD_ADD_METHOD(EvalMesh1); - PY_MOD_ADD_METHOD(EvalMesh2); - PY_MOD_ADD_METHOD(EvalPoint1); - PY_MOD_ADD_METHOD(EvalPoint2); - PY_MOD_ADD_METHOD(FeedbackBuffer); - PY_MOD_ADD_METHOD(Fogf); - PY_MOD_ADD_METHOD(Fogfv); - PY_MOD_ADD_METHOD(Fogi); - PY_MOD_ADD_METHOD(Fogiv); - PY_MOD_ADD_METHOD(Frustum); - PY_MOD_ADD_METHOD(GenLists); - PY_MOD_ADD_METHOD(GetClipPlane); - PY_MOD_ADD_METHOD(GetLightfv); - PY_MOD_ADD_METHOD(GetLightiv); - PY_MOD_ADD_METHOD(GetMapdv); - PY_MOD_ADD_METHOD(GetMapfv); - PY_MOD_ADD_METHOD(GetMapiv); - PY_MOD_ADD_METHOD(GetMaterialfv); - PY_MOD_ADD_METHOD(GetMaterialiv); - PY_MOD_ADD_METHOD(GetPixelMapfv); - PY_MOD_ADD_METHOD(GetPixelMapuiv); - PY_MOD_ADD_METHOD(GetPixelMapusv); - PY_MOD_ADD_METHOD(GetPolygonStipple); - PY_MOD_ADD_METHOD(GetTexEnvfv); - PY_MOD_ADD_METHOD(GetTexEnviv); - PY_MOD_ADD_METHOD(GetTexGendv); - PY_MOD_ADD_METHOD(GetTexGenfv); - PY_MOD_ADD_METHOD(GetTexGeniv); - PY_MOD_ADD_METHOD(IndexMask); - PY_MOD_ADD_METHOD(Indexd); - PY_MOD_ADD_METHOD(Indexdv); - PY_MOD_ADD_METHOD(Indexf); - PY_MOD_ADD_METHOD(Indexfv); - PY_MOD_ADD_METHOD(Indexi); - PY_MOD_ADD_METHOD(Indexiv); - PY_MOD_ADD_METHOD(Indexs); - PY_MOD_ADD_METHOD(Indexsv); - PY_MOD_ADD_METHOD(InitNames); - PY_MOD_ADD_METHOD(IsList); - PY_MOD_ADD_METHOD(LightModelf); - PY_MOD_ADD_METHOD(LightModelfv); - PY_MOD_ADD_METHOD(LightModeli); - PY_MOD_ADD_METHOD(LightModeliv); - PY_MOD_ADD_METHOD(Lightf); - PY_MOD_ADD_METHOD(Lightfv); - PY_MOD_ADD_METHOD(Lighti); - PY_MOD_ADD_METHOD(Lightiv); - PY_MOD_ADD_METHOD(LineStipple); - PY_MOD_ADD_METHOD(ListBase); - PY_MOD_ADD_METHOD(LoadIdentity); - PY_MOD_ADD_METHOD(LoadMatrixd); - PY_MOD_ADD_METHOD(LoadMatrixf); - PY_MOD_ADD_METHOD(LoadName); - PY_MOD_ADD_METHOD(Map1d); - PY_MOD_ADD_METHOD(Map1f); - PY_MOD_ADD_METHOD(Map2d); - PY_MOD_ADD_METHOD(Map2f); - PY_MOD_ADD_METHOD(MapGrid1d); - PY_MOD_ADD_METHOD(MapGrid1f); - PY_MOD_ADD_METHOD(MapGrid2d); - PY_MOD_ADD_METHOD(MapGrid2f); - PY_MOD_ADD_METHOD(Materialf); - PY_MOD_ADD_METHOD(Materialfv); - PY_MOD_ADD_METHOD(Materiali); - PY_MOD_ADD_METHOD(Materialiv); - PY_MOD_ADD_METHOD(MatrixMode); - PY_MOD_ADD_METHOD(MultMatrixd); - PY_MOD_ADD_METHOD(MultMatrixf); - PY_MOD_ADD_METHOD(NewList); - PY_MOD_ADD_METHOD(Normal3b); - PY_MOD_ADD_METHOD(Normal3bv); - PY_MOD_ADD_METHOD(Normal3d); - PY_MOD_ADD_METHOD(Normal3dv); - PY_MOD_ADD_METHOD(Normal3f); - PY_MOD_ADD_METHOD(Normal3fv); - PY_MOD_ADD_METHOD(Normal3i); - PY_MOD_ADD_METHOD(Normal3iv); - PY_MOD_ADD_METHOD(Normal3s); - PY_MOD_ADD_METHOD(Normal3sv); - PY_MOD_ADD_METHOD(Ortho); - PY_MOD_ADD_METHOD(PassThrough); - PY_MOD_ADD_METHOD(PixelMapfv); - PY_MOD_ADD_METHOD(PixelMapuiv); - PY_MOD_ADD_METHOD(PixelMapusv); - PY_MOD_ADD_METHOD(PixelTransferf); - PY_MOD_ADD_METHOD(PixelTransferi); - PY_MOD_ADD_METHOD(PixelZoom); - PY_MOD_ADD_METHOD(PolygonStipple); - PY_MOD_ADD_METHOD(PopAttrib); - PY_MOD_ADD_METHOD(PopMatrix); - PY_MOD_ADD_METHOD(PopName); - PY_MOD_ADD_METHOD(PushAttrib); - PY_MOD_ADD_METHOD(PushMatrix); - PY_MOD_ADD_METHOD(PushName); - PY_MOD_ADD_METHOD(RasterPos2d); - PY_MOD_ADD_METHOD(RasterPos2dv); - PY_MOD_ADD_METHOD(RasterPos2f); - PY_MOD_ADD_METHOD(RasterPos2fv); - PY_MOD_ADD_METHOD(RasterPos2i); - PY_MOD_ADD_METHOD(RasterPos2iv); - PY_MOD_ADD_METHOD(RasterPos2s); - PY_MOD_ADD_METHOD(RasterPos2sv); - PY_MOD_ADD_METHOD(RasterPos3d); - PY_MOD_ADD_METHOD(RasterPos3dv); - PY_MOD_ADD_METHOD(RasterPos3f); - PY_MOD_ADD_METHOD(RasterPos3fv); - PY_MOD_ADD_METHOD(RasterPos3i); - PY_MOD_ADD_METHOD(RasterPos3iv); - PY_MOD_ADD_METHOD(RasterPos3s); - PY_MOD_ADD_METHOD(RasterPos3sv); - PY_MOD_ADD_METHOD(RasterPos4d); - PY_MOD_ADD_METHOD(RasterPos4dv); - PY_MOD_ADD_METHOD(RasterPos4f); - PY_MOD_ADD_METHOD(RasterPos4fv); - PY_MOD_ADD_METHOD(RasterPos4i); - PY_MOD_ADD_METHOD(RasterPos4iv); - PY_MOD_ADD_METHOD(RasterPos4s); - PY_MOD_ADD_METHOD(RasterPos4sv); - PY_MOD_ADD_METHOD(Rectd); - PY_MOD_ADD_METHOD(Rectdv); - PY_MOD_ADD_METHOD(Rectf); - PY_MOD_ADD_METHOD(Rectfv); - PY_MOD_ADD_METHOD(Recti); - PY_MOD_ADD_METHOD(Rectiv); - PY_MOD_ADD_METHOD(Rects); - PY_MOD_ADD_METHOD(Rectsv); - PY_MOD_ADD_METHOD(RenderMode); - PY_MOD_ADD_METHOD(Rotated); - PY_MOD_ADD_METHOD(Rotatef); - PY_MOD_ADD_METHOD(Scaled); - PY_MOD_ADD_METHOD(Scalef); - PY_MOD_ADD_METHOD(SelectBuffer); - PY_MOD_ADD_METHOD(ShadeModel); - PY_MOD_ADD_METHOD(TexCoord1d); - PY_MOD_ADD_METHOD(TexCoord1dv); - PY_MOD_ADD_METHOD(TexCoord1f); - PY_MOD_ADD_METHOD(TexCoord1fv); - PY_MOD_ADD_METHOD(TexCoord1i); - PY_MOD_ADD_METHOD(TexCoord1iv); - PY_MOD_ADD_METHOD(TexCoord1s); - PY_MOD_ADD_METHOD(TexCoord1sv); - PY_MOD_ADD_METHOD(TexCoord2d); - PY_MOD_ADD_METHOD(TexCoord2dv); - PY_MOD_ADD_METHOD(TexCoord2f); - PY_MOD_ADD_METHOD(TexCoord2fv); - PY_MOD_ADD_METHOD(TexCoord2i); - PY_MOD_ADD_METHOD(TexCoord2iv); - PY_MOD_ADD_METHOD(TexCoord2s); - PY_MOD_ADD_METHOD(TexCoord2sv); - PY_MOD_ADD_METHOD(TexCoord3d); - PY_MOD_ADD_METHOD(TexCoord3dv); - PY_MOD_ADD_METHOD(TexCoord3f); - PY_MOD_ADD_METHOD(TexCoord3fv); - PY_MOD_ADD_METHOD(TexCoord3i); - PY_MOD_ADD_METHOD(TexCoord3iv); - PY_MOD_ADD_METHOD(TexCoord3s); - PY_MOD_ADD_METHOD(TexCoord3sv); - PY_MOD_ADD_METHOD(TexCoord4d); - PY_MOD_ADD_METHOD(TexCoord4dv); - PY_MOD_ADD_METHOD(TexCoord4f); - PY_MOD_ADD_METHOD(TexCoord4fv); - PY_MOD_ADD_METHOD(TexCoord4i); - PY_MOD_ADD_METHOD(TexCoord4iv); - PY_MOD_ADD_METHOD(TexCoord4s); - PY_MOD_ADD_METHOD(TexCoord4sv); - PY_MOD_ADD_METHOD(TexEnvf); - PY_MOD_ADD_METHOD(TexEnvfv); - PY_MOD_ADD_METHOD(TexEnvi); - PY_MOD_ADD_METHOD(TexEnviv); - PY_MOD_ADD_METHOD(TexGend); - PY_MOD_ADD_METHOD(TexGendv); - PY_MOD_ADD_METHOD(TexGenf); - PY_MOD_ADD_METHOD(TexGenfv); - PY_MOD_ADD_METHOD(TexGeni); - PY_MOD_ADD_METHOD(TexGeniv); - PY_MOD_ADD_METHOD(Translated); - PY_MOD_ADD_METHOD(Translatef); - PY_MOD_ADD_METHOD(Vertex2d); - PY_MOD_ADD_METHOD(Vertex2dv); - PY_MOD_ADD_METHOD(Vertex2f); - PY_MOD_ADD_METHOD(Vertex2fv); - PY_MOD_ADD_METHOD(Vertex2i); - PY_MOD_ADD_METHOD(Vertex2iv); - PY_MOD_ADD_METHOD(Vertex2s); - PY_MOD_ADD_METHOD(Vertex2sv); - PY_MOD_ADD_METHOD(Vertex3d); - PY_MOD_ADD_METHOD(Vertex3dv); - PY_MOD_ADD_METHOD(Vertex3f); - PY_MOD_ADD_METHOD(Vertex3fv); - PY_MOD_ADD_METHOD(Vertex3i); - PY_MOD_ADD_METHOD(Vertex3iv); - PY_MOD_ADD_METHOD(Vertex3s); - PY_MOD_ADD_METHOD(Vertex3sv); - PY_MOD_ADD_METHOD(Vertex4d); - PY_MOD_ADD_METHOD(Vertex4dv); - PY_MOD_ADD_METHOD(Vertex4f); - PY_MOD_ADD_METHOD(Vertex4fv); - PY_MOD_ADD_METHOD(Vertex4i); - PY_MOD_ADD_METHOD(Vertex4iv); - PY_MOD_ADD_METHOD(Vertex4s); - PY_MOD_ADD_METHOD(Vertex4sv); - } - /* GL_VERSION_1_1 */ { @@ -2043,27 +1778,6 @@ PyObject *BPyInit_bgl(void) PY_MOD_ADD_METHOD(TexSubImage1D); PY_MOD_ADD_METHOD(TexSubImage2D); } - /* adding in GL_VERSION_1_1 removed from core profile */ - if (use_deprecated == true) { - PY_MOD_ADD_METHOD(AreTexturesResident); - PY_MOD_ADD_METHOD(ArrayElement); - PY_MOD_ADD_METHOD(ColorPointer); - PY_MOD_ADD_METHOD(DisableClientState); - PY_MOD_ADD_METHOD(EdgeFlagPointer); - PY_MOD_ADD_METHOD(EnableClientState); - PY_MOD_ADD_METHOD(GetPointerv); - PY_MOD_ADD_METHOD(IndexPointer); - PY_MOD_ADD_METHOD(Indexub); - PY_MOD_ADD_METHOD(Indexubv); - PY_MOD_ADD_METHOD(InterleavedArrays); - PY_MOD_ADD_METHOD(NormalPointer); - PY_MOD_ADD_METHOD(PopClientAttrib); - PY_MOD_ADD_METHOD(PrioritizeTextures); - PY_MOD_ADD_METHOD(PushClientAttrib); - PY_MOD_ADD_METHOD(TexCoordPointer); - PY_MOD_ADD_METHOD(VertexPointer); - } - /* GL_VERSION_1_2 */ { @@ -2073,7 +1787,6 @@ PyObject *BPyInit_bgl(void) PY_MOD_ADD_METHOD(TexSubImage3D); } - /* GL_VERSION_1_3 */ { PY_MOD_ADD_METHOD(ActiveTexture); @@ -2086,47 +1799,6 @@ PyObject *BPyInit_bgl(void) PY_MOD_ADD_METHOD(GetCompressedTexImage); PY_MOD_ADD_METHOD(SampleCoverage); } - /* adding in GL_VERSION_1_3 removed from core profile */ - if (use_deprecated == true) { - PY_MOD_ADD_METHOD(ClientActiveTexture); - PY_MOD_ADD_METHOD(LoadTransposeMatrixd); - PY_MOD_ADD_METHOD(LoadTransposeMatrixf); - PY_MOD_ADD_METHOD(MultTransposeMatrixd); - PY_MOD_ADD_METHOD(MultTransposeMatrixf); - PY_MOD_ADD_METHOD(MultiTexCoord1d); - PY_MOD_ADD_METHOD(MultiTexCoord1dv); - PY_MOD_ADD_METHOD(MultiTexCoord1f); - PY_MOD_ADD_METHOD(MultiTexCoord1fv); - PY_MOD_ADD_METHOD(MultiTexCoord1i); - PY_MOD_ADD_METHOD(MultiTexCoord1iv); - PY_MOD_ADD_METHOD(MultiTexCoord1s); - PY_MOD_ADD_METHOD(MultiTexCoord1sv); - PY_MOD_ADD_METHOD(MultiTexCoord2d); - PY_MOD_ADD_METHOD(MultiTexCoord2dv); - PY_MOD_ADD_METHOD(MultiTexCoord2f); - PY_MOD_ADD_METHOD(MultiTexCoord2fv); - PY_MOD_ADD_METHOD(MultiTexCoord2i); - PY_MOD_ADD_METHOD(MultiTexCoord2iv); - PY_MOD_ADD_METHOD(MultiTexCoord2s); - PY_MOD_ADD_METHOD(MultiTexCoord2sv); - PY_MOD_ADD_METHOD(MultiTexCoord3d); - PY_MOD_ADD_METHOD(MultiTexCoord3dv); - PY_MOD_ADD_METHOD(MultiTexCoord3f); - PY_MOD_ADD_METHOD(MultiTexCoord3fv); - PY_MOD_ADD_METHOD(MultiTexCoord3i); - PY_MOD_ADD_METHOD(MultiTexCoord3iv); - PY_MOD_ADD_METHOD(MultiTexCoord3s); - PY_MOD_ADD_METHOD(MultiTexCoord3sv); - PY_MOD_ADD_METHOD(MultiTexCoord4d); - PY_MOD_ADD_METHOD(MultiTexCoord4dv); - PY_MOD_ADD_METHOD(MultiTexCoord4f); - PY_MOD_ADD_METHOD(MultiTexCoord4fv); - PY_MOD_ADD_METHOD(MultiTexCoord4i); - PY_MOD_ADD_METHOD(MultiTexCoord4iv); - PY_MOD_ADD_METHOD(MultiTexCoord4s); - PY_MOD_ADD_METHOD(MultiTexCoord4sv); - } - /* GL_VERSION_1_4 */ { @@ -2134,7 +1806,6 @@ PyObject *BPyInit_bgl(void) PY_MOD_ADD_METHOD(BlendEquation); } - /* GL_VERSION_1_5 */ { PY_MOD_ADD_METHOD(BeginQuery); @@ -2158,7 +1829,6 @@ PyObject *BPyInit_bgl(void) PY_MOD_ADD_METHOD(UnmapBuffer); } - /* GL_VERSION_2_0 */ { PY_MOD_ADD_METHOD(AttachShader); @@ -2256,7 +1926,6 @@ PyObject *BPyInit_bgl(void) PY_MOD_ADD_METHOD(VertexAttribPointer); } - /* GL_VERSION_2_1 */ { PY_MOD_ADD_METHOD(UniformMatrix2x3fv); @@ -2267,7 +1936,6 @@ PyObject *BPyInit_bgl(void) PY_MOD_ADD_METHOD(UniformMatrix4x3fv); } - /* GL_VERSION_3_0 */ { PY_MOD_ADD_METHOD(BindVertexArray); @@ -2276,7 +1944,6 @@ PyObject *BPyInit_bgl(void) PY_MOD_ADD_METHOD(IsVertexArray); } - /* GL_VERSION_3_1 */ { PY_MOD_ADD_METHOD(BindBufferBase); @@ -2291,7 +1958,6 @@ PyObject *BPyInit_bgl(void) PY_MOD_ADD_METHOD(UniformBlockBinding); } - /* GL_VERSION_3_2 */ { PY_MOD_ADD_METHOD(FramebufferTexture); @@ -2303,7 +1969,6 @@ PyObject *BPyInit_bgl(void) PY_MOD_ADD_METHOD(TexImage3DMultisample); } - /* GL_VERSION_3_3 */ { PY_MOD_ADD_METHOD(ColorP3ui); @@ -2544,338 +2209,6 @@ PyObject *BPyInit_bgl(void) PY_DICT_ADD_INT(GL_XOR); PY_DICT_ADD_INT(GL_ZERO); } - /* adding in GL_VERSION_1_1 removed from core profile */ - if (use_deprecated == true) { - PY_DICT_ADD_INT(GL_2D); - PY_DICT_ADD_INT(GL_2_BYTES); - PY_DICT_ADD_INT(GL_3D); - PY_DICT_ADD_INT(GL_3D_COLOR); - PY_DICT_ADD_INT(GL_3D_COLOR_TEXTURE); - PY_DICT_ADD_INT(GL_3_BYTES); - PY_DICT_ADD_INT(GL_4D_COLOR_TEXTURE); - PY_DICT_ADD_INT(GL_4_BYTES); - PY_DICT_ADD_INT(GL_ACCUM); - PY_DICT_ADD_INT(GL_ACCUM_ALPHA_BITS); - PY_DICT_ADD_INT(GL_ACCUM_BLUE_BITS); - PY_DICT_ADD_INT(GL_ACCUM_BUFFER_BIT); - PY_DICT_ADD_INT(GL_ACCUM_CLEAR_VALUE); - PY_DICT_ADD_INT(GL_ACCUM_GREEN_BITS); - PY_DICT_ADD_INT(GL_ACCUM_RED_BITS); - PY_DICT_ADD_INT(GL_ADD); - PY_DICT_ADD_INT(GL_ALL_ATTRIB_BITS); - PY_DICT_ADD_INT(GL_ALPHA12); - PY_DICT_ADD_INT(GL_ALPHA16); - PY_DICT_ADD_INT(GL_ALPHA4); - PY_DICT_ADD_INT(GL_ALPHA8); - PY_DICT_ADD_INT(GL_ALPHA_BIAS); - PY_DICT_ADD_INT(GL_ALPHA_BITS); - PY_DICT_ADD_INT(GL_ALPHA_SCALE); - PY_DICT_ADD_INT(GL_ALPHA_TEST); - PY_DICT_ADD_INT(GL_ALPHA_TEST_FUNC); - PY_DICT_ADD_INT(GL_ALPHA_TEST_REF); - PY_DICT_ADD_INT(GL_AMBIENT); - PY_DICT_ADD_INT(GL_AMBIENT_AND_DIFFUSE); - PY_DICT_ADD_INT(GL_ATTRIB_STACK_DEPTH); - PY_DICT_ADD_INT(GL_AUTO_NORMAL); - PY_DICT_ADD_INT(GL_AUX0); - PY_DICT_ADD_INT(GL_AUX1); - PY_DICT_ADD_INT(GL_AUX2); - PY_DICT_ADD_INT(GL_AUX3); - PY_DICT_ADD_INT(GL_AUX_BUFFERS); - PY_DICT_ADD_INT(GL_BITMAP); - PY_DICT_ADD_INT(GL_BITMAP_TOKEN); - PY_DICT_ADD_INT(GL_BLUE_BIAS); - PY_DICT_ADD_INT(GL_BLUE_BITS); - PY_DICT_ADD_INT(GL_BLUE_SCALE); - PY_DICT_ADD_INT(GL_C3F_V3F); - PY_DICT_ADD_INT(GL_C4F_N3F_V3F); - PY_DICT_ADD_INT(GL_C4UB_V2F); - PY_DICT_ADD_INT(GL_C4UB_V3F); - PY_DICT_ADD_INT(GL_CLAMP); - PY_DICT_ADD_INT(GL_CLIENT_ALL_ATTRIB_BITS); - PY_DICT_ADD_INT(GL_CLIENT_ATTRIB_STACK_DEPTH); - PY_DICT_ADD_INT(GL_CLIENT_PIXEL_STORE_BIT); - PY_DICT_ADD_INT(GL_CLIENT_VERTEX_ARRAY_BIT); - PY_DICT_ADD_INT(GL_CLIP_PLANE0); - PY_DICT_ADD_INT(GL_CLIP_PLANE1); - PY_DICT_ADD_INT(GL_CLIP_PLANE2); - PY_DICT_ADD_INT(GL_CLIP_PLANE3); - PY_DICT_ADD_INT(GL_CLIP_PLANE4); - PY_DICT_ADD_INT(GL_CLIP_PLANE5); - PY_DICT_ADD_INT(GL_COEFF); - PY_DICT_ADD_INT(GL_COLOR_ARRAY); - PY_DICT_ADD_INT(GL_COLOR_ARRAY_POINTER); - PY_DICT_ADD_INT(GL_COLOR_ARRAY_SIZE); - PY_DICT_ADD_INT(GL_COLOR_ARRAY_STRIDE); - PY_DICT_ADD_INT(GL_COLOR_ARRAY_TYPE); - PY_DICT_ADD_INT(GL_COLOR_INDEX); - PY_DICT_ADD_INT(GL_COLOR_INDEXES); - PY_DICT_ADD_INT(GL_COLOR_MATERIAL); - PY_DICT_ADD_INT(GL_COLOR_MATERIAL_FACE); - PY_DICT_ADD_INT(GL_COLOR_MATERIAL_PARAMETER); - PY_DICT_ADD_INT(GL_COMPILE); - PY_DICT_ADD_INT(GL_COMPILE_AND_EXECUTE); - PY_DICT_ADD_INT(GL_CONSTANT_ATTENUATION); - PY_DICT_ADD_INT(GL_COPY_PIXEL_TOKEN); - PY_DICT_ADD_INT(GL_CURRENT_BIT); - PY_DICT_ADD_INT(GL_CURRENT_COLOR); - PY_DICT_ADD_INT(GL_CURRENT_INDEX); - PY_DICT_ADD_INT(GL_CURRENT_NORMAL); - PY_DICT_ADD_INT(GL_CURRENT_RASTER_COLOR); - PY_DICT_ADD_INT(GL_CURRENT_RASTER_DISTANCE); - PY_DICT_ADD_INT(GL_CURRENT_RASTER_INDEX); - PY_DICT_ADD_INT(GL_CURRENT_RASTER_POSITION); - PY_DICT_ADD_INT(GL_CURRENT_RASTER_POSITION_VALID); - PY_DICT_ADD_INT(GL_CURRENT_RASTER_TEXTURE_COORDS); - PY_DICT_ADD_INT(GL_CURRENT_TEXTURE_COORDS); - PY_DICT_ADD_INT(GL_DECAL); - PY_DICT_ADD_INT(GL_DEPTH_BIAS); - PY_DICT_ADD_INT(GL_DEPTH_BITS); - PY_DICT_ADD_INT(GL_DEPTH_SCALE); - PY_DICT_ADD_INT(GL_DIFFUSE); - PY_DICT_ADD_INT(GL_DOMAIN); - PY_DICT_ADD_INT(GL_DRAW_PIXEL_TOKEN); - PY_DICT_ADD_INT(GL_EDGE_FLAG); - PY_DICT_ADD_INT(GL_EDGE_FLAG_ARRAY); - PY_DICT_ADD_INT(GL_EDGE_FLAG_ARRAY_POINTER); - PY_DICT_ADD_INT(GL_EDGE_FLAG_ARRAY_STRIDE); - PY_DICT_ADD_INT(GL_EMISSION); - PY_DICT_ADD_INT(GL_ENABLE_BIT); - PY_DICT_ADD_INT(GL_EVAL_BIT); - PY_DICT_ADD_INT(GL_EXP); - PY_DICT_ADD_INT(GL_EXP2); - PY_DICT_ADD_INT(GL_EYE_LINEAR); - PY_DICT_ADD_INT(GL_EYE_PLANE); - PY_DICT_ADD_INT(GL_FEEDBACK); - PY_DICT_ADD_INT(GL_FEEDBACK_BUFFER_POINTER); - PY_DICT_ADD_INT(GL_FEEDBACK_BUFFER_SIZE); - PY_DICT_ADD_INT(GL_FEEDBACK_BUFFER_TYPE); - PY_DICT_ADD_INT(GL_FLAT); - PY_DICT_ADD_INT(GL_FOG); - PY_DICT_ADD_INT(GL_FOG_BIT); - PY_DICT_ADD_INT(GL_FOG_COLOR); - PY_DICT_ADD_INT(GL_FOG_DENSITY); - PY_DICT_ADD_INT(GL_FOG_END); - PY_DICT_ADD_INT(GL_FOG_HINT); - PY_DICT_ADD_INT(GL_FOG_INDEX); - PY_DICT_ADD_INT(GL_FOG_MODE); - PY_DICT_ADD_INT(GL_FOG_START); - PY_DICT_ADD_INT(GL_GREEN_BIAS); - PY_DICT_ADD_INT(GL_GREEN_BITS); - PY_DICT_ADD_INT(GL_GREEN_SCALE); - PY_DICT_ADD_INT(GL_HINT_BIT); - PY_DICT_ADD_INT(GL_INDEX_ARRAY); - PY_DICT_ADD_INT(GL_INDEX_ARRAY_POINTER); - PY_DICT_ADD_INT(GL_INDEX_ARRAY_STRIDE); - PY_DICT_ADD_INT(GL_INDEX_ARRAY_TYPE); - PY_DICT_ADD_INT(GL_INDEX_BITS); - PY_DICT_ADD_INT(GL_INDEX_CLEAR_VALUE); - PY_DICT_ADD_INT(GL_INDEX_LOGIC_OP); - PY_DICT_ADD_INT(GL_INDEX_MODE); - PY_DICT_ADD_INT(GL_INDEX_OFFSET); - PY_DICT_ADD_INT(GL_INDEX_SHIFT); - PY_DICT_ADD_INT(GL_INDEX_WRITEMASK); - PY_DICT_ADD_INT(GL_INTENSITY); - PY_DICT_ADD_INT(GL_INTENSITY12); - PY_DICT_ADD_INT(GL_INTENSITY16); - PY_DICT_ADD_INT(GL_INTENSITY4); - PY_DICT_ADD_INT(GL_INTENSITY8); - PY_DICT_ADD_INT(GL_LIGHT0); - PY_DICT_ADD_INT(GL_LIGHT1); - PY_DICT_ADD_INT(GL_LIGHT2); - PY_DICT_ADD_INT(GL_LIGHT3); - PY_DICT_ADD_INT(GL_LIGHT4); - PY_DICT_ADD_INT(GL_LIGHT5); - PY_DICT_ADD_INT(GL_LIGHT6); - PY_DICT_ADD_INT(GL_LIGHT7); - PY_DICT_ADD_INT(GL_LIGHTING); - PY_DICT_ADD_INT(GL_LIGHTING_BIT); - PY_DICT_ADD_INT(GL_LIGHT_MODEL_AMBIENT); - PY_DICT_ADD_INT(GL_LIGHT_MODEL_LOCAL_VIEWER); - PY_DICT_ADD_INT(GL_LIGHT_MODEL_TWO_SIDE); - PY_DICT_ADD_INT(GL_LINEAR_ATTENUATION); - PY_DICT_ADD_INT(GL_LINE_BIT); - PY_DICT_ADD_INT(GL_LINE_RESET_TOKEN); - PY_DICT_ADD_INT(GL_LINE_STIPPLE); - PY_DICT_ADD_INT(GL_LINE_STIPPLE_PATTERN); - PY_DICT_ADD_INT(GL_LINE_STIPPLE_REPEAT); - PY_DICT_ADD_INT(GL_LINE_TOKEN); - PY_DICT_ADD_INT(GL_LIST_BASE); - PY_DICT_ADD_INT(GL_LIST_BIT); - PY_DICT_ADD_INT(GL_LIST_INDEX); - PY_DICT_ADD_INT(GL_LIST_MODE); - PY_DICT_ADD_INT(GL_LOAD); - PY_DICT_ADD_INT(GL_LOGIC_OP); - PY_DICT_ADD_INT(GL_LUMINANCE); - PY_DICT_ADD_INT(GL_LUMINANCE12); - PY_DICT_ADD_INT(GL_LUMINANCE12_ALPHA12); - PY_DICT_ADD_INT(GL_LUMINANCE12_ALPHA4); - PY_DICT_ADD_INT(GL_LUMINANCE16); - PY_DICT_ADD_INT(GL_LUMINANCE16_ALPHA16); - PY_DICT_ADD_INT(GL_LUMINANCE4); - PY_DICT_ADD_INT(GL_LUMINANCE4_ALPHA4); - PY_DICT_ADD_INT(GL_LUMINANCE6_ALPHA2); - PY_DICT_ADD_INT(GL_LUMINANCE8); - PY_DICT_ADD_INT(GL_LUMINANCE8_ALPHA8); - PY_DICT_ADD_INT(GL_LUMINANCE_ALPHA); - PY_DICT_ADD_INT(GL_MAP1_COLOR_4); - PY_DICT_ADD_INT(GL_MAP1_GRID_DOMAIN); - PY_DICT_ADD_INT(GL_MAP1_GRID_SEGMENTS); - PY_DICT_ADD_INT(GL_MAP1_INDEX); - PY_DICT_ADD_INT(GL_MAP1_NORMAL); - PY_DICT_ADD_INT(GL_MAP1_TEXTURE_COORD_1); - PY_DICT_ADD_INT(GL_MAP1_TEXTURE_COORD_2); - PY_DICT_ADD_INT(GL_MAP1_TEXTURE_COORD_3); - PY_DICT_ADD_INT(GL_MAP1_TEXTURE_COORD_4); - PY_DICT_ADD_INT(GL_MAP1_VERTEX_3); - PY_DICT_ADD_INT(GL_MAP1_VERTEX_4); - PY_DICT_ADD_INT(GL_MAP2_COLOR_4); - PY_DICT_ADD_INT(GL_MAP2_GRID_DOMAIN); - PY_DICT_ADD_INT(GL_MAP2_GRID_SEGMENTS); - PY_DICT_ADD_INT(GL_MAP2_INDEX); - PY_DICT_ADD_INT(GL_MAP2_NORMAL); - PY_DICT_ADD_INT(GL_MAP2_TEXTURE_COORD_1); - PY_DICT_ADD_INT(GL_MAP2_TEXTURE_COORD_2); - PY_DICT_ADD_INT(GL_MAP2_TEXTURE_COORD_3); - PY_DICT_ADD_INT(GL_MAP2_TEXTURE_COORD_4); - PY_DICT_ADD_INT(GL_MAP2_VERTEX_3); - PY_DICT_ADD_INT(GL_MAP2_VERTEX_4); - PY_DICT_ADD_INT(GL_MAP_COLOR); - PY_DICT_ADD_INT(GL_MAP_STENCIL); - PY_DICT_ADD_INT(GL_MATRIX_MODE); - PY_DICT_ADD_INT(GL_MAX_ATTRIB_STACK_DEPTH); - PY_DICT_ADD_INT(GL_MAX_CLIENT_ATTRIB_STACK_DEPTH); - PY_DICT_ADD_INT(GL_MAX_CLIP_PLANES); - PY_DICT_ADD_INT(GL_MAX_EVAL_ORDER); - PY_DICT_ADD_INT(GL_MAX_LIGHTS); - PY_DICT_ADD_INT(GL_MAX_LIST_NESTING); - PY_DICT_ADD_INT(GL_MAX_MODELVIEW_STACK_DEPTH); - PY_DICT_ADD_INT(GL_MAX_NAME_STACK_DEPTH); - PY_DICT_ADD_INT(GL_MAX_PIXEL_MAP_TABLE); - PY_DICT_ADD_INT(GL_MAX_PROJECTION_STACK_DEPTH); - PY_DICT_ADD_INT(GL_MAX_TEXTURE_STACK_DEPTH); - PY_DICT_ADD_INT(GL_MODELVIEW); - PY_DICT_ADD_INT(GL_MODELVIEW_MATRIX); - PY_DICT_ADD_INT(GL_MODELVIEW_STACK_DEPTH); - PY_DICT_ADD_INT(GL_MODULATE); - PY_DICT_ADD_INT(GL_MULT); - PY_DICT_ADD_INT(GL_N3F_V3F); - PY_DICT_ADD_INT(GL_NAME_STACK_DEPTH); - PY_DICT_ADD_INT(GL_NORMALIZE); - PY_DICT_ADD_INT(GL_NORMAL_ARRAY); - PY_DICT_ADD_INT(GL_NORMAL_ARRAY_POINTER); - PY_DICT_ADD_INT(GL_NORMAL_ARRAY_STRIDE); - PY_DICT_ADD_INT(GL_NORMAL_ARRAY_TYPE); - PY_DICT_ADD_INT(GL_OBJECT_LINEAR); - PY_DICT_ADD_INT(GL_OBJECT_PLANE); - PY_DICT_ADD_INT(GL_ORDER); - PY_DICT_ADD_INT(GL_PASS_THROUGH_TOKEN); - PY_DICT_ADD_INT(GL_PERSPECTIVE_CORRECTION_HINT); - PY_DICT_ADD_INT(GL_PIXEL_MAP_A_TO_A); - PY_DICT_ADD_INT(GL_PIXEL_MAP_A_TO_A_SIZE); - PY_DICT_ADD_INT(GL_PIXEL_MAP_B_TO_B); - PY_DICT_ADD_INT(GL_PIXEL_MAP_B_TO_B_SIZE); - PY_DICT_ADD_INT(GL_PIXEL_MAP_G_TO_G); - PY_DICT_ADD_INT(GL_PIXEL_MAP_G_TO_G_SIZE); - PY_DICT_ADD_INT(GL_PIXEL_MAP_I_TO_A); - PY_DICT_ADD_INT(GL_PIXEL_MAP_I_TO_A_SIZE); - PY_DICT_ADD_INT(GL_PIXEL_MAP_I_TO_B); - PY_DICT_ADD_INT(GL_PIXEL_MAP_I_TO_B_SIZE); - PY_DICT_ADD_INT(GL_PIXEL_MAP_I_TO_G); - PY_DICT_ADD_INT(GL_PIXEL_MAP_I_TO_G_SIZE); - PY_DICT_ADD_INT(GL_PIXEL_MAP_I_TO_I); - PY_DICT_ADD_INT(GL_PIXEL_MAP_I_TO_I_SIZE); - PY_DICT_ADD_INT(GL_PIXEL_MAP_I_TO_R); - PY_DICT_ADD_INT(GL_PIXEL_MAP_I_TO_R_SIZE); - PY_DICT_ADD_INT(GL_PIXEL_MAP_R_TO_R); - PY_DICT_ADD_INT(GL_PIXEL_MAP_R_TO_R_SIZE); - PY_DICT_ADD_INT(GL_PIXEL_MAP_S_TO_S); - PY_DICT_ADD_INT(GL_PIXEL_MAP_S_TO_S_SIZE); - PY_DICT_ADD_INT(GL_PIXEL_MODE_BIT); - PY_DICT_ADD_INT(GL_POINT_BIT); - PY_DICT_ADD_INT(GL_POINT_SMOOTH); - PY_DICT_ADD_INT(GL_POINT_SMOOTH_HINT); - PY_DICT_ADD_INT(GL_POINT_TOKEN); - PY_DICT_ADD_INT(GL_POLYGON); - PY_DICT_ADD_INT(GL_POLYGON_BIT); - PY_DICT_ADD_INT(GL_POLYGON_STIPPLE); - PY_DICT_ADD_INT(GL_POLYGON_STIPPLE_BIT); - PY_DICT_ADD_INT(GL_POLYGON_TOKEN); - PY_DICT_ADD_INT(GL_POSITION); - PY_DICT_ADD_INT(GL_PROJECTION); - PY_DICT_ADD_INT(GL_PROJECTION_MATRIX); - PY_DICT_ADD_INT(GL_PROJECTION_STACK_DEPTH); - PY_DICT_ADD_INT(GL_Q); - PY_DICT_ADD_INT(GL_QUADRATIC_ATTENUATION); - PY_DICT_ADD_INT(GL_QUADS); - PY_DICT_ADD_INT(GL_QUAD_STRIP); - PY_DICT_ADD_INT(GL_R); - PY_DICT_ADD_INT(GL_RED_BIAS); - PY_DICT_ADD_INT(GL_RED_BITS); - PY_DICT_ADD_INT(GL_RED_SCALE); - PY_DICT_ADD_INT(GL_RENDER); - PY_DICT_ADD_INT(GL_RENDER_MODE); - PY_DICT_ADD_INT(GL_RETURN); - PY_DICT_ADD_INT(GL_RGBA_MODE); - PY_DICT_ADD_INT(GL_S); - PY_DICT_ADD_INT(GL_SCISSOR_BIT); - PY_DICT_ADD_INT(GL_SELECT); - PY_DICT_ADD_INT(GL_SELECTION_BUFFER_POINTER); - PY_DICT_ADD_INT(GL_SELECTION_BUFFER_SIZE); - PY_DICT_ADD_INT(GL_SHADE_MODEL); - PY_DICT_ADD_INT(GL_SHININESS); - PY_DICT_ADD_INT(GL_SMOOTH); - PY_DICT_ADD_INT(GL_SPECULAR); - PY_DICT_ADD_INT(GL_SPHERE_MAP); - PY_DICT_ADD_INT(GL_SPOT_CUTOFF); - PY_DICT_ADD_INT(GL_SPOT_DIRECTION); - PY_DICT_ADD_INT(GL_SPOT_EXPONENT); - PY_DICT_ADD_INT(GL_STACK_OVERFLOW); - PY_DICT_ADD_INT(GL_STACK_UNDERFLOW); - PY_DICT_ADD_INT(GL_STENCIL_BITS); - PY_DICT_ADD_INT(GL_T); - PY_DICT_ADD_INT(GL_T2F_C3F_V3F); - PY_DICT_ADD_INT(GL_T2F_C4F_N3F_V3F); - PY_DICT_ADD_INT(GL_T2F_C4UB_V3F); - PY_DICT_ADD_INT(GL_T2F_N3F_V3F); - PY_DICT_ADD_INT(GL_T2F_V3F); - PY_DICT_ADD_INT(GL_T4F_C4F_N3F_V4F); - PY_DICT_ADD_INT(GL_T4F_V4F); - PY_DICT_ADD_INT(GL_TEXTURE_BIT); - PY_DICT_ADD_INT(GL_TEXTURE_BORDER); - PY_DICT_ADD_INT(GL_TEXTURE_COMPONENTS); - PY_DICT_ADD_INT(GL_TEXTURE_COORD_ARRAY); - PY_DICT_ADD_INT(GL_TEXTURE_COORD_ARRAY_POINTER); - PY_DICT_ADD_INT(GL_TEXTURE_COORD_ARRAY_SIZE); - PY_DICT_ADD_INT(GL_TEXTURE_COORD_ARRAY_STRIDE); - PY_DICT_ADD_INT(GL_TEXTURE_COORD_ARRAY_TYPE); - PY_DICT_ADD_INT(GL_TEXTURE_ENV); - PY_DICT_ADD_INT(GL_TEXTURE_ENV_COLOR); - PY_DICT_ADD_INT(GL_TEXTURE_ENV_MODE); - PY_DICT_ADD_INT(GL_TEXTURE_GEN_MODE); - PY_DICT_ADD_INT(GL_TEXTURE_GEN_Q); - PY_DICT_ADD_INT(GL_TEXTURE_GEN_R); - PY_DICT_ADD_INT(GL_TEXTURE_GEN_S); - PY_DICT_ADD_INT(GL_TEXTURE_GEN_T); - PY_DICT_ADD_INT(GL_TEXTURE_INTENSITY_SIZE); - PY_DICT_ADD_INT(GL_TEXTURE_LUMINANCE_SIZE); - PY_DICT_ADD_INT(GL_TEXTURE_MATRIX); - PY_DICT_ADD_INT(GL_TEXTURE_PRIORITY); - PY_DICT_ADD_INT(GL_TEXTURE_RESIDENT); - PY_DICT_ADD_INT(GL_TEXTURE_STACK_DEPTH); - PY_DICT_ADD_INT(GL_TRANSFORM_BIT); - PY_DICT_ADD_INT(GL_V2F); - PY_DICT_ADD_INT(GL_V3F); - PY_DICT_ADD_INT(GL_VERTEX_ARRAY); - PY_DICT_ADD_INT(GL_VERTEX_ARRAY_POINTER); - PY_DICT_ADD_INT(GL_VERTEX_ARRAY_SIZE); - PY_DICT_ADD_INT(GL_VERTEX_ARRAY_STRIDE); - PY_DICT_ADD_INT(GL_VERTEX_ARRAY_TYPE); - PY_DICT_ADD_INT(GL_VIEWPORT_BIT); - PY_DICT_ADD_INT(GL_ZOOM_X); - PY_DICT_ADD_INT(GL_ZOOM_Y); - } - /* GL_VERSION_1_2 */ { @@ -2916,15 +2249,6 @@ PyObject *BPyInit_bgl(void) PY_DICT_ADD_INT(GL_UNSIGNED_SHORT_5_6_5); PY_DICT_ADD_INT(GL_UNSIGNED_SHORT_5_6_5_REV); } - /* adding in GL_VERSION_1_2 removed from core profile */ - if (use_deprecated == true) { - PY_DICT_ADD_INT(GL_ALIASED_POINT_SIZE_RANGE); - PY_DICT_ADD_INT(GL_LIGHT_MODEL_COLOR_CONTROL); - PY_DICT_ADD_INT(GL_RESCALE_NORMAL); - PY_DICT_ADD_INT(GL_SEPARATE_SPECULAR_COLOR); - PY_DICT_ADD_INT(GL_SINGLE_COLOR); - } - /* GL_VERSION_1_3 */ { @@ -2988,47 +2312,6 @@ PyObject *BPyInit_bgl(void) PY_DICT_ADD_INT(GL_TEXTURE_CUBE_MAP_POSITIVE_Y); PY_DICT_ADD_INT(GL_TEXTURE_CUBE_MAP_POSITIVE_Z); } - /* adding in GL_VERSION_1_3 removed from core profile */ - if (use_deprecated == true) { - PY_DICT_ADD_INT(GL_ADD_SIGNED); - PY_DICT_ADD_INT(GL_CLIENT_ACTIVE_TEXTURE); - PY_DICT_ADD_INT(GL_COMBINE); - PY_DICT_ADD_INT(GL_COMBINE_ALPHA); - PY_DICT_ADD_INT(GL_COMBINE_RGB); - PY_DICT_ADD_INT(GL_COMPRESSED_ALPHA); - PY_DICT_ADD_INT(GL_COMPRESSED_INTENSITY); - PY_DICT_ADD_INT(GL_COMPRESSED_LUMINANCE); - PY_DICT_ADD_INT(GL_COMPRESSED_LUMINANCE_ALPHA); - PY_DICT_ADD_INT(GL_CONSTANT); - PY_DICT_ADD_INT(GL_DOT3_RGB); - PY_DICT_ADD_INT(GL_DOT3_RGBA); - PY_DICT_ADD_INT(GL_INTERPOLATE); - PY_DICT_ADD_INT(GL_MAX_TEXTURE_UNITS); - PY_DICT_ADD_INT(GL_MULTISAMPLE_BIT); - PY_DICT_ADD_INT(GL_NORMAL_MAP); - PY_DICT_ADD_INT(GL_OPERAND0_ALPHA); - PY_DICT_ADD_INT(GL_OPERAND0_RGB); - PY_DICT_ADD_INT(GL_OPERAND1_ALPHA); - PY_DICT_ADD_INT(GL_OPERAND1_RGB); - PY_DICT_ADD_INT(GL_OPERAND2_ALPHA); - PY_DICT_ADD_INT(GL_OPERAND2_RGB); - PY_DICT_ADD_INT(GL_PREVIOUS); - PY_DICT_ADD_INT(GL_PRIMARY_COLOR); - PY_DICT_ADD_INT(GL_REFLECTION_MAP); - PY_DICT_ADD_INT(GL_RGB_SCALE); - PY_DICT_ADD_INT(GL_SOURCE0_ALPHA); - PY_DICT_ADD_INT(GL_SOURCE0_RGB); - PY_DICT_ADD_INT(GL_SOURCE1_ALPHA); - PY_DICT_ADD_INT(GL_SOURCE1_RGB); - PY_DICT_ADD_INT(GL_SOURCE2_ALPHA); - PY_DICT_ADD_INT(GL_SOURCE2_RGB); - PY_DICT_ADD_INT(GL_SUBTRACT); - PY_DICT_ADD_INT(GL_TRANSPOSE_COLOR_MATRIX); - PY_DICT_ADD_INT(GL_TRANSPOSE_MODELVIEW_MATRIX); - PY_DICT_ADD_INT(GL_TRANSPOSE_PROJECTION_MATRIX); - PY_DICT_ADD_INT(GL_TRANSPOSE_TEXTURE_MATRIX); - } - /* GL_VERSION_1_4 */ { @@ -3058,33 +2341,6 @@ PyObject *BPyInit_bgl(void) PY_DICT_ADD_INT(GL_TEXTURE_DEPTH_SIZE); PY_DICT_ADD_INT(GL_TEXTURE_LOD_BIAS); } - /* adding in GL_VERSION_1_4 removed from core profile */ - if (use_deprecated == true) { - PY_DICT_ADD_INT(GL_COLOR_SUM); - PY_DICT_ADD_INT(GL_COMPARE_R_TO_TEXTURE); - PY_DICT_ADD_INT(GL_CURRENT_FOG_COORDINATE); - PY_DICT_ADD_INT(GL_CURRENT_SECONDARY_COLOR); - PY_DICT_ADD_INT(GL_DEPTH_TEXTURE_MODE); - PY_DICT_ADD_INT(GL_FOG_COORDINATE); - PY_DICT_ADD_INT(GL_FOG_COORDINATE_ARRAY); - PY_DICT_ADD_INT(GL_FOG_COORDINATE_ARRAY_POINTER); - PY_DICT_ADD_INT(GL_FOG_COORDINATE_ARRAY_STRIDE); - PY_DICT_ADD_INT(GL_FOG_COORDINATE_ARRAY_TYPE); - PY_DICT_ADD_INT(GL_FOG_COORDINATE_SOURCE); - PY_DICT_ADD_INT(GL_FRAGMENT_DEPTH); - PY_DICT_ADD_INT(GL_GENERATE_MIPMAP); - PY_DICT_ADD_INT(GL_GENERATE_MIPMAP_HINT); - PY_DICT_ADD_INT(GL_POINT_DISTANCE_ATTENUATION); - PY_DICT_ADD_INT(GL_POINT_SIZE_MAX); - PY_DICT_ADD_INT(GL_POINT_SIZE_MIN); - PY_DICT_ADD_INT(GL_SECONDARY_COLOR_ARRAY); - PY_DICT_ADD_INT(GL_SECONDARY_COLOR_ARRAY_POINTER); - PY_DICT_ADD_INT(GL_SECONDARY_COLOR_ARRAY_SIZE); - PY_DICT_ADD_INT(GL_SECONDARY_COLOR_ARRAY_STRIDE); - PY_DICT_ADD_INT(GL_SECONDARY_COLOR_ARRAY_TYPE); - PY_DICT_ADD_INT(GL_TEXTURE_FILTER_CONTROL); - } - /* GL_VERSION_1_5 */ { @@ -3117,32 +2373,6 @@ PyObject *BPyInit_bgl(void) PY_DICT_ADD_INT(GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING); PY_DICT_ADD_INT(GL_WRITE_ONLY); } - /* adding in GL_VERSION_1_5 removed from core profile */ - if (use_deprecated == true) { - PY_DICT_ADD_INT(GL_COLOR_ARRAY_BUFFER_BINDING); - PY_DICT_ADD_INT(GL_CURRENT_FOG_COORD); - PY_DICT_ADD_INT(GL_EDGE_FLAG_ARRAY_BUFFER_BINDING); - PY_DICT_ADD_INT(GL_FOG_COORD); - PY_DICT_ADD_INT(GL_FOG_COORDINATE_ARRAY_BUFFER_BINDING); - PY_DICT_ADD_INT(GL_FOG_COORD_ARRAY); - PY_DICT_ADD_INT(GL_FOG_COORD_ARRAY_BUFFER_BINDING); - PY_DICT_ADD_INT(GL_FOG_COORD_ARRAY_POINTER); - PY_DICT_ADD_INT(GL_FOG_COORD_ARRAY_STRIDE); - PY_DICT_ADD_INT(GL_FOG_COORD_ARRAY_TYPE); - PY_DICT_ADD_INT(GL_FOG_COORD_SRC); - PY_DICT_ADD_INT(GL_INDEX_ARRAY_BUFFER_BINDING); - PY_DICT_ADD_INT(GL_NORMAL_ARRAY_BUFFER_BINDING); - PY_DICT_ADD_INT(GL_SECONDARY_COLOR_ARRAY_BUFFER_BINDING); - PY_DICT_ADD_INT(GL_SRC0_ALPHA); - PY_DICT_ADD_INT(GL_SRC0_RGB); - PY_DICT_ADD_INT(GL_SRC1_RGB); - PY_DICT_ADD_INT(GL_SRC2_ALPHA); - PY_DICT_ADD_INT(GL_SRC2_RGB); - PY_DICT_ADD_INT(GL_TEXTURE_COORD_ARRAY_BUFFER_BINDING); - PY_DICT_ADD_INT(GL_VERTEX_ARRAY_BUFFER_BINDING); - PY_DICT_ADD_INT(GL_WEIGHT_ARRAY_BUFFER_BINDING); - } - /* GL_VERSION_2_0 */ { @@ -3227,14 +2457,6 @@ PyObject *BPyInit_bgl(void) PY_DICT_ADD_INT(GL_VERTEX_PROGRAM_POINT_SIZE); PY_DICT_ADD_INT(GL_VERTEX_SHADER); } - /* adding in GL_VERSION_2_0 removed from core profile */ - if (use_deprecated == true) { - PY_DICT_ADD_INT(GL_COORD_REPLACE); - PY_DICT_ADD_INT(GL_MAX_TEXTURE_COORDS); - PY_DICT_ADD_INT(GL_POINT_SPRITE); - PY_DICT_ADD_INT(GL_VERTEX_PROGRAM_TWO_SIDE); - } - /* GL_VERSION_2_1 */ { @@ -3255,16 +2477,6 @@ PyObject *BPyInit_bgl(void) PY_DICT_ADD_INT(GL_SRGB8_ALPHA8); PY_DICT_ADD_INT(GL_SRGB_ALPHA); } - /* adding in GL_VERSION_2_1 removed from core profile */ - if (use_deprecated == true) { - PY_DICT_ADD_INT(GL_COMPRESSED_SLUMINANCE); - PY_DICT_ADD_INT(GL_COMPRESSED_SLUMINANCE_ALPHA); - PY_DICT_ADD_INT(GL_CURRENT_RASTER_SECONDARY_COLOR); - PY_DICT_ADD_INT(GL_SLUMINANCE); - PY_DICT_ADD_INT(GL_SLUMINANCE8); - PY_DICT_ADD_INT(GL_SLUMINANCE8_ALPHA8); - PY_DICT_ADD_INT(GL_SLUMINANCE_ALPHA); - } /* GL_VERSION_3_0 */ { @@ -3505,14 +2717,6 @@ PyObject *BPyInit_bgl(void) PY_DICT_ADD_INT(GL_VERTEX_ARRAY_BINDING); PY_DICT_ADD_INT(GL_VERTEX_ATTRIB_ARRAY_INTEGER); } - /* adding in GL_VERSION_3_0 removed from core profile */ - if (use_deprecated == true) { - PY_DICT_ADD_INT(GL_ALPHA_INTEGER); - PY_DICT_ADD_INT(GL_CLAMP_FRAGMENT_COLOR); - PY_DICT_ADD_INT(GL_CLAMP_VERTEX_COLOR); - PY_DICT_ADD_INT(GL_TEXTURE_INTENSITY_TYPE); - PY_DICT_ADD_INT(GL_TEXTURE_LUMINANCE_TYPE); - } /* GL_VERSION_3_1 */ { @@ -3579,7 +2783,6 @@ PyObject *BPyInit_bgl(void) PY_DICT_ADD_INT(GL_UNSIGNED_INT_SAMPLER_BUFFER); } - /* GL_VERSION_3_2 */ { PY_DICT_ADD_INT(GL_ALREADY_SIGNALED); @@ -3685,4 +2888,4 @@ static PyObject *Method_ShaderSource(PyObject *UNUSED(self), PyObject *args) } -/** \} */
\ No newline at end of file +/** \} */ diff --git a/source/blender/python/generic/blf_py_api.c b/source/blender/python/generic/blf_py_api.c index 69f1e297b43..02bd1fdbe39 100644 --- a/source/blender/python/generic/blf_py_api.c +++ b/source/blender/python/generic/blf_py_api.c @@ -114,6 +114,7 @@ static PyObject *py_blf_aspect(PyObject *UNUSED(self), PyObject *args) } +#if BLF_BLUR_ENABLE PyDoc_STRVAR(py_blf_blur_doc, ".. function:: blur(fontid, radius)\n" "\n" @@ -135,6 +136,7 @@ static PyObject *py_blf_blur(PyObject *UNUSED(self), PyObject *args) Py_RETURN_NONE; } +#endif PyDoc_STRVAR(py_blf_draw_doc, @@ -418,7 +420,9 @@ static PyObject *py_blf_unload(PyObject *UNUSED(self), PyObject *args) /*----------------------------MODULE INIT-------------------------*/ static PyMethodDef BLF_methods[] = { {"aspect", (PyCFunction) py_blf_aspect, METH_VARARGS, py_blf_aspect_doc}, +#if BLF_BLUR_ENABLE {"blur", (PyCFunction) py_blf_blur, METH_VARARGS, py_blf_blur_doc}, +#endif {"clipping", (PyCFunction) py_blf_clipping, METH_VARARGS, py_blf_clipping_doc}, {"word_wrap", (PyCFunction) py_blf_word_wrap, METH_VARARGS, py_blf_word_wrap_doc}, {"disable", (PyCFunction) py_blf_disable, METH_VARARGS, py_blf_disable_doc}, 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/convertblender.c b/source/blender/render/intern/source/convertblender.c index 263ea3d4ef2..1ea99f406ba 100644 --- a/source/blender/render/intern/source/convertblender.c +++ b/source/blender/render/intern/source/convertblender.c @@ -4975,14 +4975,13 @@ static void add_group_render_dupli_obs(Render *re, Group *group, int nolamps, in } } -static void database_init_objects(Render *re, unsigned int renderlay, int nolamps, int onlyselected, Object *actob, int timeoffset) +static void database_init_objects(Render *re, unsigned int UNUSED(renderlay), int nolamps, int onlyselected, Object *actob, int timeoffset) { Base *base; Object *ob; Group *group; ObjectInstanceRen *obi; Scene *sce_iter; - int lay, vectorlay; /* for duplis we need the Object texture mapping to work as if * untransformed, set_dupli_tex_mat sets the matrix to allow that @@ -5010,14 +5009,18 @@ static void database_init_objects(Render *re, unsigned int renderlay, int nolamp for (SETLOOPER(re->scene, sce_iter, base)) { ob= base->object; +#if 0 + TODO_LAYER; /* investigate if this is an issue*/ /* in the prev/next pass for making speed vectors, avoid creating * objects that are not on a renderlayer with a vector pass, can * save a lot of time in complex scenes */ vectorlay= get_vector_renderlayers(re->scene); - lay= (timeoffset)? renderlay & vectorlay: renderlay; +#endif - /* if the object has been restricted from rendering in the outliner, ignore it */ - if (is_object_restricted(re, ob)) continue; + /* if the object is not visible, ignore it */ + if ((base->flag & BASE_VISIBLED) == 0) { + continue; + } /* OB_DONE means the object itself got duplicated, so was already converted */ if (ob->flag & OB_DONE) { @@ -5030,7 +5033,7 @@ static void database_init_objects(Render *re, unsigned int renderlay, int nolamp } } } - else if ((base->lay & lay) || (ob->type==OB_LAMP && (base->lay & re->lay)) ) { + else if (((base->flag & BASE_VISIBLED) != 0) || (ob->type==OB_LAMP)) { if ((ob->transflag & OB_DUPLI) && (ob->type!=OB_MBALL)) { DupliObject *dob; ListBase *duplilist; diff --git a/source/blender/render/intern/source/envmap.c b/source/blender/render/intern/source/envmap.c index d97e18d6511..33258d04673 100644 --- a/source/blender/render/intern/source/envmap.c +++ b/source/blender/render/intern/source/envmap.c @@ -51,6 +51,7 @@ #include "BKE_main.h" #include "BKE_image.h" /* BKE_imbuf_write */ +#include "BKE_layer.h" #include "BKE_texture.h" #include "BKE_scene.h" @@ -247,17 +248,14 @@ static void envmap_transmatrix(float mat[4][4], int part) static void env_set_imats(Render *re) { - Base *base; float mat[4][4]; - - base = re->scene->base.first; - while (base) { - mul_m4_m4m4(mat, re->viewmat, base->object->obmat); - invert_m4_m4(base->object->imat, mat); - - base = base->next; + + FOREACH_SCENE_OBJECT(re->scene, ob) + { + mul_m4_m4m4(mat, re->viewmat, ob->obmat); + invert_m4_m4(ob->imat, mat); } - + FOREACH_SCENE_OBJECT_END } /* ------------------------------------------------------------------------- */ 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/blender/render/intern/source/pipeline.c b/source/blender/render/intern/source/pipeline.c index 52eca5f7005..7598cb3ff6b 100644 --- a/source/blender/render/intern/source/pipeline.c +++ b/source/blender/render/intern/source/pipeline.c @@ -2012,14 +2012,14 @@ bool RE_allow_render_generic_object(Object *ob) #define DEPSGRAPH_WORKAROUND_HACK #ifdef DEPSGRAPH_WORKAROUND_HACK -static void tag_dependend_objects_for_render(Scene *scene, int renderlay) +static void tag_dependend_objects_for_render(Scene *scene, int UNUSED(renderlay)) { Scene *sce_iter; Base *base; for (SETLOOPER(scene, sce_iter, base)) { Object *object = base->object; - if ((base->lay & renderlay) == 0) { + if ((base->flag & BASE_VISIBLED) == 0) { continue; } diff --git a/source/blender/windowmanager/CMakeLists.txt b/source/blender/windowmanager/CMakeLists.txt index b6245a8c0d1..b5c19534b15 100644 --- a/source/blender/windowmanager/CMakeLists.txt +++ b/source/blender/windowmanager/CMakeLists.txt @@ -25,6 +25,8 @@ set(INC . + manipulators + manipulators/intern ../blenfont ../blenkernel ../blenlib @@ -68,6 +70,10 @@ set(SRC intern/wm_subwindow.c intern/wm_window.c intern/wm_stereo.c + manipulators/intern/wm_manipulator.c + manipulators/intern/wm_manipulatorgroup.c + manipulators/intern/wm_manipulatormap.c + manipulators/intern/manipulator_library/manipulator_library_utils.c WM_api.h WM_keymap.h @@ -80,6 +86,11 @@ set(SRC wm_files.h wm_subwindow.h wm_window.h + manipulators/WM_manipulator_api.h + manipulators/WM_manipulator_types.h + manipulators/wm_manipulator_wmapi.h + manipulators/intern/wm_manipulator_intern.h + manipulators/intern/manipulator_library/manipulator_library_intern.h ) if(WITH_AUDASPACE) diff --git a/source/blender/windowmanager/WM_api.h b/source/blender/windowmanager/WM_api.h index 2b82f1becb3..2809795268d 100644 --- a/source/blender/windowmanager/WM_api.h +++ b/source/blender/windowmanager/WM_api.h @@ -42,6 +42,9 @@ #include "WM_keymap.h" #include "BLI_compiler_attrs.h" +/* Include external manipulator API's */ +#include "manipulators/WM_manipulator_api.h" + #ifdef __cplusplus extern "C" { #endif @@ -64,12 +67,16 @@ struct wmDrag; struct ImBuf; struct ImageFormatData; struct ARegion; +struct ScrArea; #ifdef WITH_INPUT_NDOF struct wmNDOFMotionData; #endif typedef struct wmJob wmJob; +typedef struct wmManipulator wmManipulator; +typedef struct wmManipulatorMap wmManipulatorMap; +typedef struct wmManipulatorMapType wmManipulatorMapType; /* general API */ void WM_init_state_size_set (int stax, int stay, int sizx, int sizy); @@ -171,6 +178,9 @@ void WM_event_free_ui_handler_all( wmUIHandlerFunc ui_handle, wmUIHandlerRemoveFunc ui_remove); struct wmEventHandler *WM_event_add_modal_handler(struct bContext *C, struct wmOperator *op); +void WM_event_modal_handler_area_replace(wmWindow *win, const struct ScrArea *old_area, struct ScrArea *new_area); +void WM_event_modal_handler_region_replace(wmWindow *win, const struct ARegion *old_region, struct ARegion *new_region); + void WM_event_remove_handlers(struct bContext *C, ListBase *handlers); /* handler flag */ diff --git a/source/blender/windowmanager/WM_types.h b/source/blender/windowmanager/WM_types.h index cd46e24264d..3bed4dac2cf 100644 --- a/source/blender/windowmanager/WM_types.h +++ b/source/blender/windowmanager/WM_types.h @@ -119,6 +119,7 @@ struct ImBuf; /* exported types for WM */ #include "wm_cursors.h" #include "wm_event_types.h" +#include "manipulators/WM_manipulator_types.h" /* ************** wmOperatorType ************************ */ @@ -568,6 +569,9 @@ typedef struct wmOperatorType { /* pointer to modal keymap, do not free! */ struct wmKeyMap *modalkeymap; + /* manipulator-group that is accessible while operator runs */ + wmManipulatorGroupType *mgrouptype; + /* python needs the operator type as well */ int (*pyop_poll)(struct bContext *, struct wmOperatorType *ot) ATTR_WARN_UNUSED_RESULT; diff --git a/source/blender/windowmanager/intern/wm_dragdrop.c b/source/blender/windowmanager/intern/wm_dragdrop.c index 3a53906a8e8..2d1dcd7f3c9 100644 --- a/source/blender/windowmanager/intern/wm_dragdrop.c +++ b/source/blender/windowmanager/intern/wm_dragdrop.c @@ -268,10 +268,10 @@ void wm_drags_check_ops(bContext *C, wmEvent *event) static void wm_drop_operator_draw(const char *name, int x, int y) { const uiFontStyle *fstyle = UI_FSTYLE_WIDGET; - const unsigned char fg[4] = {255, 255, 255, 255}; - const unsigned char bg[4] = {0, 0, 0, 50}; + const float col_fg[4] = {1.0f, 1.0f, 1.0f, 1.0f}; + const float col_bg[4] = {0.0f, 0.0f, 0.0f, 0.2f}; - UI_fontstyle_draw_simple_backdrop(fstyle, x, y, name, fg, bg); + UI_fontstyle_draw_simple_backdrop(fstyle, x, y, name, col_fg, col_bg); } static const char *wm_drag_name(wmDrag *drag) @@ -361,8 +361,8 @@ void wm_drags_draw(bContext *C, wmWindow *win, rcti *rect) drag_rect_minmax(rect, x, y, x + w, y + iconsize); } else { - glColor4ub(255, 255, 255, 255); - UI_fontstyle_draw_simple(fstyle, x, y, wm_drag_name(drag)); + const unsigned char col[] = {255, 255, 255, 255}; + UI_fontstyle_draw_simple(fstyle, x, y, wm_drag_name(drag), col); } /* operator name with roundbox */ diff --git a/source/blender/windowmanager/intern/wm_draw.c b/source/blender/windowmanager/intern/wm_draw.c index 77ffa46b990..809a5cac6e8 100644 --- a/source/blender/windowmanager/intern/wm_draw.c +++ b/source/blender/windowmanager/intern/wm_draw.c @@ -59,6 +59,7 @@ #include "GPU_extensions.h" #include "GPU_glew.h" #include "GPU_basic_shader.h" +#include "GPU_immediate.h" #include "RE_engine.h" @@ -128,7 +129,7 @@ static bool wm_area_test_invalid_backbuf(ScrArea *sa) if (sa->spacetype == SPACE_VIEW3D) return (((View3D *)sa->spacedata.first)->flag & V3D_INVALID_BACKBUF) != 0; else - return 1; + return true; } static void wm_region_test_render_do_draw(bScreen *screen, ScrArea *sa, ARegion *ar) @@ -372,118 +373,116 @@ static void wm_draw_triple_fail(bContext *C, wmWindow *win) { wm_draw_window_clear(win); - win->drawfail = 1; + win->drawfail = true; wm_method_draw_overlap_all(C, win, 0); } -static int wm_triple_gen_textures(wmWindow *win, wmDrawTriple *triple) +static bool wm_triple_gen_textures(wmWindow *win, wmDrawTriple *triple) { - const int winsize_x = WM_window_pixels_x(win); - const int winsize_y = WM_window_pixels_y(win); - - GLint maxsize; - /* compute texture sizes */ - if (GLEW_ARB_texture_rectangle || GLEW_NV_texture_rectangle || GLEW_EXT_texture_rectangle) { - triple->target = GL_TEXTURE_RECTANGLE_ARB; - } - else { - triple->target = GL_TEXTURE_2D; - } - - triple->x = winsize_x; - triple->y = winsize_y; + triple->x = WM_window_pixels_x(win); + triple->y = WM_window_pixels_y(win); + +#if USE_TEXTURE_RECTANGLE + /* GL_TEXTURE_RECTANGLE is part of GL 3.1 so we can use it soon without runtime checks */ + triple->target = GL_TEXTURE_RECTANGLE; +#else + triple->target = GL_TEXTURE_2D; +#endif /* generate texture names */ glGenTextures(1, &triple->bind); - if (!triple->bind) { - /* not the typical failure case but we handle it anyway */ - printf("WM: failed to allocate texture for triple buffer drawing (glGenTextures).\n"); - return 0; - } - /* proxy texture is only guaranteed to test for the cases that * there is only one texture in use, which may not be the case */ - maxsize = GPU_max_texture_size(); + const GLint maxsize = GPU_max_texture_size(); if (triple->x > maxsize || triple->y > maxsize) { - glBindTexture(triple->target, 0); printf("WM: failed to allocate texture for triple buffer drawing " - "(texture too large for graphics card).\n"); - return 0; + "(texture too large for graphics card).\n"); + return false; } /* setup actual texture */ glBindTexture(triple->target, triple->bind); - glTexImage2D(triple->target, 0, GL_RGB8, triple->x, triple->y, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL); + + /* no mipmaps */ +#if USE_TEXTURE_RECTANGLE + /* already has no mipmaps */ +#else + glTexParameteri(triple->target, GL_TEXTURE_MAX_LEVEL, 0); + /* GL_TEXTURE_BASE_LEVEL = 0 by default */ +#endif + glTexParameteri(triple->target, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(triple->target, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glBindTexture(triple->target, 0); - /* not sure if this works everywhere .. */ - if (glGetError() == GL_OUT_OF_MEMORY) { - printf("WM: failed to allocate texture for triple buffer drawing (out of memory).\n"); - return 0; - } + glTexImage2D(triple->target, 0, GL_RGB8, triple->x, triple->y, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL); + + glBindTexture(triple->target, 0); - return 1; + return true; } -void wm_triple_draw_textures(wmWindow *win, wmDrawTriple *triple, float alpha, bool is_interlace) +void wm_triple_draw_textures(wmWindow *win, wmDrawTriple *triple, float alpha) { const int sizex = WM_window_pixels_x(win); const int sizey = WM_window_pixels_y(win); - float halfx, halfy, ratiox, ratioy; - /* wmOrtho for the screen has this same offset */ - ratiox = sizex; - ratioy = sizey; - halfx = GLA_PIXEL_OFS; - halfy = GLA_PIXEL_OFS; + float ratiox = sizex; + float ratioy = sizey; + float halfx = GLA_PIXEL_OFS; + float halfy = GLA_PIXEL_OFS; +#if USE_TEXTURE_RECTANGLE /* texture rectangle has unnormalized coordinates */ - if (triple->target == GL_TEXTURE_2D) { - ratiox /= triple->x; - ratioy /= triple->y; - halfx /= triple->x; - halfy /= triple->y; - } +#else + ratiox /= triple->x; + ratioy /= triple->y; + halfx /= triple->x; + halfy /= triple->y; +#endif - /* interlace stereo buffer bind the shader before calling wm_triple_draw_textures */ - if (is_interlace) { - glEnable(triple->target); - } - else { - GPU_basic_shader_bind((triple->target == GL_TEXTURE_2D) ? GPU_SHADER_TEXTURE_2D : GPU_SHADER_TEXTURE_RECT); - } + 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); + const int activeTex = 7; /* arbitrary */ + glActiveTexture(GL_TEXTURE0 + activeTex); glBindTexture(triple->target, triple->bind); - glColor4f(1.0f, 1.0f, 1.0f, alpha); - glBegin(GL_QUADS); - glTexCoord2f(halfx, halfy); - glVertex2f(0, 0); +#if USE_TEXTURE_RECTANGLE + immBindBuiltinProgram(GPU_SHADER_3D_IMAGE_RECT_MODULATE_ALPHA); +#else + immBindBuiltinProgram(GPU_SHADER_3D_IMAGE_MODULATE_ALPHA); + /* TODO: make pure 2D version + * and a 2D_IMAGE (replace, not modulate) version for when alpha = 1.0 + */ +#endif + immUniform1f("alpha", alpha); + immUniform1i("image", activeTex); - glTexCoord2f(ratiox + halfx, halfy); - glVertex2f(sizex, 0); + immBegin(GL_QUADS, 4); - glTexCoord2f(ratiox + halfx, ratioy + halfy); - glVertex2f(sizex, sizey); + immAttrib2f(texcoord, halfx, halfy); + immVertex2f(pos, 0.0f, 0.0f); - glTexCoord2f(halfx, ratioy + halfy); - glVertex2f(0, sizey); - glEnd(); + immAttrib2f(texcoord, ratiox + halfx, halfy); + immVertex2f(pos, sizex, 0.0f); - glBindTexture(triple->target, 0); + immAttrib2f(texcoord, ratiox + halfx, ratioy + halfy); + immVertex2f(pos, sizex, sizey); - if (is_interlace) { - glDisable(triple->target); - } - else { - GPU_basic_shader_bind(GPU_SHADER_USE_COLOR); - } + immAttrib2f(texcoord, halfx, ratioy + halfy); + immVertex2f(pos, 0.0f, sizey); + + immEnd(); + immUnbindProgram(); + + glBindTexture(triple->target, 0); + if (activeTex != 0) + glActiveTexture(GL_TEXTURE0); } static void wm_triple_copy_textures(wmWindow *win, wmDrawTriple *triple) @@ -492,8 +491,8 @@ static void wm_triple_copy_textures(wmWindow *win, wmDrawTriple *triple) const int sizey = WM_window_pixels_y(win); glBindTexture(triple->target, triple->bind); + /* what is GL_READ_BUFFER right now? */ glCopyTexSubImage2D(triple->target, 0, 0, 0, 0, 0, sizex, sizey); - glBindTexture(triple->target, 0); } @@ -506,7 +505,7 @@ static void wm_draw_region_blend(wmWindow *win, ARegion *ar, wmDrawTriple *tripl wmSubWindowScissorSet(win, win->screen->mainwin, &ar->winrct, true); glEnable(GL_BLEND); - wm_triple_draw_textures(win, triple, 1.0f - fac, false); + wm_triple_draw_textures(win, triple, 1.0f - fac); glDisable(GL_BLEND); } } @@ -514,20 +513,21 @@ static void wm_draw_region_blend(wmWindow *win, ARegion *ar, wmDrawTriple *tripl static void wm_method_draw_triple(bContext *C, wmWindow *win) { wmWindowManager *wm = CTX_wm_manager(C); - wmDrawTriple *triple; wmDrawData *dd, *dd_next, *drawdata = win->drawdata.first; bScreen *screen = win->screen; ScrArea *sa; ARegion *ar; - int copytex = false; + bool copytex = false; if (drawdata && drawdata->triple) { - glClearColor(0, 0, 0, 0); + #if 0 /* why do we need to clear before overwriting? */ + glClearColor(1, 1, 0, 0); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + #endif wmSubWindowSet(win, screen->mainwin); - wm_triple_draw_textures(win, drawdata->triple, 1.0f, false); + wm_triple_draw_textures(win, drawdata->triple, 1.0f); } else { /* we run it when we start OR when we turn stereo on */ @@ -554,7 +554,7 @@ static void wm_method_draw_triple(bContext *C, wmWindow *win) MEM_freeN(dd); } - triple = drawdata->triple; + wmDrawTriple *triple = drawdata->triple; /* draw marked area regions */ for (sa = screen->areabase.first; sa; sa = sa->next) { @@ -562,7 +562,6 @@ static void wm_method_draw_triple(bContext *C, wmWindow *win) for (ar = sa->regionbase.first; ar; ar = ar->next) { if (ar->swinid && ar->do_draw) { - if (ar->overlap == false) { CTX_wm_region_set(C, ar); ED_region_do_draw(C, ar); @@ -662,12 +661,14 @@ static void wm_method_draw_triple_multiview(bContext *C, wmWindow *win, StereoVi if (drawdata && drawdata->triple) { if (id == 0) { + #if 0 /* why do we need to clear before overwriting? */ glClearColor(0, 0, 0, 0); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + #endif wmSubWindowSet(win, screen->mainwin); - wm_triple_draw_textures(win, drawdata->triple, 1.0f, false); + wm_triple_draw_textures(win, drawdata->triple, 1.0f); } } else { @@ -849,20 +850,20 @@ static bool wm_draw_update_test_window(wmWindow *win) } if (do_draw) - return 1; + return true; if (win->screen->do_refresh) - return 1; + return true; if (win->screen->do_draw) - return 1; + return true; if (win->screen->do_draw_gesture) - return 1; + return true; if (win->screen->do_draw_paintcursor) - return 1; + return true; if (win->screen->do_draw_drag) - return 1; + return true; - return 0; + return false; } static int wm_automatic_draw_method(wmWindow *win) @@ -916,7 +917,6 @@ void wm_draw_update(bContext *C) { wmWindowManager *wm = CTX_wm_manager(C); wmWindow *win; - int drawmethod; #ifdef WITH_OPENSUBDIV BKE_subsurf_free_unused_buffers(); @@ -952,7 +952,7 @@ void wm_draw_update(bContext *C) if (win->screen->do_refresh) ED_screen_refresh(wm, win); - drawmethod = wm_automatic_draw_method(win); + int drawmethod = wm_automatic_draw_method(win); if (win->drawfail) wm_method_draw_overlap_all(C, win, 0); diff --git a/source/blender/windowmanager/intern/wm_event_system.c b/source/blender/windowmanager/intern/wm_event_system.c index d2b0acd836b..1a831846af7 100644 --- a/source/blender/windowmanager/intern/wm_event_system.c +++ b/source/blender/windowmanager/intern/wm_event_system.c @@ -68,8 +68,6 @@ #include "RNA_access.h" -#include "GPU_debug.h" - #include "UI_interface.h" #include "PIL_time.h" @@ -1677,7 +1675,12 @@ static int wm_handler_operator_call(bContext *C, ListBase *handlers, wmEventHand wm_handler_op_context(C, handler, event); wm_region_mouse_co(C, event); wm_event_modalkeymap(C, op, event, &dbl_click_disabled); - + + /* attach manipulator-map to handler if not there yet */ + if (ot->mgrouptype && !handler->manipulator_map) { + wm_manipulatorgroup_attach_to_modal_handler(C, handler, ot->mgrouptype, op); + } + if (ot->flag & OPTYPE_UNDO) wm->op_undo_depth++; @@ -1726,6 +1729,9 @@ static int wm_handler_operator_call(bContext *C, ListBase *handlers, wmEventHand CTX_wm_region_set(C, NULL); } + /* update manipulators during modal handlers */ + wm_manipulatormaps_handled_modal_update(C, event, handler, ot); + /* remove modal handler, operator itself should have been canceled and freed */ if (retval & (OPERATOR_CANCELLED | OPERATOR_FINISHED)) { WM_cursor_grab_disable(CTX_wm_window(C), NULL); @@ -2098,6 +2104,71 @@ static int wm_handlers_do_intern(bContext *C, wmEvent *event, ListBase *handlers } } } + else if (handler->manipulator_map) { + ScrArea *area = CTX_wm_area(C); + ARegion *region = CTX_wm_region(C); + wmManipulatorMap *mmap = handler->manipulator_map; + wmManipulator *manipulator = wm_manipulatormap_get_highlighted_manipulator(mmap); + unsigned char part; + + wm_manipulatormap_handler_context(C, handler); + wm_region_mouse_co(C, event); + + /* handle manipulator highlighting */ + if (event->type == MOUSEMOVE && !wm_manipulatormap_get_active_manipulator(mmap)) { + manipulator = wm_manipulatormap_find_highlighted_manipulator(mmap, C, event, &part); + wm_manipulatormap_set_highlighted_manipulator(mmap, C, manipulator, part); + } + /* handle user configurable manipulator-map keymap */ + else if (manipulator) { + /* get user customized keymap from default one */ + const wmManipulatorGroup *highlightgroup = wm_manipulator_get_parent_group(manipulator); + const wmKeyMap *keymap = WM_keymap_active(wm, highlightgroup->type->keymap); + wmKeyMapItem *kmi; + + PRINT("%s: checking '%s' ...", __func__, keymap->idname); + + if (!keymap->poll || keymap->poll(C)) { + PRINT("pass\n"); + for (kmi = keymap->items.first; kmi; kmi = kmi->next) { + if (wm_eventmatch(event, kmi)) { + wmOperator *op = handler->op; + + PRINT("%s: item matched '%s'\n", __func__, kmi->idname); + + /* weak, but allows interactive callback to not use rawkey */ + event->keymap_idname = kmi->idname; + + /* handler->op is called later, we want keymap op to be triggered here */ + handler->op = NULL; + action |= wm_handler_operator_call(C, handlers, handler, event, kmi->ptr); + handler->op = op; + + if (action & WM_HANDLER_BREAK) { + if (action & WM_HANDLER_HANDLED) { + if (G.debug & (G_DEBUG_EVENTS | G_DEBUG_HANDLERS)) + printf("%s: handled - and pass on! '%s'\n", __func__, kmi->idname); + } + else { + PRINT("%s: un-handled '%s'\n", __func__, kmi->idname); + } + } + } + } + } + else { + PRINT("fail\n"); + } + } + + /* restore the area */ + CTX_wm_area_set(C, area); + CTX_wm_region_set(C, region); + + if (handler->op) { + action |= wm_handler_operator_call(C, handlers, handler, event, NULL); + } + } else { /* modal, swallows all */ action |= wm_handler_operator_call(C, handlers, handler, event, NULL); @@ -2540,8 +2611,6 @@ void wm_event_do_handlers(bContext *C) /* update key configuration after handling events */ WM_keyconfig_update(wm); - - GPU_ASSERT_NO_GL_ERRORS("wm_event_do_handlers"); } /* ********** filesector handling ************ */ @@ -2578,7 +2647,7 @@ void WM_event_add_fileselect(bContext *C, wmOperator *op) wmWindow *win = CTX_wm_window(C); /* only allow 1 file selector open per window */ - for (handler = win->modalhandlers.first; handler; handler = handlernext) { + for (handler = win->handlers.first; handler; handler = handlernext) { handlernext = handler->next; if (handler->type == WM_HANDLER_FILESELECT) { @@ -2592,7 +2661,7 @@ void WM_event_add_fileselect(bContext *C, wmOperator *op) if (sfile->op == handler->op) { CTX_wm_area_set(C, sa); - wm_handler_fileselect_do(C, &win->modalhandlers, handler, EVT_FILESELECT_CANCEL); + wm_handler_fileselect_do(C, &win->handlers, handler, EVT_FILESELECT_CANCEL); break; } } @@ -2600,7 +2669,7 @@ void WM_event_add_fileselect(bContext *C, wmOperator *op) /* if not found we stop the handler without changing the screen */ if (!sa) - wm_handler_fileselect_do(C, &win->modalhandlers, handler, EVT_FILESELECT_EXTERNAL_CANCEL); + wm_handler_fileselect_do(C, &win->handlers, handler, EVT_FILESELECT_EXTERNAL_CANCEL); } } @@ -2611,7 +2680,7 @@ void WM_event_add_fileselect(bContext *C, wmOperator *op) handler->op_area = CTX_wm_area(C); handler->op_region = CTX_wm_region(C); - BLI_addhead(&win->modalhandlers, handler); + BLI_addhead(&win->handlers, handler); /* check props once before invoking if check is available * ensures initial properties are valid */ @@ -2654,6 +2723,33 @@ wmEventHandler *WM_event_add_modal_handler(bContext *C, wmOperator *op) return handler; } +/** + * Modal handlers store a pointer to an area which might be freed while the handler runs. + * Use this function to NULL all handler pointers to \a old_area. + */ +void WM_event_modal_handler_area_replace(wmWindow *win, const ScrArea *old_area, ScrArea *new_area) +{ + for (wmEventHandler *handler = win->modalhandlers.first; handler; handler = handler->next) { + if (handler->op_area == old_area) { + handler->op_area = new_area; + } + } +} + +/** + * Modal handlers store a pointer to a region which might be freed while the handler runs. + * Use this function to NULL all handler pointers to \a old_region. + */ +void WM_event_modal_handler_region_replace(wmWindow *win, const ARegion *old_region, ARegion *new_region) +{ + for (wmEventHandler *handler = win->modalhandlers.first; handler; handler = handler->next) { + if (handler->op_region == old_region) { + handler->op_region = new_region; + handler->op_region_type = new_region ? new_region->regiontype : RGN_TYPE_WINDOW; + } + } +} + wmEventHandler *WM_event_add_keymap_handler(ListBase *handlers, wmKeyMap *keymap) { wmEventHandler *handler; diff --git a/source/blender/windowmanager/intern/wm_init_exit.c b/source/blender/windowmanager/intern/wm_init_exit.c index c11c398c616..fbbde2a6d28 100644 --- a/source/blender/windowmanager/intern/wm_init_exit.c +++ b/source/blender/windowmanager/intern/wm_init_exit.c @@ -169,6 +169,7 @@ void WM_init(bContext *C, int argc, const char **argv) BKE_library_callback_free_window_manager_set(wm_close_and_free); /* library.c */ BKE_library_callback_free_notifier_reference_set(WM_main_remove_notifier_reference); /* library.c */ + BKE_region_callback_free_manipulatormap_set(wm_manipulatormap_delete); /* screen.c */ BKE_library_callback_remap_editor_id_reference_set(WM_main_remap_editor_id_reference); /* library.c */ BKE_blender_callback_test_break_set(wm_window_testbreak); /* blender.c */ BKE_spacedata_callback_id_remap_set(ED_spacedata_id_remap); /* screen.c */ @@ -529,6 +530,9 @@ void WM_exit_ext(bContext *C, const bool do_python) ED_gpencil_strokes_copybuf_free(); BKE_node_clipboard_clear(); + /* free manipulator-maps after freeing blender, so no deleted data get accessed during cleaning up of areas */ + wm_manipulatormaptypes_free(); + BLF_exit(); #ifdef WITH_INTERNATIONAL diff --git a/source/blender/windowmanager/intern/wm_operators.c b/source/blender/windowmanager/intern/wm_operators.c index cef5e7e4a8e..6591005b5f3 100644 --- a/source/blender/windowmanager/intern/wm_operators.c +++ b/source/blender/windowmanager/intern/wm_operators.c @@ -98,6 +98,7 @@ #include "ED_view3d.h" #include "GPU_basic_shader.h" +#include "GPU_immediate.h" #include "RNA_access.h" #include "RNA_define.h" @@ -491,6 +492,9 @@ void WM_operatortype_remove_ptr(wmOperatorType *ot) BLI_ghash_remove(global_ops_hash, ot->idname, NULL, NULL); WM_keyconfig_update_operatortype(); + if (ot->mgrouptype) { + WM_manipulatorgrouptype_unregister(NULL, G.main, ot->mgrouptype); + } MEM_freeN(ot); } @@ -2985,8 +2989,8 @@ static void radial_control_set_tex(RadialControl *rc) if ((ibuf = BKE_brush_gen_radial_control_imbuf(rc->image_id_ptr.data, rc->use_secondary_tex))) { glGenTextures(1, &rc->gltex); glBindTexture(GL_TEXTURE_2D, rc->gltex); - glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA8, ibuf->x, ibuf->y, 0, - GL_ALPHA, GL_FLOAT, ibuf->rect_float); + glTexImage2D(GL_TEXTURE_2D, 0, GL_R8, ibuf->x, ibuf->y, 0, + GL_RED, GL_FLOAT, ibuf->rect_float); MEM_freeN(ibuf->rect_float); MEM_freeN(ibuf); } @@ -3019,13 +3023,26 @@ static void radial_control_paint_tex(RadialControl *rc, float radius, float alph RNA_property_float_get_array(fill_ptr, fill_prop, col); } - glColor4f(col[0], col[1], col[2], alpha); + + VertexFormat *format = immVertexFormat(); + unsigned pos = add_attrib(format, "pos", GL_FLOAT, 2, KEEP_FLOAT); if (rc->gltex) { + + unsigned texCoord = add_attrib(format, "texCoord", GL_FLOAT, 2, KEEP_FLOAT); + glBindTexture(GL_TEXTURE_2D, rc->gltex); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + + GLint swizzleMask[] = {GL_ZERO, GL_ZERO, GL_ZERO, GL_RED}; + glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_RGBA, swizzleMask); + + immBindBuiltinProgram(GPU_SHADER_2D_IMAGE_MASK_UNIFORM_COLOR); + + immUniform4f("color", col[0], col[1], col[2], alpha); + immUniform1i("image", GL_TEXTURE0); /* set up rotation if available */ if (rc->rot_prop) { @@ -3035,18 +3052,21 @@ static void radial_control_paint_tex(RadialControl *rc, float radius, float alph } /* draw textured quad */ - GPU_basic_shader_bind(GPU_SHADER_TEXTURE_2D | GPU_SHADER_USE_COLOR); - glBegin(GL_QUADS); - glTexCoord2f(0, 0); - glVertex2f(-radius, -radius); - glTexCoord2f(1, 0); - glVertex2f(radius, -radius); - glTexCoord2f(1, 1); - glVertex2f(radius, radius); - glTexCoord2f(0, 1); - glVertex2f(-radius, radius); - glEnd(); - GPU_basic_shader_bind(GPU_SHADER_USE_COLOR); + immBegin(GL_QUADS, 4); + + immAttrib2f(texCoord, 0, 0); + immVertex2f(pos, -radius, -radius); + + immAttrib2f(texCoord, 1, 0); + immVertex2f(pos, radius, -radius); + + immAttrib2f(texCoord, 1, 1); + immVertex2f(pos, radius, radius); + + immAttrib2f(texCoord, 0, 1); + immVertex2f(pos, -radius, radius); + + immEnd(); /* undo rotation */ if (rc->rot_prop) @@ -3054,8 +3074,12 @@ static void radial_control_paint_tex(RadialControl *rc, float radius, float alph } else { /* flat color if no texture available */ - glutil_draw_filled_arc(0, M_PI * 2, radius, 40); + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + immUniformColor3fvAlpha(col, alpha); + imm_draw_filled_circle(pos, 0.0f, 0.0f, radius, 40); } + + immUnbindProgram(); } static void radial_control_paint_cursor(bContext *C, int x, int y, void *customdata) @@ -3131,24 +3155,38 @@ static void radial_control_paint_cursor(bContext *C, int x, int y, void *customd /* set line color */ if (rc->col_prop) RNA_property_float_get_array(&rc->col_ptr, rc->col_prop, col); - glColor4f(col[0], col[1], col[2], 0.5); + + VertexFormat *format = immVertexFormat(); + unsigned pos = add_attrib(format, "pos", GL_FLOAT, 2, KEEP_FLOAT); + + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + immUniformColor3fvAlpha(col, 0.5); if (rc->subtype == PROP_ANGLE) { glPushMatrix(); + /* draw original angle line */ glRotatef(RAD2DEGF(rc->initial_value), 0, 0, 1); - fdrawline((float)WM_RADIAL_CONTROL_DISPLAY_MIN_SIZE, 0.0f, (float)WM_RADIAL_CONTROL_DISPLAY_SIZE, 0.0f); + immBegin(GL_LINES, 2); + immVertex2f(pos, (float)WM_RADIAL_CONTROL_DISPLAY_MIN_SIZE, 0.0f); + immVertex2f(pos, (float)WM_RADIAL_CONTROL_DISPLAY_SIZE, 0.0f); + immEnd(); + /* draw new angle line */ glRotatef(RAD2DEGF(rc->current_value - rc->initial_value), 0, 0, 1); - fdrawline((float)WM_RADIAL_CONTROL_DISPLAY_MIN_SIZE, 0.0f, (float)WM_RADIAL_CONTROL_DISPLAY_SIZE, 0.0f); + immBegin(GL_LINES, 2); + immVertex2f(pos, (float)WM_RADIAL_CONTROL_DISPLAY_MIN_SIZE, 0.0f); + immVertex2f(pos, (float)WM_RADIAL_CONTROL_DISPLAY_SIZE, 0.0f); + immEnd(); + glPopMatrix(); } /* draw circles on top */ - glutil_draw_lined_arc(0.0, (float)(M_PI * 2.0), r1, 40); - glutil_draw_lined_arc(0.0, (float)(M_PI * 2.0), r2, 40); + imm_draw_lined_circle(pos, 0.0f, 0.0f, r1, 40); + imm_draw_lined_circle(pos, 0.0f, 0.0f, r2, 40); if (rmin > 0.0f) - glutil_draw_lined_arc(0.0, (float)(M_PI * 2.0), rmin, 40); + imm_draw_lined_circle(pos, 0.0, 0.0f, rmin, 40); BLF_size(fontid, 1.5 * fstyle_points * U.pixelsize, U.dpi); BLF_enable(fontid, BLF_SHADOW); @@ -3164,6 +3202,8 @@ static void radial_control_paint_cursor(bContext *C, int x, int y, void *customd glDisable(GL_BLEND); glDisable(GL_LINE_SMOOTH); + + immUnbindProgram(); } typedef enum { @@ -4174,6 +4214,10 @@ void wm_operatortype_init(void) WM_operatortype_append(WM_OT_previews_ensure); WM_operatortype_append(WM_OT_previews_clear); WM_operatortype_append(WM_OT_doc_view_manual_ui_context); + + /* manipulators */ + WM_operatortype_append(MANIPULATORGROUP_OT_manipulator_select); + WM_operatortype_append(MANIPULATORGROUP_OT_manipulator_tweak); } /* circleselect-like modal operators */ @@ -4479,6 +4523,7 @@ void wm_window_keymap(wmKeyConfig *keyconf) RNA_float_set(kmi->ptr, "value", 1.0f / 1.5f); #endif /* WITH_INPUT_NDOF */ + wm_manipulators_keymap(keyconf); gesture_circle_modal_keymap(keyconf); gesture_border_modal_keymap(keyconf); gesture_zoom_border_modal_keymap(keyconf); diff --git a/source/blender/windowmanager/intern/wm_stereo.c b/source/blender/windowmanager/intern/wm_stereo.c index 46cee907991..d312f4c007c 100644 --- a/source/blender/windowmanager/intern/wm_stereo.c +++ b/source/blender/windowmanager/intern/wm_stereo.c @@ -54,6 +54,7 @@ #include "GPU_glew.h" #include "GPU_basic_shader.h" +#include "GPU_immediate.h" #include "WM_api.h" #include "WM_types.h" @@ -77,54 +78,82 @@ static void wm_method_draw_stereo3d_pageflip(wmWindow *win) else //STEREO_RIGHT_ID glDrawBuffer(GL_BACK_RIGHT); - wm_triple_draw_textures(win, drawdata->triple, 1.0f, false); + wm_triple_draw_textures(win, drawdata->triple, 1.0f); } glDrawBuffer(GL_BACK); } -static enum eStereo3dInterlaceType interlace_prev_type = -1; -static char interlace_prev_swap = -1; +static GPUInterlaceShader interlace_gpu_id_from_type(eStereo3dInterlaceType interlace_type) +{ + switch (interlace_type) { + case S3D_INTERLACE_ROW: + return GPU_SHADER_INTERLACE_ROW; + case S3D_INTERLACE_COLUMN: + return GPU_SHADER_INTERLACE_COLUMN; + case S3D_INTERLACE_CHECKERBOARD: + default: + return GPU_SHADER_INTERLACE_CHECKER; + } +} static void wm_method_draw_stereo3d_interlace(wmWindow *win) { - wmDrawData *drawdata; - int view; - bool flag; bool swap = (win->stereo3d_format->flag & S3D_INTERLACE_SWAP) != 0; enum eStereo3dInterlaceType interlace_type = win->stereo3d_format->interlace_type; - for (view = 0; view < 2; view ++) { - flag = swap ? !view : view; - drawdata = BLI_findlink(&win->drawdata, (view * 2) + 1); - GPU_basic_shader_bind(GPU_SHADER_STIPPLE); - switch (interlace_type) { - case S3D_INTERLACE_ROW: - if (flag) - GPU_basic_shader_stipple(GPU_SHADER_STIPPLE_S3D_INTERLACE_ROW_SWAP); - else - GPU_basic_shader_stipple(GPU_SHADER_STIPPLE_S3D_INTERLACE_ROW); - break; - case S3D_INTERLACE_COLUMN: - if (flag) - GPU_basic_shader_stipple(GPU_SHADER_STIPPLE_S3D_INTERLACE_COLUMN_SWAP); - else - GPU_basic_shader_stipple(GPU_SHADER_STIPPLE_S3D_INTERLACE_COLUMN); - break; - case S3D_INTERLACE_CHECKERBOARD: - default: - if (flag) - GPU_basic_shader_stipple(GPU_SHADER_STIPPLE_S3D_INTERLACE_CHECKER_SWAP); - else - GPU_basic_shader_stipple(GPU_SHADER_STIPPLE_S3D_INTERLACE_CHECKER); - break; - } + wmDrawData *drawdata[2]; + for (int eye = 0; eye < 2; eye++) { + int view = swap ? !eye : eye; + drawdata[eye] = BLI_findlink(&win->drawdata, (view * 2) + 1); + } + + const int sizex = WM_window_pixels_x(win); + const int sizey = WM_window_pixels_y(win); + + /* wmOrtho for the screen has this same offset */ + float ratiox = sizex; + float ratioy = sizey; + float halfx = GLA_PIXEL_OFS; + float halfy = GLA_PIXEL_OFS; + + 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_2D_IMAGE_INTERLACE); + + /* leave GL_TEXTURE0 as the latest bind texture */ + for (int eye = 1; eye >= 0; eye--) { + glActiveTexture(GL_TEXTURE0 + eye); + glBindTexture(drawdata[eye]->triple->target, drawdata[eye]->triple->bind); + } - wm_triple_draw_textures(win, drawdata->triple, 1.0f, true); - GPU_basic_shader_bind(GPU_SHADER_USE_COLOR); + immUniform1i("image_a", 0); + immUniform1i("image_b", 1); + + immUniform1i("interlace_id", interlace_gpu_id_from_type(interlace_type)); + + immBegin(GL_QUADS, 4); + + immAttrib2f(texcoord, halfx, halfy); + immVertex2f(pos, 0.0f, 0.0f); + + immAttrib2f(texcoord, ratiox + halfx, halfy); + immVertex2f(pos, sizex, 0.0f); + + immAttrib2f(texcoord, ratiox + halfx, ratioy + halfy); + immVertex2f(pos, sizex, sizey); + + immAttrib2f(texcoord, halfx, ratioy + halfy); + immVertex2f(pos, 0.0f, sizey); + + immEnd(); + immUnbindProgram(); + + for (int eye = 0; eye < 2; eye++) { + glBindTexture(drawdata[eye]->triple->target, 0); } - interlace_prev_type = interlace_type; - interlace_prev_swap = swap; } static void wm_method_draw_stereo3d_anaglyph(wmWindow *win) @@ -157,7 +186,7 @@ static void wm_method_draw_stereo3d_anaglyph(wmWindow *win) break; } - wm_triple_draw_textures(win, drawdata->triple, 1.0f, false); + wm_triple_draw_textures(win, drawdata->triple, 1.0f); glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); } @@ -172,6 +201,10 @@ static void wm_method_draw_stereo3d_sidebyside(wmWindow *win) int soffx; bool cross_eyed = (win->stereo3d_format->flag & S3D_SIDEBYSIDE_CROSSEYED) != 0; + 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); + for (view = 0; view < 2; view ++) { drawdata = BLI_findlink(&win->drawdata, (view * 2) + 1); triple = drawdata->triple; @@ -203,26 +236,33 @@ static void wm_method_draw_stereo3d_sidebyside(wmWindow *win) halfy /= triple->y; } - glEnable(triple->target); + /* TODO: if target is always same for both eyes, bind program & set uniform before loop */ + immBindBuiltinProgram((triple->target == GL_TEXTURE_2D) ? GPU_SHADER_3D_IMAGE_MODULATE_ALPHA : GPU_SHADER_3D_IMAGE_RECT_MODULATE_ALPHA); + glBindTexture(triple->target, triple->bind); - glColor4f(1.0f, 1.0f, 1.0f, 1.0f); - glBegin(GL_QUADS); - glTexCoord2f(halfx, halfy); - glVertex2f(soffx, 0); + immUniform1f("alpha", 1.0f); + immUniform1i("image", 0); /* default GL_TEXTURE0 unit */ + + immBegin(GL_QUADS, 4); + + immAttrib2f(texcoord, halfx, halfy); + immVertex2f(pos, soffx, 0.0f); - glTexCoord2f(ratiox + halfx, halfy); - glVertex2f(soffx + (sizex * 0.5f), 0); + immAttrib2f(texcoord, ratiox + halfx, halfy); + immVertex2f(pos, soffx + (sizex * 0.5f), 0.0f); - glTexCoord2f(ratiox + halfx, ratioy + halfy); - glVertex2f(soffx + (sizex * 0.5f), sizey); + immAttrib2f(texcoord, ratiox + halfx, ratioy + halfy); + immVertex2f(pos, soffx + (sizex * 0.5f), sizey); - glTexCoord2f(halfx, ratioy + halfy); - glVertex2f(soffx, sizey); - glEnd(); + immAttrib2f(texcoord, halfx, ratioy + halfy); + immVertex2f(pos, soffx, sizey); + immEnd(); + + /* TODO: if target is always same for both eyes, unbind program & texture target after loop */ glBindTexture(triple->target, 0); - glDisable(triple->target); + immUnbindProgram(); } } @@ -234,6 +274,10 @@ static void wm_method_draw_stereo3d_topbottom(wmWindow *win) int view; int soffy; + 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); + for (view = 0; view < 2; view ++) { drawdata = BLI_findlink(&win->drawdata, (view * 2) + 1); triple = drawdata->triple; @@ -262,26 +306,33 @@ static void wm_method_draw_stereo3d_topbottom(wmWindow *win) halfy /= triple->y; } - glEnable(triple->target); + /* TODO: if target is always same for both eyes, bind program & set uniforms before loop */ + immBindBuiltinProgram((triple->target == GL_TEXTURE_2D) ? GPU_SHADER_3D_IMAGE_MODULATE_ALPHA : GPU_SHADER_3D_IMAGE_RECT_MODULATE_ALPHA); + glBindTexture(triple->target, triple->bind); - glColor4f(1.0f, 1.0f, 1.0f, 1.0f); - glBegin(GL_QUADS); - glTexCoord2f(halfx, halfy); - glVertex2f(0, soffy); + immUniform1f("alpha", 1.0f); + immUniform1i("image", 0); /* default GL_TEXTURE0 unit */ + + immBegin(GL_QUADS, 4); + + immAttrib2f(texcoord, halfx, halfy); + immVertex2f(pos, 0.0f, soffy); + + immAttrib2f(texcoord, ratiox + halfx, halfy); + immVertex2f(pos, sizex, soffy); - glTexCoord2f(ratiox + halfx, halfy); - glVertex2f(sizex, soffy); + immAttrib2f(texcoord, ratiox + halfx, ratioy + halfy); + immVertex2f(pos, sizex, soffy + (sizey * 0.5f)); - glTexCoord2f(ratiox + halfx, ratioy + halfy); - glVertex2f(sizex, soffy + (sizey * 0.5f)); + immAttrib2f(texcoord, halfx, ratioy + halfy); + immVertex2f(pos, 0.0f, soffy + (sizey * 0.5f)); - glTexCoord2f(halfx, ratioy + halfy); - glVertex2f(0, soffy + (sizey * 0.5f)); - glEnd(); + immEnd(); + /* TODO: if target is always same for both eyes, unbind program & texture target after loop */ + immUnbindProgram(); glBindTexture(triple->target, 0); - glDisable(triple->target); } } @@ -310,9 +361,9 @@ void wm_method_draw_stereo3d(const bContext *UNUSED(C), wmWindow *win) static bool wm_stereo3d_quadbuffer_supported(void) { - int gl_stereo = 0; - glGetBooleanv(GL_STEREO, (GLboolean *)&gl_stereo); - return gl_stereo != 0; + GLboolean stereo = GL_FALSE; + glGetBooleanv(GL_STEREO, &stereo); + return stereo == GL_TRUE; } static bool wm_stereo3d_is_fullscreen_required(eStereoDisplayMode stereo_display) diff --git a/source/blender/windowmanager/intern/wm_window.c b/source/blender/windowmanager/intern/wm_window.c index 2d43c47679d..e271225e437 100644 --- a/source/blender/windowmanager/intern/wm_window.c +++ b/source/blender/windowmanager/intern/wm_window.c @@ -51,6 +51,7 @@ #include "BKE_blender.h" #include "BKE_context.h" +#include "BKE_icons.h" #include "BKE_library.h" #include "BKE_global.h" #include "BKE_main.h" @@ -76,7 +77,7 @@ #include "GPU_draw.h" #include "GPU_extensions.h" #include "GPU_init_exit.h" -#include "GPU_glew.h" +#include "GPU_immediate.h" /* for assert */ #ifndef NDEBUG @@ -827,13 +828,16 @@ void wm_window_make_drawable(wmWindowManager *wm, wmWindow *win) { if (win != wm->windrawable && win->ghostwin) { // win->lmbut = 0; /* keeps hanging when mousepressed while other window opened */ - + wm->windrawable = win; if (G.debug & G_DEBUG_EVENTS) { printf("%s: set drawable %d\n", __func__, win->winid); } + + immDeactivate(); GHOST_ActivateWindowDrawingContext(win->ghostwin); - + immActivate(); + /* this can change per window */ U.pixelsize = wm_window_pixelsize(win); BKE_blender_userdef_refresh(); @@ -1102,6 +1106,7 @@ static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr C_void_ptr wm_window_make_drawable(wm, win); wm_draw_window_clear(win); + BKE_icon_changed(win->screen->id.icon_id); WM_event_add_notifier(C, NC_SCREEN | NA_EDITED, NULL); WM_event_add_notifier(C, NC_WINDOW | NA_EDITED, NULL); @@ -1203,6 +1208,7 @@ static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr C_void_ptr if (U.pixelsize != prev_pixelsize) { BKE_blender_userdef_refresh(); + BKE_icon_changed(win->screen->id.icon_id); // close all popups since they are positioned with the pixel // size baked in and it's difficult to correct them diff --git a/source/blender/windowmanager/manipulators/WM_manipulator_api.h b/source/blender/windowmanager/manipulators/WM_manipulator_api.h new file mode 100644 index 00000000000..099ad7fd851 --- /dev/null +++ b/source/blender/windowmanager/manipulators/WM_manipulator_api.h @@ -0,0 +1,110 @@ +/* + * ***** 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) 2016 Blender Foundation. + * All rights reserved. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/windowmanager/manipulators/WM_manipulator_api.h + * \ingroup wm + * + * \name Manipulator API + * \brief API for external use of wmManipulator types. + * + * Only included in WM_api.h + */ + + +#ifndef __WM_MANIPULATOR_API_H__ +#define __WM_MANIPULATOR_API_H__ + +struct ARegion; +struct Main; +struct wmKeyConfig; +struct wmManipulatorGroupType; +struct wmManipulatorMap; +struct wmManipulatorMapType; +struct wmManipulatorMapType_Params; + +/* -------------------------------------------------------------------- */ +/* wmManipulator */ + +struct wmManipulator *WM_manipulator_new( + void (*draw)(const struct bContext *, struct wmManipulator *), + void (*render_3d_intersection)(const struct bContext *, struct wmManipulator *, int), + int (*intersect)(struct bContext *, const struct wmEvent *, struct wmManipulator *), + int (*handler)(struct bContext *, const struct wmEvent *, struct wmManipulator *, const int)); +void WM_manipulator_delete( + ListBase *manipulatorlist, struct wmManipulatorMap *mmap, struct wmManipulator *manipulator, + struct bContext *C); + +void WM_manipulator_set_property(struct wmManipulator *, int slot, struct PointerRNA *ptr, const char *propname); +struct PointerRNA *WM_manipulator_set_operator(struct wmManipulator *, const char *opname); +void WM_manipulator_set_func_select( + struct wmManipulator *manipulator, + void (*select)(struct bContext *, struct wmManipulator *, const int action)); /* wmManipulatorSelectFunc */ +void WM_manipulator_set_origin(struct wmManipulator *manipulator, const float origin[3]); +void WM_manipulator_set_offset(struct wmManipulator *manipulator, const float offset[3]); +void WM_manipulator_set_flag(struct wmManipulator *manipulator, const int flag, const bool enable); +void WM_manipulator_set_scale(struct wmManipulator *manipulator, float scale); +void WM_manipulator_set_line_width(struct wmManipulator *manipulator, const float line_width); +void WM_manipulator_set_colors(struct wmManipulator *manipulator, const float col[4], const float col_hi[4]); + + +/* -------------------------------------------------------------------- */ +/* wmManipulatorGroup */ + +struct wmManipulatorGroupType *WM_manipulatorgrouptype_append( + struct wmManipulatorMapType *mmaptype, + void (*mgrouptype_func)(struct wmManipulatorGroupType *)); +struct wmManipulatorGroupType *WM_manipulatorgrouptype_append_runtime( + const struct Main *main, struct wmManipulatorMapType *mmaptype, + void (*mgrouptype_func)(struct wmManipulatorGroupType *)); +void WM_manipulatorgrouptype_init_runtime( + const struct Main *bmain, struct wmManipulatorMapType *mmaptype, + struct wmManipulatorGroupType *mgrouptype); +void WM_manipulatorgrouptype_unregister( + struct bContext *C, struct Main *bmain, struct wmManipulatorGroupType *mgroup); + +struct wmKeyMap *WM_manipulatorgroup_keymap_common( + const struct wmManipulatorGroupType *mgrouptype, struct wmKeyConfig *config); +struct wmKeyMap *WM_manipulatorgroup_keymap_common_sel( + const struct wmManipulatorGroupType *mgrouptype, struct wmKeyConfig *config); + + +/* -------------------------------------------------------------------- */ +/* wmManipulatorMap */ + +struct wmManipulatorMapType *WM_manipulatormaptype_find( + const struct wmManipulatorMapType_Params *mmap_params); +struct wmManipulatorMapType *WM_manipulatormaptype_ensure( + const struct wmManipulatorMapType_Params *mmap_params); + +struct wmManipulatorMap *WM_manipulatormap_new_from_type( + const struct wmManipulatorMapType_Params *mmap_params); +void WM_manipulatormap_tag_refresh(struct wmManipulatorMap *mmap); +void WM_manipulatormap_draw(struct wmManipulatorMap *mmap, const struct bContext *C, const int drawstep); +void WM_manipulatormap_add_handlers(struct ARegion *ar, struct wmManipulatorMap *mmap); +bool WM_manipulatormap_select_all(struct bContext *C, struct wmManipulatorMap *mmap, const int action); +bool WM_manipulatormap_cursor_set(const struct wmManipulatorMap *mmap, struct wmWindow *win); + +#endif /* __WM_MANIPULATOR_API_H__ */ + diff --git a/source/blender/windowmanager/manipulators/WM_manipulator_types.h b/source/blender/windowmanager/manipulators/WM_manipulator_types.h new file mode 100644 index 00000000000..284a3e9bd22 --- /dev/null +++ b/source/blender/windowmanager/manipulators/WM_manipulator_types.h @@ -0,0 +1,167 @@ +/* + * ***** 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) 2016 Blender Foundation. + * All rights reserved. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/windowmanager/manipulators/WM_manipulator_types.h + * \ingroup wm + * + * \name Manipulator Types + * \brief Manipulator defines for external use. + * + * Only included in WM_types.h and lower level files. + */ + + +#ifndef __WM_MANIPULATOR_TYPES_H__ +#define __WM_MANIPULATOR_TYPES_H__ + +#include "BLI_compiler_attrs.h" + +struct wmManipulatorGroupType; +struct wmManipulatorGroup; +struct wmKeyConfig; + +typedef bool (*wmManipulatorGroupPollFunc)(const struct bContext *, struct wmManipulatorGroupType *) ATTR_WARN_UNUSED_RESULT; +typedef void (*wmManipulatorGroupInitFunc)(const struct bContext *, struct wmManipulatorGroup *); +typedef void (*wmManipulatorGroupRefreshFunc)(const struct bContext *, struct wmManipulatorGroup *); +typedef void (*wmManipulatorGroupDrawPrepareFunc)(const struct bContext *, struct wmManipulatorGroup *); + + +/* -------------------------------------------------------------------- */ +/* wmManipulator */ + +/** + * Simple utility wrapper for storing a single manipulator as wmManipulatorGroup.customdata (which gets freed). + */ +typedef struct wmManipulatorWrapper { + struct wmManipulator *manipulator; +} wmManipulatorWrapper; + +/* wmManipulator.flag + * Flags for individual manipulators. */ +enum { + WM_MANIPULATOR_DRAW_HOVER = (1 << 0), /* draw *only* while hovering */ + WM_MANIPULATOR_DRAW_ACTIVE = (1 << 1), /* draw while dragging */ + WM_MANIPULATOR_DRAW_VALUE = (1 << 2), /* draw an indicator for the current value while dragging */ + WM_MANIPULATOR_HIDDEN = (1 << 3), +}; + + +/* -------------------------------------------------------------------- */ +/* wmManipulatorGroup */ + +typedef struct wmManipulatorGroup { + struct wmManipulatorGroup *next, *prev; + + struct wmManipulatorGroupType *type; + ListBase manipulators; + + void *py_instance; /* python stores the class instance here */ + struct ReportList *reports; /* errors and warnings storage */ + + void *customdata; + void (*customdata_free)(void *); /* for freeing customdata from above */ + int flag; /* private */ + int pad; +} wmManipulatorGroup; + +/* factory class for a manipulator-group type, gets called every time a new area is spawned */ +typedef struct wmManipulatorGroupType { + struct wmManipulatorGroupType *next, *prev; + + char idname[64]; /* MAX_NAME */ + const char *name; /* manipulator-group name - displayed in UI (keymap editor) */ + + /* poll if manipulator-map should be visible */ + wmManipulatorGroupPollFunc poll; + /* initially create manipulators and set permanent data - stuff you only need to do once */ + wmManipulatorGroupInitFunc init; + /* refresh data, only called if recreate flag is set (WM_manipulatormap_tag_refresh) */ + wmManipulatorGroupRefreshFunc refresh; + /* refresh data for drawing, called before each redraw */ + wmManipulatorGroupDrawPrepareFunc draw_prepare; + + /* keymap init callback for this manipulator-group */ + struct wmKeyMap *(*keymap_init)(const struct wmManipulatorGroupType *, struct wmKeyConfig *); + /* keymap created with callback from above */ + struct wmKeyMap *keymap; + + /* rna for properties */ + struct StructRNA *srna; + + /* RNA integration */ + ExtensionRNA ext; + + int flag; + + /* if type is spawned from operator this is set here */ + void *op; + + /* same as manipulator-maps, so registering/unregistering goes to the correct region */ + short spaceid, regionid; + char mapidname[64]; +} wmManipulatorGroupType; + +/** + * wmManipulatorGroupType.flag + * Flags that influence the behavior of all manipulators in the group. + */ +enum { + /* Mark manipulator-group as being 3D */ + WM_MANIPULATORGROUPTYPE_IS_3D = (1 << 0), + /* Scale manipulators as 3D object that respects zoom (otherwise zoom independent draw size) */ + WM_MANIPULATORGROUPTYPE_SCALE_3D = (1 << 1), + /* Manipulators can be depth culled with scene objects (covered by other geometry - TODO) */ + WM_MANIPULATORGROUPTYPE_SCENE_DEPTH = (1 << 2), + /* Manipulators can be selected */ + WM_MANIPULATORGROUPTYPE_SELECTABLE = (1 << 3), + /* manipulator group is attached to operator, and is only accessible as long as this runs */ + WM_MANIPULATORGROUPTYPE_OP = (1 << 4), +}; + + +/* -------------------------------------------------------------------- */ +/* wmManipulatorMap */ + +struct wmManipulatorMapType_Params { + const char *idname; + const int spaceid; + const int regionid; +}; + +/** + * Pass a value of this enum to #WM_manipulatormap_draw to tell it what to draw. + */ +enum { + /* Draw 2D manipulator-groups (ManipulatorGroupType.is_3d == false) */ + WM_MANIPULATORMAP_DRAWSTEP_2D = 0, + /* Draw 3D manipulator-groups (ManipulatorGroupType.is_3d == true) */ + WM_MANIPULATORMAP_DRAWSTEP_3D, + /* Draw only depth culled manipulators (WM_MANIPULATOR_SCENE_DEPTH flag). + * Note that these are expected to be 3D manipulators too. */ + WM_MANIPULATORMAP_DRAWSTEP_IN_SCENE, +}; + +#endif /* __WM_MANIPULATOR_TYPES_H__ */ + diff --git a/source/blender/windowmanager/manipulators/intern/manipulator_library/manipulator_library_intern.h b/source/blender/windowmanager/manipulators/intern/manipulator_library/manipulator_library_intern.h new file mode 100644 index 00000000000..66598fa29d7 --- /dev/null +++ b/source/blender/windowmanager/manipulators/intern/manipulator_library/manipulator_library_intern.h @@ -0,0 +1,100 @@ +/* + * ***** 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) 2016 Blender Foundation. + * All rights reserved. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/windowmanager/manipulators/intern/manipulator_library/manipulator_library_intern.h + * \ingroup wm + */ + + +#ifndef __MANIPULATOR_LIBRARY_INTERN_H__ +#define __MANIPULATOR_LIBRARY_INTERN_H__ + +/* distance around which manipulators respond to input (and get highlighted) */ +#define MANIPULATOR_HOTSPOT 14.0f + +/** + * Data for common interactions. Used in manipulator_library_utils.c functions. + */ +typedef struct ManipulatorCommonData { + int flag; + + float range_fac; /* factor for arrow min/max distance */ + float offset; + + /* property range for constrained manipulators */ + float range; + /* min/max value for constrained manipulators */ + float min, max; +} ManipulatorCommonData; + +typedef struct ManipulatorInteraction { + float init_value; /* initial property value */ + float init_origin[3]; + float init_mval[2]; + float init_offset; + float init_scale; + + /* offset of last handling step */ + float prev_offset; + /* Total offset added by precision tweaking. + * Needed to allow toggling precision on/off without causing jumps */ + float precision_offset; +} ManipulatorInteraction; + +/* ManipulatorCommonData->flag */ +enum { + MANIPULATOR_CUSTOM_RANGE_SET = (1 << 0), +}; + + +float manipulator_offset_from_value( + ManipulatorCommonData *data, const float value, + const bool constrained, const bool inverted); +float manipulator_value_from_offset( + ManipulatorCommonData *data, ManipulatorInteraction *inter, const float offset, + const bool constrained, const bool inverted, const bool use_precision); + +void manipulator_property_data_update( + wmManipulator *manipulator, ManipulatorCommonData *data, const int slot, + const bool constrained, const bool inverted); + +void manipulator_property_value_set( + bContext *C, const wmManipulator *manipulator, + const int slot, const float value); +float manipulator_property_value_get( + const wmManipulator *manipulator, const int slot); +void manipulator_property_value_reset( + bContext *C, const wmManipulator *manipulator, ManipulatorInteraction *inter, + const int slot); + + +/* -------------------------------------------------------------------- */ + +void manipulator_color_get( + const wmManipulator *manipulator, const bool highlight, + float r_col[]); + +#endif /* __MANIPULATOR_LIBRARY_INTERN_H__ */ + diff --git a/source/blender/windowmanager/manipulators/intern/manipulator_library/manipulator_library_utils.c b/source/blender/windowmanager/manipulators/intern/manipulator_library/manipulator_library_utils.c new file mode 100644 index 00000000000..0617e9e873b --- /dev/null +++ b/source/blender/windowmanager/manipulators/intern/manipulator_library/manipulator_library_utils.c @@ -0,0 +1,171 @@ +/* + * ***** 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) 2015 Blender Foundation. + * All rights reserved. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/windowmanager/manipulators/intern/manipulator_library/manipulator_library_utils.c + * \ingroup wm + * + * \name Manipulator Library Utilities + * + * \brief This file contains functions for common behaviors of manipulators. + */ + +#include "BKE_context.h" + +#include "BLI_math.h" + +#include "RNA_access.h" + +#include "WM_api.h" + +/* own includes */ +#include "WM_manipulator_types.h" +#include "wm_manipulator_wmapi.h" +#include "wm_manipulator_intern.h" +#include "manipulator_library_intern.h" + +/* factor for precision tweaking */ +#define MANIPULATOR_PRECISION_FAC 0.05f + + +BLI_INLINE float manipulator_offset_from_value_constr( + const float range_fac, const float min, const float range, const float value, + const bool inverted) +{ + return inverted ? (range_fac * (min + range - value) / range) : (range_fac * (value / range)); +} + +BLI_INLINE float manipulator_value_from_offset_constr( + const float range_fac, const float min, const float range, const float value, + const bool inverted) +{ + return inverted ? (min + range - (value * range / range_fac)) : (value * range / range_fac); +} + +float manipulator_offset_from_value( + ManipulatorCommonData *data, const float value, const bool constrained, const bool inverted) +{ + if (constrained) + return manipulator_offset_from_value_constr(data->range_fac, data->min, data->range, value, inverted); + + return value; +} + +float manipulator_value_from_offset( + ManipulatorCommonData *data, ManipulatorInteraction *inter, const float offset, + const bool constrained, const bool inverted, const bool use_precision) +{ + const float max = data->min + data->range; + + if (use_precision) { + /* add delta offset of this step to total precision_offset */ + inter->precision_offset += offset - inter->prev_offset; + } + inter->prev_offset = offset; + + float ofs_new = inter->init_offset + offset - inter->precision_offset * (1.0f - MANIPULATOR_PRECISION_FAC); + float value; + + if (constrained) { + value = manipulator_value_from_offset_constr(data->range_fac, data->min, data->range, ofs_new, inverted); + } + else { + value = ofs_new; + } + + /* clamp to custom range */ + if (data->flag & MANIPULATOR_CUSTOM_RANGE_SET) { + CLAMP(value, data->min, max); + } + + return value; +} + +void manipulator_property_data_update( + wmManipulator *manipulator, ManipulatorCommonData *data, const int slot, + const bool constrained, const bool inverted) +{ + if (!manipulator->props[slot]) { + data->offset = 0.0f; + return; + } + + PointerRNA ptr = manipulator->ptr[slot]; + PropertyRNA *prop = manipulator->props[slot]; + float value = manipulator_property_value_get(manipulator, slot); + + if (constrained) { + if ((data->flag & MANIPULATOR_CUSTOM_RANGE_SET) == 0) { + float step, precision; + float min, max; + RNA_property_float_ui_range(&ptr, prop, &min, &max, &step, &precision); + data->range = max - min; + data->min = min; + } + data->offset = manipulator_offset_from_value_constr(data->range_fac, data->min, data->range, value, inverted); + } + else { + data->offset = value; + } +} + +void manipulator_property_value_set( + bContext *C, const wmManipulator *manipulator, + const int slot, const float value) +{ + PointerRNA ptr = manipulator->ptr[slot]; + PropertyRNA *prop = manipulator->props[slot]; + + /* reset property */ + RNA_property_float_set(&ptr, prop, value); + RNA_property_update(C, &ptr, prop); +} + +float manipulator_property_value_get(const wmManipulator *manipulator, const int slot) +{ + BLI_assert(RNA_property_type(manipulator->props[slot]) == PROP_FLOAT); + return RNA_property_float_get(&manipulator->ptr[slot], manipulator->props[slot]); +} + +void manipulator_property_value_reset( + bContext *C, const wmManipulator *manipulator, ManipulatorInteraction *inter, + const int slot) +{ + manipulator_property_value_set(C, manipulator, slot, inter->init_value); +} + + +/* -------------------------------------------------------------------- */ + +void manipulator_color_get( + const wmManipulator *manipulator, const bool highlight, + float r_col[4]) +{ + if (highlight && !(manipulator->flag & WM_MANIPULATOR_DRAW_HOVER)) { + copy_v4_v4(r_col, manipulator->col_hi); + } + else { + copy_v4_v4(r_col, manipulator->col); + } +} diff --git a/source/blender/windowmanager/manipulators/intern/wm_manipulator.c b/source/blender/windowmanager/manipulators/intern/wm_manipulator.c new file mode 100644 index 00000000000..7fdbb0d6324 --- /dev/null +++ b/source/blender/windowmanager/manipulators/intern/wm_manipulator.c @@ -0,0 +1,404 @@ +/* + * ***** 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) 2014 Blender Foundation. + * All rights reserved. + * + * Contributor(s): Blender Foundation + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/windowmanager/manipulators/intern/wm_manipulator.c + * \ingroup wm + */ + +#include "BKE_context.h" + +#include "BLI_listbase.h" +#include "BLI_math.h" +#include "BLI_string.h" +#include "BLI_string_utils.h" + +#include "ED_screen.h" +#include "ED_view3d.h" + +#include "GL/glew.h" + +#include "MEM_guardedalloc.h" + +#include "RNA_access.h" + +#include "WM_api.h" +#include "WM_types.h" + +/* own includes */ +#include "wm_manipulator_wmapi.h" +#include "wm_manipulator_intern.h" + + +/* Still unused */ +wmManipulator *WM_manipulator_new( + void (*draw)(const bContext *C, wmManipulator *customdata), + void (*render_3d_intersection)(const bContext *C, wmManipulator *customdata, int selectionbase), + int (*intersect)(bContext *C, const wmEvent *event, wmManipulator *manipulator), + int (*handler)(bContext *C, const wmEvent *event, wmManipulator *manipulator, const int flag)) +{ + wmManipulator *manipulator = MEM_callocN(sizeof(wmManipulator), "manipulator"); + + manipulator->draw = draw; + manipulator->handler = handler; + manipulator->intersect = intersect; + manipulator->render_3d_intersection = render_3d_intersection; + + /* XXX */ +// fix_linking_manipulator_arrow(); +// fix_linking_manipulator_arrow2d(); +// fix_linking_manipulator_cage(); +// fix_linking_manipulator_dial(); +// fix_linking_manipulator_facemap(); +// fix_linking_manipulator_primitive(); + + return manipulator; +} + +/** + * Assign an idname that is unique in \a mgroup to \a manipulator. + * + * \param rawname: Name used as basis to define final unique idname. + */ +static void manipulator_unique_idname_set(wmManipulatorGroup *mgroup, wmManipulator *manipulator, const char *rawname) +{ + if (mgroup->type->idname[0]) { + BLI_snprintf(manipulator->idname, sizeof(manipulator->idname), "%s_%s", mgroup->type->idname, rawname); + } + else { + BLI_strncpy(manipulator->idname, rawname, sizeof(manipulator->idname)); + } + + /* ensure name is unique, append '.001', '.002', etc if not */ + BLI_uniquename(&mgroup->manipulators, manipulator, "Manipulator", '.', + offsetof(wmManipulator, idname), sizeof(manipulator->idname)); +} + +/** + * Initialize default values and allocate needed memory for members. + */ +static void manipulator_init(wmManipulator *manipulator) +{ + const float col_default[4] = {1.0f, 1.0f, 1.0f, 1.0f}; + + manipulator->user_scale = 1.0f; + manipulator->line_width = 1.0f; + + /* defaults */ + copy_v4_v4(manipulator->col, col_default); + copy_v4_v4(manipulator->col_hi, col_default); + + /* create at least one property for interaction */ + if (manipulator->max_prop == 0) { + manipulator->max_prop = 1; + } + + manipulator->props = MEM_callocN(sizeof(PropertyRNA *) * manipulator->max_prop, "manipulator->props"); + manipulator->ptr = MEM_callocN(sizeof(PointerRNA) * manipulator->max_prop, "manipulator->ptr"); +} + +/** + * Register \a manipulator. + * + * \param name: name used to create a unique idname for \a manipulator in \a mgroup + */ +void wm_manipulator_register(wmManipulatorGroup *mgroup, wmManipulator *manipulator, const char *name) +{ + manipulator_init(manipulator); + manipulator_unique_idname_set(mgroup, manipulator, name); + wm_manipulatorgroup_manipulator_register(mgroup, manipulator); +} + +/** + * Free \a manipulator and unlink from \a manipulatorlist. + * \a manipulatorlist is allowed to be NULL. + */ +void WM_manipulator_delete(ListBase *manipulatorlist, wmManipulatorMap *mmap, wmManipulator *manipulator, bContext *C) +{ + if (manipulator->state & WM_MANIPULATOR_HIGHLIGHT) { + wm_manipulatormap_set_highlighted_manipulator(mmap, C, NULL, 0); + } + if (manipulator->state & WM_MANIPULATOR_ACTIVE) { + wm_manipulatormap_set_active_manipulator(mmap, C, NULL, NULL); + } + if (manipulator->state & WM_MANIPULATOR_SELECTED) { + wm_manipulator_deselect(mmap, manipulator); + } + + if (manipulator->opptr.data) { + WM_operator_properties_free(&manipulator->opptr); + } + MEM_freeN(manipulator->props); + MEM_freeN(manipulator->ptr); + + if (manipulatorlist) + BLI_remlink(manipulatorlist, manipulator); + MEM_freeN(manipulator); +} + +wmManipulatorGroup *wm_manipulator_get_parent_group(const wmManipulator *manipulator) +{ + return manipulator->mgroup; +} + + +/* -------------------------------------------------------------------- */ +/** \name Manipulator Creation API + * + * API for defining data on manipulator creation. + * + * \{ */ + +void WM_manipulator_set_property(wmManipulator *manipulator, const int slot, PointerRNA *ptr, const char *propname) +{ + if (slot < 0 || slot >= manipulator->max_prop) { + fprintf(stderr, "invalid index %d when binding property for manipulator type %s\n", slot, manipulator->idname); + return; + } + + /* if manipulator evokes an operator we cannot use it for property manipulation */ + manipulator->opname = NULL; + manipulator->ptr[slot] = *ptr; + manipulator->props[slot] = RNA_struct_find_property(ptr, propname); + + if (manipulator->prop_data_update) + manipulator->prop_data_update(manipulator, slot); +} + +PointerRNA *WM_manipulator_set_operator(wmManipulator *manipulator, const char *opname) +{ + wmOperatorType *ot = WM_operatortype_find(opname, 0); + + if (ot) { + manipulator->opname = opname; + + if (manipulator->opptr.data) { + WM_operator_properties_free(&manipulator->opptr); + } + WM_operator_properties_create_ptr(&manipulator->opptr, ot); + + return &manipulator->opptr; + } + else { + fprintf(stderr, "Error binding operator to manipulator: operator %s not found!\n", opname); + } + + return NULL; +} + +/** + * \brief Set manipulator select callback. + * + * Callback is called when manipulator gets selected/deselected. + */ +void WM_manipulator_set_func_select(wmManipulator *manipulator, wmManipulatorSelectFunc select) +{ + BLI_assert(manipulator->mgroup->type->flag & WM_MANIPULATORGROUPTYPE_SELECTABLE); + manipulator->select = select; +} + +void WM_manipulator_set_origin(wmManipulator *manipulator, const float origin[3]) +{ + copy_v3_v3(manipulator->origin, origin); +} + +void WM_manipulator_set_offset(wmManipulator *manipulator, const float offset[3]) +{ + copy_v3_v3(manipulator->offset, offset); +} + +void WM_manipulator_set_flag(wmManipulator *manipulator, const int flag, const bool enable) +{ + if (enable) { + manipulator->flag |= flag; + } + else { + manipulator->flag &= ~flag; + } +} + +void WM_manipulator_set_scale(wmManipulator *manipulator, const float scale) +{ + manipulator->user_scale = scale; +} + +void WM_manipulator_set_line_width(wmManipulator *manipulator, const float line_width) +{ + manipulator->line_width = line_width; +} + +/** + * Set manipulator rgba colors. + * + * \param col Normal state color. + * \param col_hi Highlighted state color. + */ +void WM_manipulator_set_colors(wmManipulator *manipulator, const float col[4], const float col_hi[4]) +{ + copy_v4_v4(manipulator->col, col); + copy_v4_v4(manipulator->col_hi, col_hi); +} + +/** \} */ // Manipulator Creation API + + +/* -------------------------------------------------------------------- */ + +/** + * Remove \a manipulator from selection. + * Reallocates memory for selected manipulators so better not call for selecting multiple ones. + * + * \return if the selection has changed. + */ +bool wm_manipulator_deselect(wmManipulatorMap *mmap, wmManipulator *manipulator) +{ + if (!mmap->mmap_context.selected_manipulator) + return false; + + wmManipulator ***sel = &mmap->mmap_context.selected_manipulator; + int *tot_selected = &mmap->mmap_context.tot_selected; + bool changed = false; + + /* caller should check! */ + BLI_assert(manipulator->state & WM_MANIPULATOR_SELECTED); + + /* remove manipulator from selected_manipulators array */ + for (int i = 0; i < (*tot_selected); i++) { + if ((*sel)[i] == manipulator) { + for (int j = i; j < ((*tot_selected) - 1); j++) { + (*sel)[j] = (*sel)[j + 1]; + } + changed = true; + break; + } + } + + /* update array data */ + if ((*tot_selected) <= 1) { + wm_manipulatormap_selected_delete(mmap); + } + else { + *sel = MEM_reallocN(*sel, sizeof(**sel) * (*tot_selected)); + (*tot_selected)--; + } + + manipulator->state &= ~WM_MANIPULATOR_SELECTED; + return changed; +} + +/** + * Add \a manipulator to selection. + * Reallocates memory for selected manipulators so better not call for selecting multiple ones. + * + * \return if the selection has changed. + */ +bool wm_manipulator_select(bContext *C, wmManipulatorMap *mmap, wmManipulator *manipulator) +{ + wmManipulator ***sel = &mmap->mmap_context.selected_manipulator; + int *tot_selected = &mmap->mmap_context.tot_selected; + + if (!manipulator || (manipulator->state & WM_MANIPULATOR_SELECTED)) + return false; + + (*tot_selected)++; + + *sel = MEM_reallocN(*sel, sizeof(wmManipulator *) * (*tot_selected)); + (*sel)[(*tot_selected) - 1] = manipulator; + + manipulator->state |= WM_MANIPULATOR_SELECTED; + if (manipulator->select) { + manipulator->select(C, manipulator, SEL_SELECT); + } + wm_manipulatormap_set_highlighted_manipulator(mmap, C, manipulator, manipulator->highlighted_part); + + return true; +} + +void wm_manipulator_calculate_scale(wmManipulator *manipulator, const bContext *C) +{ + const RegionView3D *rv3d = CTX_wm_region_view3d(C); + float scale = 1.0f; + + if (manipulator->mgroup->type->flag & WM_MANIPULATORGROUPTYPE_SCALE_3D) { + if (rv3d /*&& (U.manipulator_flag & V3D_3D_MANIPULATORS) == 0*/) { /* UserPref flag might be useful for later */ + if (manipulator->get_final_position) { + float position[3]; + + manipulator->get_final_position(manipulator, position); + scale = ED_view3d_pixel_size(rv3d, position) * (float)U.manipulator_scale; + } + else { + scale = ED_view3d_pixel_size(rv3d, manipulator->origin) * (float)U.manipulator_scale; + } + } + else { + scale = U.manipulator_scale * 0.02f; + } + } + + manipulator->scale = scale * manipulator->user_scale; +} + +static void manipulator_update_prop_data(wmManipulator *manipulator) +{ + /* manipulator property might have been changed, so update manipulator */ + if (manipulator->props && manipulator->prop_data_update) { + for (int i = 0; i < manipulator->max_prop; i++) { + if (manipulator->props[i]) { + manipulator->prop_data_update(manipulator, i); + } + } + } +} + +void wm_manipulator_update(wmManipulator *manipulator, const bContext *C, const bool refresh_map) +{ + if (refresh_map) { + manipulator_update_prop_data(manipulator); + } + wm_manipulator_calculate_scale(manipulator, C); +} + +bool wm_manipulator_is_visible(wmManipulator *manipulator) +{ + if (manipulator->flag & WM_MANIPULATOR_HIDDEN) { + return false; + } + if ((manipulator->state & WM_MANIPULATOR_ACTIVE) && + !(manipulator->flag & (WM_MANIPULATOR_DRAW_ACTIVE | WM_MANIPULATOR_DRAW_VALUE))) + { + /* don't draw while active (while dragging) */ + return false; + } + if ((manipulator->flag & WM_MANIPULATOR_DRAW_HOVER) && + !(manipulator->state & WM_MANIPULATOR_HIGHLIGHT) && + !(manipulator->state & WM_MANIPULATOR_SELECTED)) /* still draw selected manipulators */ + { + /* only draw on mouse hover */ + return false; + } + + return true; +} + diff --git a/source/blender/windowmanager/manipulators/intern/wm_manipulator_intern.h b/source/blender/windowmanager/manipulators/intern/wm_manipulator_intern.h new file mode 100644 index 00000000000..1a9693a472b --- /dev/null +++ b/source/blender/windowmanager/manipulators/intern/wm_manipulator_intern.h @@ -0,0 +1,230 @@ +/* + * ***** 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. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/windowmanager/manipulators/intern/wm_manipulator_intern.h + * \ingroup wm + */ + + +#ifndef __WM_MANIPULATOR_INTERN_H__ +#define __WM_MANIPULATOR_INTERN_H__ + +struct wmKeyConfig; +struct wmManipulatorMap; + +/* -------------------------------------------------------------------- */ +/* wmManipulator */ + +/* manipulators are set per region by registering them on manipulator-maps */ +typedef struct wmManipulator { + struct wmManipulator *next, *prev; + + char idname[MAX_NAME + 4]; /* + 4 for unique '.001', '.002', etc suffix */ + /* pointer back to group this manipulator is in (just for quick access) */ + struct wmManipulatorGroup *mgroup; + + /* could become wmManipulatorType */ + /* draw manipulator */ + void (*draw)(const struct bContext *, struct wmManipulator *); + + /* determine if the mouse intersects with the manipulator. The calculation should be done in the callback itself */ + int (*intersect)(struct bContext *, const struct wmEvent *, struct wmManipulator *); + + /* determines 3d intersection by rendering the manipulator in a selection routine. */ + void (*render_3d_intersection)(const struct bContext *, struct wmManipulator *, int); + + /* handler used by the manipulator. Usually handles interaction tied to a manipulator type */ + int (*handler)(struct bContext *, const struct wmEvent *, struct wmManipulator *, const int); + + /* manipulator-specific handler to update manipulator attributes based on the property value */ + void (*prop_data_update)(struct wmManipulator *, int); + + /* returns the final position which may be different from the origin, depending on the manipulator. + * used in calculations of scale */ + void (*get_final_position)(struct wmManipulator *, float[]); + + /* activate a manipulator state when the user clicks on it */ + int (*invoke)(struct bContext *, const struct wmEvent *, struct wmManipulator *); + + /* called when manipulator tweaking is done - used to free data and reset property when cancelling */ + void (*exit)(struct bContext *, struct wmManipulator *, const bool ); + + int (*get_cursor)(struct wmManipulator *); + + /* called when manipulator selection state changes */ + wmManipulatorSelectFunc select; + + int flag; /* flags that influence the behavior or how the manipulators are drawn */ + short state; /* state flags (active, highlighted, selected) */ + + unsigned char highlighted_part; + + /* center of manipulator in space, 2d or 3d */ + float origin[3]; + /* custom offset from origin */ + float offset[3]; + /* runtime property, set the scale while drawing on the viewport */ + float scale; + /* user defined scale, in addition to the original one */ + float user_scale; + /* user defined width for line drawing */ + float line_width; + /* manipulator colors (uses default fallbacks if not defined) */ + float col[4], col_hi[4]; + + /* data used during interaction */ + void *interaction_data; + + /* name of operator to spawn when activating the manipulator */ + const char *opname; + /* operator properties if manipulator spawns and controls an operator, + * or owner pointer if manipulator spawns and controls a property */ + PointerRNA opptr; + + /* maximum number of properties attached to the manipulator */ + int max_prop; + /* arrays of properties attached to various manipulator parameters. As + * the manipulator is interacted with, those properties get updated */ + PointerRNA *ptr; + PropertyRNA **props; +} wmManipulator; + +/* wmManipulator.state */ +enum { + WM_MANIPULATOR_HIGHLIGHT = (1 << 0), /* while hovered */ + WM_MANIPULATOR_ACTIVE = (1 << 1), /* while dragging */ + WM_MANIPULATOR_SELECTED = (1 << 2), +}; + +/** + * \brief Manipulator tweak flag. + * Bitflag passed to manipulator while tweaking. + */ +enum { + /* drag with extra precision (shift) + * NOTE: Manipulators are responsible for handling this (manipulator->handler callback)! */ + WM_MANIPULATOR_TWEAK_PRECISE = (1 << 0), +}; + +void wm_manipulator_register(struct wmManipulatorGroup *mgroup, struct wmManipulator *manipulator, const char *name); + +bool wm_manipulator_deselect(struct wmManipulatorMap *mmap, struct wmManipulator *manipulator); +bool wm_manipulator_select(bContext *C, struct wmManipulatorMap *mmap, struct wmManipulator *manipulator); + +void wm_manipulator_calculate_scale(struct wmManipulator *manipulator, const bContext *C); +void wm_manipulator_update(struct wmManipulator *manipulator, const bContext *C, const bool refresh_map); +bool wm_manipulator_is_visible(struct wmManipulator *manipulator); + +void fix_linking_manipulator_arrow(void); +void fix_linking_manipulator_arrow2d(void); +void fix_linking_manipulator_cage(void); +void fix_linking_manipulator_dial(void); +void fix_linking_manipulator_facemap(void); +void fix_linking_manipulator_primitive(void); + + +/* -------------------------------------------------------------------- */ +/* wmManipulatorGroup */ + +enum { + TWEAK_MODAL_CANCEL = 1, + TWEAK_MODAL_CONFIRM, + TWEAK_MODAL_PRECISION_ON, + TWEAK_MODAL_PRECISION_OFF, +}; + +struct wmManipulatorGroup *wm_manipulatorgroup_new_from_type(struct wmManipulatorGroupType *mgrouptype); +void wm_manipulatorgroup_free(bContext *C, struct wmManipulatorMap *mmap, struct wmManipulatorGroup *mgroup); +void wm_manipulatorgroup_manipulator_register(struct wmManipulatorGroup *mgroup, wmManipulator *manipulator); +wmManipulator *wm_manipulatorgroup_find_intersected_mainpulator( + const struct wmManipulatorGroup *mgroup, struct bContext *C, const struct wmEvent *event, + unsigned char *part); +void wm_manipulatorgroup_intersectable_manipulators_to_list( + const struct wmManipulatorGroup *mgroup, struct ListBase *listbase); +void wm_manipulatorgroup_ensure_initialized(struct wmManipulatorGroup *mgroup, const struct bContext *C); +bool wm_manipulatorgroup_is_visible(const struct wmManipulatorGroup *mgroup, const struct bContext *C); +bool wm_manipulatorgroup_is_visible_in_drawstep(const struct wmManipulatorGroup *mgroup, const int drawstep); + +void wm_manipulatorgrouptype_keymap_init(struct wmManipulatorGroupType *mgrouptype, struct wmKeyConfig *keyconf); + + +/* -------------------------------------------------------------------- */ +/* wmManipulatorMap */ + +typedef struct wmManipulatorMap { + struct wmManipulatorMap *next, *prev; + + struct wmManipulatorMapType *type; + ListBase manipulator_groups; + + char update_flag; /* private, update tagging */ + + /** + * \brief Manipulator map runtime context + * + * Contains information about this manipulator-map. Currently + * highlighted manipulator, currently selected manipulators, ... + */ + struct { + /* we redraw the manipulator-map when this changes */ + struct wmManipulator *highlighted_manipulator; + /* user has clicked this manipulator and it gets all input */ + struct wmManipulator *active_manipulator; + /* array for all selected manipulators + * TODO check on using BLI_array */ + struct wmManipulator **selected_manipulator; + int tot_selected; + } mmap_context; +} wmManipulatorMap; + +/** + * This is a container for all manipulator types that can be instantiated in a region. + * (similar to dropboxes). + * + * \note There is only ever one of these for every (area, region) combination. + */ +typedef struct wmManipulatorMapType { + struct wmManipulatorMapType *next, *prev; + char idname[64]; + short spaceid, regionid; + /* types of manipulator-groups for this manipulator-map type */ + ListBase manipulator_grouptypes; +} wmManipulatorMapType; + +void wm_manipulatormap_selected_delete(wmManipulatorMap *mmap); +bool wm_manipulatormap_deselect_all(struct wmManipulatorMap *mmap, wmManipulator ***sel); + + +/* -------------------------------------------------------------------- */ +/* Manipulator drawing */ + +typedef struct ManipulatorGeometryInfo { + int nverts; + int ntris; + float (*verts)[3]; + float (*normals)[3]; + unsigned short *indices; + bool init; +} ManipulatorGeometryInfo; + +#endif /* __WM_MANIPULATOR_INTERN_H__ */ + diff --git a/source/blender/windowmanager/manipulators/intern/wm_manipulatorgroup.c b/source/blender/windowmanager/manipulators/intern/wm_manipulatorgroup.c new file mode 100644 index 00000000000..f9f46b0f71a --- /dev/null +++ b/source/blender/windowmanager/manipulators/intern/wm_manipulatorgroup.c @@ -0,0 +1,588 @@ +/* + * ***** 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) 2014 Blender Foundation. + * All rights reserved. + * + * Contributor(s): Blender Foundation + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/windowmanager/manipulators/intern/wm_manipulatorgroup.c + * \ingroup wm + * + * \name Manipulator-Group + * + * Manipulator-groups store and manage groups of manipulators. They can be + * attached to modal handlers and have own keymaps. + */ + +#include <stdlib.h> + +#include "BKE_context.h" +#include "BKE_main.h" +#include "BKE_report.h" + +#include "BLI_listbase.h" +#include "BLI_string.h" + +#include "BPY_extern.h" + +#include "ED_screen.h" + +#include "MEM_guardedalloc.h" + +#include "RNA_access.h" + +#include "WM_api.h" +#include "WM_types.h" +#include "wm_event_system.h" + +/* own includes */ +#include "wm_manipulator_wmapi.h" +#include "wm_manipulator_intern.h" + + +/* -------------------------------------------------------------------- */ +/** \name wmManipulatorGroup + * + * \{ */ + +/* wmManipulatorGroup.flag */ +enum { + WM_MANIPULATORGROUP_INITIALIZED = (1 << 2), /* mgroup has been initialized */ +}; + +/** + * Create a new manipulator-group from \a mgrouptype. + */ +wmManipulatorGroup *wm_manipulatorgroup_new_from_type(wmManipulatorGroupType *mgrouptype) +{ + wmManipulatorGroup *mgroup = MEM_callocN(sizeof(*mgroup), "manipulator-group"); + mgroup->type = mgrouptype; + + return mgroup; +} + +void wm_manipulatorgroup_free(bContext *C, wmManipulatorMap *mmap, wmManipulatorGroup *mgroup) +{ + for (wmManipulator *manipulator = mgroup->manipulators.first; manipulator;) { + wmManipulator *manipulator_next = manipulator->next; + WM_manipulator_delete(&mgroup->manipulators, mmap, manipulator, C); + manipulator = manipulator_next; + } + BLI_assert(BLI_listbase_is_empty(&mgroup->manipulators)); + +#ifdef WITH_PYTHON + if (mgroup->py_instance) { + /* do this first in case there are any __del__ functions or + * similar that use properties */ + BPY_DECREF_RNA_INVALIDATE(mgroup->py_instance); + } +#endif + + if (mgroup->reports && (mgroup->reports->flag & RPT_FREE)) { + BKE_reports_clear(mgroup->reports); + MEM_freeN(mgroup->reports); + } + + if (mgroup->customdata_free) { + mgroup->customdata_free(mgroup->customdata); + } + else { + MEM_SAFE_FREE(mgroup->customdata); + } + + BLI_remlink(&mmap->manipulator_groups, mgroup); + MEM_freeN(mgroup); +} + +/** + * Add \a manipulator to \a mgroup and make sure its name is unique within the group. + */ +void wm_manipulatorgroup_manipulator_register(wmManipulatorGroup *mgroup, wmManipulator *manipulator) +{ + BLI_assert(!BLI_findstring(&mgroup->manipulators, manipulator->idname, offsetof(wmManipulator, idname))); + BLI_addtail(&mgroup->manipulators, manipulator); + manipulator->mgroup = mgroup; +} + +void wm_manipulatorgroup_attach_to_modal_handler( + bContext *C, wmEventHandler *handler, + wmManipulatorGroupType *mgrouptype, wmOperator *op) +{ + /* maybe overly careful, but manipulator-grouptype could come from a failed creation */ + if (!mgrouptype) { + return; + } + + /* now instantiate the manipulator-map */ + mgrouptype->op = op; + + /* try to find map in handler region that contains mgrouptype */ + if (handler->op_region && handler->op_region->manipulator_map) { + handler->manipulator_map = handler->op_region->manipulator_map; + ED_region_tag_redraw(handler->op_region); + } + + WM_event_add_mousemove(C); +} + +wmManipulator *wm_manipulatorgroup_find_intersected_mainpulator( + const wmManipulatorGroup *mgroup, bContext *C, const wmEvent *event, + unsigned char *part) +{ + for (wmManipulator *manipulator = mgroup->manipulators.first; manipulator; manipulator = manipulator->next) { + if (manipulator->intersect && (manipulator->flag & WM_MANIPULATOR_HIDDEN) == 0) { + if ((*part = manipulator->intersect(C, event, manipulator))) { + return manipulator; + } + } + } + + return NULL; +} + +/** + * Adds all manipulators of \a mgroup that can be selected to the head of \a listbase. Added items need freeing! + */ +void wm_manipulatorgroup_intersectable_manipulators_to_list(const wmManipulatorGroup *mgroup, ListBase *listbase) +{ + for (wmManipulator *manipulator = mgroup->manipulators.first; manipulator; manipulator = manipulator->next) { + if ((manipulator->flag & WM_MANIPULATOR_HIDDEN) == 0) { + if (((mgroup->type->flag & WM_MANIPULATORGROUPTYPE_IS_3D) && manipulator->render_3d_intersection) || + ((mgroup->type->flag & WM_MANIPULATORGROUPTYPE_IS_3D) == 0 && manipulator->intersect)) + { + BLI_addhead(listbase, BLI_genericNodeN(manipulator)); + } + } + } +} + +void wm_manipulatorgroup_ensure_initialized(wmManipulatorGroup *mgroup, const bContext *C) +{ + /* prepare for first draw */ + if (UNLIKELY((mgroup->flag & WM_MANIPULATORGROUP_INITIALIZED) == 0)) { + mgroup->type->init(C, mgroup); + mgroup->flag |= WM_MANIPULATORGROUP_INITIALIZED; + } +} + +bool wm_manipulatorgroup_is_visible(const wmManipulatorGroup *mgroup, const bContext *C) +{ + /* Check for poll function, if manipulator-group belongs to an operator, also check if the operator is running. */ + return ((mgroup->type->flag & WM_MANIPULATORGROUPTYPE_OP) == 0 || mgroup->type->op) && + (!mgroup->type->poll || mgroup->type->poll(C, mgroup->type)); +} + +bool wm_manipulatorgroup_is_visible_in_drawstep(const wmManipulatorGroup *mgroup, const int drawstep) +{ + switch (drawstep) { + case WM_MANIPULATORMAP_DRAWSTEP_2D: + return (mgroup->type->flag & WM_MANIPULATORGROUPTYPE_IS_3D) == 0; + case WM_MANIPULATORMAP_DRAWSTEP_3D: + return (mgroup->type->flag & WM_MANIPULATORGROUPTYPE_IS_3D); + case WM_MANIPULATORMAP_DRAWSTEP_IN_SCENE: + return (mgroup->type->flag & WM_MANIPULATORGROUPTYPE_SCENE_DEPTH); + default: + BLI_assert(0); + return false; + } +} + +/** \name Manipulator operators + * + * Basic operators for manipulator interaction with user configurable keymaps. + * + * \{ */ + +static int manipulator_select_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) +{ + ARegion *ar = CTX_wm_region(C); + wmManipulatorMap *mmap = ar->manipulator_map; + wmManipulator ***sel = &mmap->mmap_context.selected_manipulator; + wmManipulator *highlighted = mmap->mmap_context.highlighted_manipulator; + + bool extend = RNA_boolean_get(op->ptr, "extend"); + bool deselect = RNA_boolean_get(op->ptr, "deselect"); + bool toggle = RNA_boolean_get(op->ptr, "toggle"); + + /* deselect all first */ + if (extend == false && deselect == false && toggle == false) { + wm_manipulatormap_deselect_all(mmap, sel); + BLI_assert(*sel == NULL && mmap->mmap_context.tot_selected == 0); + } + + if (highlighted) { + const bool is_selected = (highlighted->state & WM_MANIPULATOR_SELECTED); + bool redraw = false; + + if (toggle) { + /* toggle: deselect if already selected, else select */ + deselect = is_selected; + } + + if (deselect) { + if (is_selected && wm_manipulator_deselect(mmap, highlighted)) { + redraw = true; + } + } + else if (wm_manipulator_select(C, mmap, highlighted)) { + redraw = true; + } + + if (redraw) { + ED_region_tag_redraw(ar); + } + + return OPERATOR_FINISHED; + } + else { + BLI_assert(0); + return (OPERATOR_CANCELLED | OPERATOR_PASS_THROUGH); + } + + return OPERATOR_PASS_THROUGH; +} + +void MANIPULATORGROUP_OT_manipulator_select(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Manipulator Select"; + ot->description = "Select the currently highlighted manipulator"; + ot->idname = "MANIPULATORGROUP_OT_manipulator_select"; + + /* api callbacks */ + ot->invoke = manipulator_select_invoke; + + ot->flag = OPTYPE_UNDO; + + WM_operator_properties_mouse_select(ot); +} + +typedef struct ManipulatorTweakData { + wmManipulatorMap *mmap; + wmManipulator *active; + + int init_event; /* initial event type */ + int flag; /* tweak flags */ +} ManipulatorTweakData; + +static void manipulator_tweak_finish(bContext *C, wmOperator *op, const bool cancel) +{ + ManipulatorTweakData *mtweak = op->customdata; + if (mtweak->active->exit) { + mtweak->active->exit(C, mtweak->active, cancel); + } + wm_manipulatormap_set_active_manipulator(mtweak->mmap, C, NULL, NULL); + MEM_freeN(mtweak); +} + +static int manipulator_tweak_modal(bContext *C, wmOperator *op, const wmEvent *event) +{ + ManipulatorTweakData *mtweak = op->customdata; + wmManipulator *manipulator = mtweak->active; + + if (!manipulator) { + BLI_assert(0); + return (OPERATOR_CANCELLED | OPERATOR_PASS_THROUGH); + } + + if (event->type == mtweak->init_event && event->val == KM_RELEASE) { + manipulator_tweak_finish(C, op, false); + return OPERATOR_FINISHED; + } + + + if (event->type == EVT_MODAL_MAP) { + switch (event->val) { + case TWEAK_MODAL_CANCEL: + manipulator_tweak_finish(C, op, true); + return OPERATOR_CANCELLED; + case TWEAK_MODAL_CONFIRM: + manipulator_tweak_finish(C, op, false); + return OPERATOR_FINISHED; + case TWEAK_MODAL_PRECISION_ON: + mtweak->flag |= WM_MANIPULATOR_TWEAK_PRECISE; + break; + case TWEAK_MODAL_PRECISION_OFF: + mtweak->flag &= ~WM_MANIPULATOR_TWEAK_PRECISE; + break; + } + } + + /* handle manipulator */ + if (manipulator->handler) { + manipulator->handler(C, event, manipulator, mtweak->flag); + } + + /* Ugly hack to send manipulator events */ + ((wmEvent *)event)->type = EVT_MANIPULATOR_UPDATE; + + /* always return PASS_THROUGH so modal handlers + * with manipulators attached can update */ + return OPERATOR_PASS_THROUGH; +} + +static int manipulator_tweak_invoke(bContext *C, wmOperator *op, const wmEvent *event) +{ + ARegion *ar = CTX_wm_region(C); + wmManipulatorMap *mmap = ar->manipulator_map; + wmManipulator *manipulator = mmap->mmap_context.highlighted_manipulator; + + if (!manipulator) { + /* wm_handlers_do_intern shouldn't let this happen */ + BLI_assert(0); + return (OPERATOR_CANCELLED | OPERATOR_PASS_THROUGH); + } + + + /* activate highlighted manipulator */ + wm_manipulatormap_set_active_manipulator(mmap, C, event, manipulator); + + /* XXX temporary workaround for modal manipulator operator + * conflicting with modal operator attached to manipulator */ + if (manipulator->opname) { + wmOperatorType *ot = WM_operatortype_find(manipulator->opname, true); + if (ot->modal) { + return OPERATOR_FINISHED; + } + } + + + ManipulatorTweakData *mtweak = MEM_mallocN(sizeof(ManipulatorTweakData), __func__); + + mtweak->init_event = event->type; + mtweak->active = mmap->mmap_context.highlighted_manipulator; + mtweak->mmap = mmap; + mtweak->flag = 0; + + op->customdata = mtweak; + + WM_event_add_modal_handler(C, op); + + return OPERATOR_RUNNING_MODAL; +} + +void MANIPULATORGROUP_OT_manipulator_tweak(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Manipulator Tweak"; + ot->description = "Tweak the active manipulator"; + ot->idname = "MANIPULATORGROUP_OT_manipulator_tweak"; + + /* api callbacks */ + ot->invoke = manipulator_tweak_invoke; + ot->modal = manipulator_tweak_modal; + + ot->flag = OPTYPE_UNDO; +} + +/** \} */ // Manipulator operators + + +static wmKeyMap *manipulatorgroup_tweak_modal_keymap(wmKeyConfig *keyconf, const char *mgroupname) +{ + wmKeyMap *keymap; + char name[KMAP_MAX_NAME]; + + static EnumPropertyItem modal_items[] = { + {TWEAK_MODAL_CANCEL, "CANCEL", 0, "Cancel", ""}, + {TWEAK_MODAL_CONFIRM, "CONFIRM", 0, "Confirm", ""}, + {TWEAK_MODAL_PRECISION_ON, "PRECISION_ON", 0, "Enable Precision", ""}, + {TWEAK_MODAL_PRECISION_OFF, "PRECISION_OFF", 0, "Disable Precision", ""}, + {0, NULL, 0, NULL, NULL} + }; + + + BLI_snprintf(name, sizeof(name), "%s Tweak Modal Map", mgroupname); + keymap = WM_modalkeymap_get(keyconf, name); + + /* this function is called for each spacetype, only needs to add map once */ + if (keymap && keymap->modal_items) + return NULL; + + keymap = WM_modalkeymap_add(keyconf, name, modal_items); + + + /* items for modal map */ + WM_modalkeymap_add_item(keymap, ESCKEY, KM_PRESS, KM_ANY, 0, TWEAK_MODAL_CANCEL); + WM_modalkeymap_add_item(keymap, RIGHTMOUSE, KM_PRESS, KM_ANY, 0, TWEAK_MODAL_CANCEL); + + WM_modalkeymap_add_item(keymap, RETKEY, KM_PRESS, KM_ANY, 0, TWEAK_MODAL_CONFIRM); + WM_modalkeymap_add_item(keymap, PADENTER, KM_PRESS, KM_ANY, 0, TWEAK_MODAL_CONFIRM); + + WM_modalkeymap_add_item(keymap, RIGHTSHIFTKEY, KM_PRESS, KM_ANY, 0, TWEAK_MODAL_PRECISION_ON); + WM_modalkeymap_add_item(keymap, RIGHTSHIFTKEY, KM_RELEASE, KM_ANY, 0, TWEAK_MODAL_PRECISION_OFF); + WM_modalkeymap_add_item(keymap, LEFTSHIFTKEY, KM_PRESS, KM_ANY, 0, TWEAK_MODAL_PRECISION_ON); + WM_modalkeymap_add_item(keymap, LEFTSHIFTKEY, KM_RELEASE, KM_ANY, 0, TWEAK_MODAL_PRECISION_OFF); + + + WM_modalkeymap_assign(keymap, "MANIPULATORGROUP_OT_manipulator_tweak"); + + return keymap; +} + +/** + * Common default keymap for manipulator groups + */ +wmKeyMap *WM_manipulatorgroup_keymap_common(const struct wmManipulatorGroupType *mgrouptype, wmKeyConfig *config) +{ + /* Use area and region id since we might have multiple manipulators with the same name in different areas/regions */ + wmKeyMap *km = WM_keymap_find(config, mgrouptype->name, mgrouptype->spaceid, mgrouptype->regionid); + + WM_keymap_add_item(km, "MANIPULATORGROUP_OT_manipulator_tweak", ACTIONMOUSE, KM_PRESS, KM_ANY, 0); + manipulatorgroup_tweak_modal_keymap(config, mgrouptype->name); + + return km; +} + +/** + * Variation of #WM_manipulatorgroup_keymap_common but with keymap items for selection + */ +wmKeyMap *WM_manipulatorgroup_keymap_common_sel(const struct wmManipulatorGroupType *mgrouptype, wmKeyConfig *config) +{ + /* Use area and region id since we might have multiple manipulators with the same name in different areas/regions */ + wmKeyMap *km = WM_keymap_find(config, mgrouptype->name, mgrouptype->spaceid, mgrouptype->regionid); + + WM_keymap_add_item(km, "MANIPULATORGROUP_OT_manipulator_tweak", ACTIONMOUSE, KM_PRESS, KM_ANY, 0); + manipulatorgroup_tweak_modal_keymap(config, mgrouptype->name); + + wmKeyMapItem *kmi = WM_keymap_add_item(km, "MANIPULATORGROUP_OT_manipulator_select", SELECTMOUSE, KM_PRESS, 0, 0); + RNA_boolean_set(kmi->ptr, "extend", false); + RNA_boolean_set(kmi->ptr, "deselect", false); + RNA_boolean_set(kmi->ptr, "toggle", false); + kmi = WM_keymap_add_item(km, "MANIPULATORGROUP_OT_manipulator_select", SELECTMOUSE, KM_PRESS, KM_SHIFT, 0); + RNA_boolean_set(kmi->ptr, "extend", false); + RNA_boolean_set(kmi->ptr, "deselect", false); + RNA_boolean_set(kmi->ptr, "toggle", true); + + return km; +} + +/** \} */ /* wmManipulatorGroup */ + +/* -------------------------------------------------------------------- */ +/** \name wmManipulatorGroupType + * + * \{ */ + +/** + * Use this for registering manipulators on startup. For runtime, use #WM_manipulatorgrouptype_append_runtime. + */ +wmManipulatorGroupType *WM_manipulatorgrouptype_append( + wmManipulatorMapType *mmaptype, void (*mgrouptype_func)(wmManipulatorGroupType *)) +{ + wmManipulatorGroupType *mgrouptype = MEM_callocN(sizeof(wmManipulatorGroupType), "manipulator-group"); + + mgrouptype_func(mgrouptype); + mgrouptype->spaceid = mmaptype->spaceid; + mgrouptype->regionid = mmaptype->regionid; + BLI_strncpy(mgrouptype->mapidname, mmaptype->idname, MAX_NAME); + /* if not set, use default */ + if (!mgrouptype->keymap_init) { + mgrouptype->keymap_init = WM_manipulatorgroup_keymap_common; + } + + /* add the type for future created areas of the same type */ + BLI_addtail(&mmaptype->manipulator_grouptypes, mgrouptype); + return mgrouptype; +} + +/** + * Use this for registering manipulators on runtime. + */ +wmManipulatorGroupType *WM_manipulatorgrouptype_append_runtime( + const Main *main, wmManipulatorMapType *mmaptype, + void (*mgrouptype_func)(wmManipulatorGroupType *)) +{ + wmManipulatorGroupType *mgrouptype = WM_manipulatorgrouptype_append(mmaptype, mgrouptype_func); + + /* Main is missing on startup when we create new areas. + * So this is only called for manipulators initialized on runtime */ + WM_manipulatorgrouptype_init_runtime(main, mmaptype, mgrouptype); + + return mgrouptype; +} + +void WM_manipulatorgrouptype_init_runtime( + const Main *bmain, wmManipulatorMapType *mmaptype, + wmManipulatorGroupType *mgrouptype) +{ + /* init keymap - on startup there's an extra call to init keymaps for 'permanent' manipulator-groups */ + wm_manipulatorgrouptype_keymap_init(mgrouptype, ((wmWindowManager *)bmain->wm.first)->defaultconf); + + /* now create a manipulator for all existing areas */ + for (bScreen *sc = bmain->screen.first; sc; sc = sc->id.next) { + for (ScrArea *sa = sc->areabase.first; sa; sa = sa->next) { + for (SpaceLink *sl = sa->spacedata.first; sl; sl = sl->next) { + ListBase *lb = (sl == sa->spacedata.first) ? &sa->regionbase : &sl->regionbase; + for (ARegion *ar = lb->first; ar; ar = ar->next) { + wmManipulatorMap *mmap = ar->manipulator_map; + if (mmap->type == mmaptype) { + wmManipulatorGroup *mgroup = wm_manipulatorgroup_new_from_type(mgrouptype); + + /* just add here, drawing will occur on next update */ + BLI_addtail(&mmap->manipulator_groups, mgroup); + wm_manipulatormap_set_highlighted_manipulator(mmap, NULL, NULL, 0); + ED_region_tag_redraw(ar); + } + } + } + } + } +} + +void WM_manipulatorgrouptype_unregister(bContext *C, Main *bmain, wmManipulatorGroupType *mgrouptype) +{ + for (bScreen *sc = bmain->screen.first; sc; sc = sc->id.next) { + for (ScrArea *sa = sc->areabase.first; sa; sa = sa->next) { + for (SpaceLink *sl = sa->spacedata.first; sl; sl = sl->next) { + ListBase *lb = (sl == sa->spacedata.first) ? &sa->regionbase : &sl->regionbase; + for (ARegion *ar = lb->first; ar; ar = ar->next) { + wmManipulatorMap *mmap = ar->manipulator_map; + wmManipulatorGroup *mgroup, *mgroup_next; + + for (mgroup = mmap->manipulator_groups.first; mgroup; mgroup = mgroup_next) { + mgroup_next = mgroup->next; + if (mgroup->type == mgrouptype) { + wm_manipulatorgroup_free(C, mmap, mgroup); + ED_region_tag_redraw(ar); + } + } + } + } + } + } + + wmManipulatorMapType *mmaptype = WM_manipulatormaptype_find(&(const struct wmManipulatorMapType_Params) { + mgrouptype->mapidname, mgrouptype->spaceid, + mgrouptype->regionid}); + + BLI_remlink(&mmaptype->manipulator_grouptypes, mgrouptype); + mgrouptype->prev = mgrouptype->next = NULL; + + MEM_freeN(mgrouptype); +} + +void wm_manipulatorgrouptype_keymap_init(wmManipulatorGroupType *mgrouptype, wmKeyConfig *keyconf) +{ + mgrouptype->keymap = mgrouptype->keymap_init(mgrouptype, keyconf); +} + +/** \} */ /* wmManipulatorGroupType */ diff --git a/source/blender/windowmanager/manipulators/intern/wm_manipulatormap.c b/source/blender/windowmanager/manipulators/intern/wm_manipulatormap.c new file mode 100644 index 00000000000..500092f5f2d --- /dev/null +++ b/source/blender/windowmanager/manipulators/intern/wm_manipulatormap.c @@ -0,0 +1,760 @@ +/* + * ***** 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) 2014 Blender Foundation. + * All rights reserved. + * + * Contributor(s): Blender Foundation + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/windowmanager/manipulators/intern/wm_manipulatormap.c + * \ingroup wm + */ + +#include <string.h> + +#include "BKE_context.h" + +#include "BLI_listbase.h" +#include "BLI_math.h" +#include "BLI_string.h" +#include "BLI_ghash.h" + +#include "ED_screen.h" +#include "ED_view3d.h" + +#include "GPU_glew.h" +#include "GPU_select.h" + +#include "MEM_guardedalloc.h" + +#include "WM_api.h" +#include "WM_types.h" +#include "wm_event_system.h" + +/* own includes */ +#include "wm_manipulator_wmapi.h" +#include "wm_manipulator_intern.h" + +/** + * Store all manipulator-maps here. Anyone who wants to register a manipulator for a certain + * area type can query the manipulator-map to do so. + */ +static ListBase manipulatormaptypes = {NULL, NULL}; + +/** + * Manipulator-map update tagging. + */ +enum eManipulatorMapUpdateFlags { + /* Tag manipulator-map for refresh. */ + MANIPULATORMAP_REFRESH = (1 << 0), +}; + + +/* -------------------------------------------------------------------- */ +/** \name wmManipulatorMap + * + * \{ */ + +/** + * Creates a manipulator-map with all registered manipulators for that type + */ +wmManipulatorMap *WM_manipulatormap_new_from_type(const struct wmManipulatorMapType_Params *mmap_params) +{ + wmManipulatorMapType *mmaptype = WM_manipulatormaptype_ensure(mmap_params); + wmManipulatorMap *mmap; + + mmap = MEM_callocN(sizeof(wmManipulatorMap), "ManipulatorMap"); + mmap->type = mmaptype; + mmap->update_flag = MANIPULATORMAP_REFRESH; + + /* create all manipulator-groups for this manipulator-map. We may create an empty one + * too in anticipation of manipulators from operators etc */ + for (wmManipulatorGroupType *mgrouptype = mmaptype->manipulator_grouptypes.first; + mgrouptype; + mgrouptype = mgrouptype->next) + { + wmManipulatorGroup *mgroup = wm_manipulatorgroup_new_from_type(mgrouptype); + BLI_addtail(&mmap->manipulator_groups, mgroup); + } + + return mmap; +} + +void wm_manipulatormap_selected_delete(wmManipulatorMap *mmap) +{ + MEM_SAFE_FREE(mmap->mmap_context.selected_manipulator); + mmap->mmap_context.tot_selected = 0; +} + +void wm_manipulatormap_delete(wmManipulatorMap *mmap) +{ + if (!mmap) + return; + + for (wmManipulatorGroup *mgroup = mmap->manipulator_groups.first, *mgroup_next; mgroup; mgroup = mgroup_next) { + mgroup_next = mgroup->next; + wm_manipulatorgroup_free(NULL, mmap, mgroup); + } + BLI_assert(BLI_listbase_is_empty(&mmap->manipulator_groups)); + + wm_manipulatormap_selected_delete(mmap); + + MEM_freeN(mmap); +} + +/** + * Creates and returns idname hash table for (visible) manipulators in \a mmap + * + * \param poll Polling function for excluding manipulators. + * \param data Custom data passed to \a poll + */ +static GHash *WM_manipulatormap_manipulator_hash_new( + const bContext *C, wmManipulatorMap *mmap, + bool (*poll)(const wmManipulator *, void *), + void *data, const bool include_hidden) +{ + GHash *hash = BLI_ghash_str_new(__func__); + + /* collect manipulators */ + for (wmManipulatorGroup *mgroup = mmap->manipulator_groups.first; mgroup; mgroup = mgroup->next) { + if (!mgroup->type->poll || mgroup->type->poll(C, mgroup->type)) { + for (wmManipulator *manipulator = mgroup->manipulators.first; + manipulator; + manipulator = manipulator->next) + { + if ((include_hidden || (manipulator->flag & WM_MANIPULATOR_HIDDEN) == 0) && + (!poll || poll(manipulator, data))) + { + BLI_ghash_insert(hash, manipulator->idname, manipulator); + } + } + } + } + + return hash; +} + +void WM_manipulatormap_tag_refresh(wmManipulatorMap *mmap) +{ + if (mmap) { + mmap->update_flag |= MANIPULATORMAP_REFRESH; + } +} + +static void manipulatormap_tag_updated(wmManipulatorMap *mmap) +{ + mmap->update_flag = 0; +} + +static bool manipulator_prepare_drawing( + wmManipulatorMap *mmap, wmManipulator *manipulator, + const bContext *C, ListBase *draw_manipulators) +{ + if (!wm_manipulator_is_visible(manipulator)) { + /* skip */ + } + else { + wm_manipulator_update(manipulator, C, (mmap->update_flag & MANIPULATORMAP_REFRESH) != 0); + BLI_addhead(draw_manipulators, BLI_genericNodeN(manipulator)); + return true; + } + + return false; +} + +/** + * Update manipulators of \a mmap to prepare for drawing. Adds all manipulators that + * should be drawn to list \a draw_manipulators, note that added items need freeing. + */ +static void manipulatormap_prepare_drawing( + wmManipulatorMap *mmap, const bContext *C, ListBase *draw_manipulators, const int drawstep) +{ + if (!mmap || BLI_listbase_is_empty(&mmap->manipulator_groups)) + return; + wmManipulator *active_manipulator = mmap->mmap_context.active_manipulator; + + /* only active manipulator needs updating */ + if (active_manipulator) { + if (manipulator_prepare_drawing(mmap, active_manipulator, C, draw_manipulators)) { + manipulatormap_tag_updated(mmap); + } + /* don't draw any other manipulators */ + return; + } + + for (wmManipulatorGroup *mgroup = mmap->manipulator_groups.first; mgroup; mgroup = mgroup->next) { + /* check group visibility - drawstep first to avoid unnecessary call of group poll callback */ + if (!wm_manipulatorgroup_is_visible_in_drawstep(mgroup, drawstep) || + !wm_manipulatorgroup_is_visible(mgroup, C)) + { + continue; + } + + /* needs to be initialized on first draw */ + wm_manipulatorgroup_ensure_initialized(mgroup, C); + /* update data if needed */ + /* XXX weak: Manipulator-group may skip refreshing if it's invisible (map gets untagged nevertheless) */ + if (mmap->update_flag & MANIPULATORMAP_REFRESH && mgroup->type->refresh) { + mgroup->type->refresh(C, mgroup); + } + /* prepare drawing */ + if (mgroup->type->draw_prepare) { + mgroup->type->draw_prepare(C, mgroup); + } + + for (wmManipulator *manipulator = mgroup->manipulators.first; manipulator; manipulator = manipulator->next) { + manipulator_prepare_drawing(mmap, manipulator, C, draw_manipulators); + } + } + + manipulatormap_tag_updated(mmap); +} + +/** + * Draw all visible manipulators in \a mmap. + * Uses global draw_manipulators listbase. + */ +static void manipulators_draw_list(const wmManipulatorMap *mmap, const bContext *C, ListBase *draw_manipulators) +{ + if (!mmap) + return; + BLI_assert(!BLI_listbase_is_empty(&mmap->manipulator_groups)); + + /* draw_manipulators contains all visible manipulators - draw them */ + for (LinkData *link = draw_manipulators->first, *link_next; link; link = link_next) { + wmManipulator *manipulator = link->data; + link_next = link->next; + + manipulator->draw(C, manipulator); + /* free/remove manipulator link after drawing */ + BLI_freelinkN(draw_manipulators, link); + } +} + +void WM_manipulatormap_draw(wmManipulatorMap *mmap, const bContext *C, const int drawstep) +{ + ListBase draw_manipulators = {NULL}; + + manipulatormap_prepare_drawing(mmap, C, &draw_manipulators, drawstep); + manipulators_draw_list(mmap, C, &draw_manipulators); + BLI_assert(BLI_listbase_is_empty(&draw_manipulators)); +} + +static void manipulator_find_active_3D_loop(const bContext *C, ListBase *visible_manipulators) +{ + int selectionbase = 0; + wmManipulator *manipulator; + + for (LinkData *link = visible_manipulators->first; link; link = link->next) { + manipulator = link->data; + /* pass the selection id shifted by 8 bits. Last 8 bits are used for selected manipulator part id */ + manipulator->render_3d_intersection(C, manipulator, selectionbase << 8); + + selectionbase++; + } +} + +static int manipulator_find_intersected_3D_intern( + ListBase *visible_manipulators, const bContext *C, const int co[2], + const float hotspot) +{ + ScrArea *sa = CTX_wm_area(C); + ARegion *ar = CTX_wm_region(C); + View3D *v3d = sa->spacedata.first; + RegionView3D *rv3d = ar->regiondata; + rctf rect, selrect; + GLuint buffer[64]; // max 4 items per select, so large enuf + short hits; + const bool do_passes = GPU_select_query_check_active(); + + extern void view3d_winmatrix_set(ARegion *ar, View3D *v3d, rctf *rect); + + + rect.xmin = co[0] - hotspot; + rect.xmax = co[0] + hotspot; + rect.ymin = co[1] - hotspot; + rect.ymax = co[1] + hotspot; + + selrect = rect; + + view3d_winmatrix_set(ar, v3d, &rect); + mul_m4_m4m4(rv3d->persmat, rv3d->winmat, rv3d->viewmat); + + if (do_passes) + GPU_select_begin(buffer, ARRAY_SIZE(buffer), &selrect, GPU_SELECT_NEAREST_FIRST_PASS, 0); + else + GPU_select_begin(buffer, ARRAY_SIZE(buffer), &selrect, GPU_SELECT_ALL, 0); + /* do the drawing */ + manipulator_find_active_3D_loop(C, visible_manipulators); + + hits = GPU_select_end(); + + if (do_passes) { + GPU_select_begin(buffer, ARRAY_SIZE(buffer), &selrect, GPU_SELECT_NEAREST_SECOND_PASS, hits); + manipulator_find_active_3D_loop(C, visible_manipulators); + GPU_select_end(); + } + + view3d_winmatrix_set(ar, v3d, NULL); + mul_m4_m4m4(rv3d->persmat, rv3d->winmat, rv3d->viewmat); + + return hits > 0 ? buffer[3] : -1; +} + +/** + * Try to find a 3D manipulator at screen-space coordinate \a co. Uses OpenGL picking. + */ +static wmManipulator *manipulator_find_intersected_3D( + bContext *C, const int co[2], ListBase *visible_manipulators, + unsigned char *part) +{ + wmManipulator *result = NULL; + const float hotspot = 14.0f; + int ret; + + *part = 0; + /* set up view matrices */ + view3d_operator_needs_opengl(C); + + ret = manipulator_find_intersected_3D_intern(visible_manipulators, C, co, 0.5f * hotspot); + + if (ret != -1) { + LinkData *link; + int retsec; + retsec = manipulator_find_intersected_3D_intern(visible_manipulators, C, co, 0.2f * hotspot); + + if (retsec != -1) + ret = retsec; + + link = BLI_findlink(visible_manipulators, ret >> 8); + *part = ret & 255; + result = link->data; + } + + return result; +} + +/** + * Try to find a manipulator under the mouse position. 2D intersections have priority over + * 3D ones (could check for smallest screen-space distance but not needed right now). + */ +wmManipulator *wm_manipulatormap_find_highlighted_manipulator( + wmManipulatorMap *mmap, bContext *C, const wmEvent *event, + unsigned char *part) +{ + wmManipulator *manipulator = NULL; + ListBase visible_3d_manipulators = {NULL}; + + for (wmManipulatorGroup *mgroup = mmap->manipulator_groups.first; mgroup; mgroup = mgroup->next) { + if (wm_manipulatorgroup_is_visible(mgroup, C)) { + if (mgroup->type->flag & WM_MANIPULATORGROUPTYPE_IS_3D) { + wm_manipulatorgroup_intersectable_manipulators_to_list(mgroup, &visible_3d_manipulators); + } + else if ((manipulator = wm_manipulatorgroup_find_intersected_mainpulator(mgroup, C, event, part))) { + break; + } + } + } + + if (!BLI_listbase_is_empty(&visible_3d_manipulators)) { + manipulator = manipulator_find_intersected_3D(C, event->mval, &visible_3d_manipulators, part); + BLI_freelistN(&visible_3d_manipulators); + } + + return manipulator; +} + +void WM_manipulatormap_add_handlers(ARegion *ar, wmManipulatorMap *mmap) +{ + wmEventHandler *handler = MEM_callocN(sizeof(wmEventHandler), "manipulator handler"); + + BLI_assert(mmap == ar->manipulator_map); + handler->manipulator_map = mmap; + BLI_addtail(&ar->handlers, handler); +} + +void wm_manipulatormaps_handled_modal_update( + bContext *C, wmEvent *event, wmEventHandler *handler, + const wmOperatorType *ot) +{ + const bool modal_running = (handler->op != NULL); + + /* happens on render or when joining areas */ + if (!handler->op_region || !handler->op_region->manipulator_map) + return; + + /* hide operator manipulators */ + if (!modal_running && ot->mgrouptype) { + ot->mgrouptype->op = NULL; + } + + wmManipulatorMap *mmap = handler->op_region->manipulator_map; + wmManipulator *manipulator = wm_manipulatormap_get_active_manipulator(mmap); + ScrArea *area = CTX_wm_area(C); + ARegion *region = CTX_wm_region(C); + + wm_manipulatormap_handler_context(C, handler); + + /* regular update for running operator */ + if (modal_running) { + if (manipulator && manipulator->handler && manipulator->opname && + STREQ(manipulator->opname, handler->op->idname)) + { + manipulator->handler(C, event, manipulator, 0); + } + } + /* operator not running anymore */ + else { + wm_manipulatormap_set_highlighted_manipulator(mmap, C, NULL, 0); + wm_manipulatormap_set_active_manipulator(mmap, C, event, NULL); + } + + /* restore the area */ + CTX_wm_area_set(C, area); + CTX_wm_region_set(C, region); +} + +/** + * Deselect all selected manipulators in \a mmap. + * \return if selection has changed. + */ +bool wm_manipulatormap_deselect_all(wmManipulatorMap *mmap, wmManipulator ***sel) +{ + if (*sel == NULL || mmap->mmap_context.tot_selected == 0) + return false; + + for (int i = 0; i < mmap->mmap_context.tot_selected; i++) { + (*sel)[i]->state &= ~WM_MANIPULATOR_SELECTED; + (*sel)[i] = NULL; + } + wm_manipulatormap_selected_delete(mmap); + + /* always return true, we already checked + * if there's anything to deselect */ + return true; +} + +BLI_INLINE bool manipulator_selectable_poll(const wmManipulator *manipulator, void *UNUSED(data)) +{ + return (manipulator->mgroup->type->flag & WM_MANIPULATORGROUPTYPE_SELECTABLE); +} + +/** + * Select all selectable manipulators in \a mmap. + * \return if selection has changed. + */ +static bool wm_manipulatormap_select_all_intern( + bContext *C, wmManipulatorMap *mmap, wmManipulator ***sel, + const int action) +{ + /* GHash is used here to avoid having to loop over all manipulators twice (once to + * get tot_sel for allocating, once for actually selecting). Instead we collect + * selectable manipulators in hash table and use this to get tot_sel and do selection */ + + GHash *hash = WM_manipulatormap_manipulator_hash_new(C, mmap, manipulator_selectable_poll, NULL, true); + GHashIterator gh_iter; + int i, *tot_sel = &mmap->mmap_context.tot_selected; + bool changed = false; + + *tot_sel = BLI_ghash_size(hash); + *sel = MEM_reallocN(*sel, sizeof(**sel) * (*tot_sel)); + + GHASH_ITER_INDEX (gh_iter, hash, i) { + wmManipulator *manipulator_iter = BLI_ghashIterator_getValue(&gh_iter); + + if ((manipulator_iter->state & WM_MANIPULATOR_SELECTED) == 0) { + changed = true; + } + manipulator_iter->state |= WM_MANIPULATOR_SELECTED; + if (manipulator_iter->select) { + manipulator_iter->select(C, manipulator_iter, action); + } + (*sel)[i] = manipulator_iter; + BLI_assert(i < (*tot_sel)); + } + /* highlight first manipulator */ + wm_manipulatormap_set_highlighted_manipulator(mmap, C, (*sel)[0], (*sel)[0]->highlighted_part); + + BLI_ghash_free(hash, NULL, NULL); + return changed; +} + +/** + * Select/Deselect all selectable manipulators in \a mmap. + * \return if selection has changed. + * + * TODO select all by type + */ +bool WM_manipulatormap_select_all(bContext *C, wmManipulatorMap *mmap, const int action) +{ + wmManipulator ***sel = &mmap->mmap_context.selected_manipulator; + bool changed = false; + + switch (action) { + case SEL_SELECT: + changed = wm_manipulatormap_select_all_intern(C, mmap, sel, action); + break; + case SEL_DESELECT: + changed = wm_manipulatormap_deselect_all(mmap, sel); + break; + default: + BLI_assert(0); + break; + } + + if (changed) + WM_event_add_mousemove(C); + + return changed; +} + +/** + * Prepare context for manipulator handling (but only if area/region is + * part of screen). Version of #wm_handler_op_context for manipulators. + */ +void wm_manipulatormap_handler_context(bContext *C, wmEventHandler *handler) +{ + bScreen *screen = CTX_wm_screen(C); + + if (screen) { + if (handler->op_area == NULL) { + /* do nothing in this context */ + } + else { + ScrArea *sa; + + for (sa = screen->areabase.first; sa; sa = sa->next) + if (sa == handler->op_area) + break; + if (sa == NULL) { + /* when changing screen layouts with running modal handlers (like render display), this + * is not an error to print */ + if (handler->manipulator_map == NULL) + printf("internal error: modal manipulator-map handler has invalid area\n"); + } + else { + ARegion *ar; + CTX_wm_area_set(C, sa); + for (ar = sa->regionbase.first; ar; ar = ar->next) + if (ar == handler->op_region) + break; + /* XXX no warning print here, after full-area and back regions are remade */ + if (ar) + CTX_wm_region_set(C, ar); + } + } + } +} + +bool WM_manipulatormap_cursor_set(const wmManipulatorMap *mmap, wmWindow *win) +{ + for (; mmap; mmap = mmap->next) { + wmManipulator *manipulator = mmap->mmap_context.highlighted_manipulator; + if (manipulator && manipulator->get_cursor) { + WM_cursor_set(win, manipulator->get_cursor(manipulator)); + return true; + } + } + + return false; +} + +void wm_manipulatormap_set_highlighted_manipulator( + wmManipulatorMap *mmap, const bContext *C, wmManipulator *manipulator, + unsigned char part) +{ + if ((manipulator != mmap->mmap_context.highlighted_manipulator) || + (manipulator && part != manipulator->highlighted_part)) + { + if (mmap->mmap_context.highlighted_manipulator) { + mmap->mmap_context.highlighted_manipulator->state &= ~WM_MANIPULATOR_HIGHLIGHT; + mmap->mmap_context.highlighted_manipulator->highlighted_part = 0; + } + + mmap->mmap_context.highlighted_manipulator = manipulator; + + if (manipulator) { + manipulator->state |= WM_MANIPULATOR_HIGHLIGHT; + manipulator->highlighted_part = part; + + if (C && manipulator->get_cursor) { + wmWindow *win = CTX_wm_window(C); + WM_cursor_set(win, manipulator->get_cursor(manipulator)); + } + } + else { + if (C) { + wmWindow *win = CTX_wm_window(C); + WM_cursor_set(win, CURSOR_STD); + } + } + + /* tag the region for redraw */ + if (C) { + ARegion *ar = CTX_wm_region(C); + ED_region_tag_redraw(ar); + } + } +} + +wmManipulator *wm_manipulatormap_get_highlighted_manipulator(wmManipulatorMap *mmap) +{ + return mmap->mmap_context.highlighted_manipulator; +} + +void wm_manipulatormap_set_active_manipulator( + wmManipulatorMap *mmap, bContext *C, const wmEvent *event, wmManipulator *manipulator) +{ + if (manipulator && C) { + manipulator->state |= WM_MANIPULATOR_ACTIVE; + mmap->mmap_context.active_manipulator = manipulator; + + if (manipulator->opname) { + wmOperatorType *ot = WM_operatortype_find(manipulator->opname, 0); + + if (ot) { + /* first activate the manipulator itself */ + if (manipulator->invoke && manipulator->handler) { + manipulator->invoke(C, event, manipulator); + } + + WM_operator_name_call_ptr(C, ot, WM_OP_INVOKE_DEFAULT, &manipulator->opptr); + + /* we failed to hook the manipulator to the operator handler or operator was cancelled, return */ + if (!mmap->mmap_context.active_manipulator) { + manipulator->state &= ~WM_MANIPULATOR_ACTIVE; + /* first activate the manipulator itself */ + if (manipulator->interaction_data) { + MEM_freeN(manipulator->interaction_data); + manipulator->interaction_data = NULL; + } + } + return; + } + else { + printf("Manipulator error: operator not found"); + mmap->mmap_context.active_manipulator = NULL; + return; + } + } + else { + if (manipulator->invoke && manipulator->handler) { + manipulator->invoke(C, event, manipulator); + } + } + WM_cursor_grab_enable(CTX_wm_window(C), true, true, NULL); + } + else { + manipulator = mmap->mmap_context.active_manipulator; + + + /* deactivate, manipulator but first take care of some stuff */ + if (manipulator) { + manipulator->state &= ~WM_MANIPULATOR_ACTIVE; + /* first activate the manipulator itself */ + if (manipulator->interaction_data) { + MEM_freeN(manipulator->interaction_data); + manipulator->interaction_data = NULL; + } + } + mmap->mmap_context.active_manipulator = NULL; + + if (C) { + WM_cursor_grab_disable(CTX_wm_window(C), NULL); + ED_region_tag_redraw(CTX_wm_region(C)); + WM_event_add_mousemove(C); + } + } +} + +wmManipulator *wm_manipulatormap_get_active_manipulator(wmManipulatorMap *mmap) +{ + return mmap->mmap_context.active_manipulator; +} + +/** \} */ /* wmManipulatorMap */ + + +/* -------------------------------------------------------------------- */ +/** \name wmManipulatorMapType + * + * \{ */ + +wmManipulatorMapType *WM_manipulatormaptype_find( + const struct wmManipulatorMapType_Params *mmap_params) +{ + for (wmManipulatorMapType *mmaptype = manipulatormaptypes.first; mmaptype; mmaptype = mmaptype->next) { + if (mmaptype->spaceid == mmap_params->spaceid && + mmaptype->regionid == mmap_params->regionid && + STREQ(mmaptype->idname, mmap_params->idname)) + { + return mmaptype; + } + } + + return NULL; +} + +wmManipulatorMapType *WM_manipulatormaptype_ensure( + const struct wmManipulatorMapType_Params *mmap_params) +{ + wmManipulatorMapType *mmaptype = WM_manipulatormaptype_find(mmap_params); + + if (mmaptype) { + return mmaptype; + } + + mmaptype = MEM_callocN(sizeof(wmManipulatorMapType), "manipulatortype list"); + mmaptype->spaceid = mmap_params->spaceid; + mmaptype->regionid = mmap_params->regionid; + BLI_strncpy(mmaptype->idname, mmap_params->idname, sizeof(mmaptype->idname)); + BLI_addhead(&manipulatormaptypes, mmaptype); + + return mmaptype; +} + +void wm_manipulatormaptypes_free(void) +{ + for (wmManipulatorMapType *mmaptype = manipulatormaptypes.first; mmaptype; mmaptype = mmaptype->next) { + BLI_freelistN(&mmaptype->manipulator_grouptypes); + } + BLI_freelistN(&manipulatormaptypes); +} + +/** + * Initialize keymaps for all existing manipulator-groups + */ +void wm_manipulators_keymap(wmKeyConfig *keyconf) +{ + wmManipulatorMapType *mmaptype; + wmManipulatorGroupType *mgrouptype; + + /* we add this item-less keymap once and use it to group manipulator-group keymaps into it */ + WM_keymap_find(keyconf, "Manipulators", 0, 0); + + for (mmaptype = manipulatormaptypes.first; mmaptype; mmaptype = mmaptype->next) { + for (mgrouptype = mmaptype->manipulator_grouptypes.first; mgrouptype; mgrouptype = mgrouptype->next) { + wm_manipulatorgrouptype_keymap_init(mgrouptype, keyconf); + } + } +} + +/** \} */ /* wmManipulatorMapType */ + diff --git a/source/blender/windowmanager/manipulators/wm_manipulator_wmapi.h b/source/blender/windowmanager/manipulators/wm_manipulator_wmapi.h new file mode 100644 index 00000000000..c5008cef896 --- /dev/null +++ b/source/blender/windowmanager/manipulators/wm_manipulator_wmapi.h @@ -0,0 +1,90 @@ +/* + * ***** 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) 2016 Blender Foundation. + * All rights reserved. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/windowmanager/manipulators/wm_manipulator_wmapi.h + * \ingroup wm + * + * \name Manipulators Window Manager API + * API for usage in window manager code only. It should contain all functionality + * needed to hook up the manipulator system with Blender's window manager. It's + * mostly the event system that needs to communicate with manipulator code. + * + * Only included in wm.h and lower level files. + */ + + +#ifndef __WM_MANIPULATOR_WMAPI_H__ +#define __WM_MANIPULATOR_WMAPI_H__ + +struct wmEventHandler; +struct wmManipulatorMap; +struct wmOperatorType; +struct wmOperator; + + +/* -------------------------------------------------------------------- */ +/* wmManipulator */ + +typedef void (*wmManipulatorSelectFunc)(struct bContext *, struct wmManipulator *, const int); + +struct wmManipulatorGroup *wm_manipulator_get_parent_group(const struct wmManipulator *manipulator); + +/* -------------------------------------------------------------------- */ +/* wmManipulatorGroup */ + +void MANIPULATORGROUP_OT_manipulator_select(struct wmOperatorType *ot); +void MANIPULATORGROUP_OT_manipulator_tweak(struct wmOperatorType *ot); + +void wm_manipulatorgroup_attach_to_modal_handler( + struct bContext *C, struct wmEventHandler *handler, + struct wmManipulatorGroupType *mgrouptype, struct wmOperator *op); + +/* -------------------------------------------------------------------- */ +/* wmManipulatorMap */ + +void wm_manipulatormap_delete(struct wmManipulatorMap *mmap); +void wm_manipulatormaptypes_free(void); + +void wm_manipulators_keymap(struct wmKeyConfig *keyconf); + +void wm_manipulatormaps_handled_modal_update( + bContext *C, struct wmEvent *event, struct wmEventHandler *handler, + const struct wmOperatorType *ot); +void wm_manipulatormap_handler_context(bContext *C, struct wmEventHandler *handler); + +struct wmManipulator *wm_manipulatormap_find_highlighted_manipulator( + struct wmManipulatorMap *mmap, bContext *C, + const struct wmEvent *event, unsigned char *part); +void wm_manipulatormap_set_highlighted_manipulator( + struct wmManipulatorMap *mmap, const bContext *C, + struct wmManipulator *manipulator, unsigned char part); +struct wmManipulator *wm_manipulatormap_get_highlighted_manipulator(struct wmManipulatorMap *mmap); +void wm_manipulatormap_set_active_manipulator( + struct wmManipulatorMap *mmap, bContext *C, + const struct wmEvent *event, struct wmManipulator *manipulator); +struct wmManipulator *wm_manipulatormap_get_active_manipulator(struct wmManipulatorMap *mmap); + +#endif /* __WM_MANIPULATOR_WMAPI_H__ */ + diff --git a/source/blender/windowmanager/wm.h b/source/blender/windowmanager/wm.h index 2f06ddab1e8..3dd294128e2 100644 --- a/source/blender/windowmanager/wm.h +++ b/source/blender/windowmanager/wm.h @@ -34,6 +34,8 @@ struct wmWindow; struct ReportList; +#include "manipulators/wm_manipulator_wmapi.h" + typedef struct wmPaintCursor { struct wmPaintCursor *next, *prev; diff --git a/source/blender/windowmanager/wm_draw.h b/source/blender/windowmanager/wm_draw.h index 5257bba45ff..56dff304719 100644 --- a/source/blender/windowmanager/wm_draw.h +++ b/source/blender/windowmanager/wm_draw.h @@ -34,6 +34,8 @@ #include "GPU_glew.h" +#define USE_TEXTURE_RECTANGLE 1 + typedef struct wmDrawTriple { GLuint bind; int x, y; @@ -56,7 +58,7 @@ void wm_draw_region_clear (struct wmWindow *win, struct ARegion *ar); void wm_tag_redraw_overlay (struct wmWindow *win, struct ARegion *ar); -void wm_triple_draw_textures (struct wmWindow *win, struct wmDrawTriple *triple, float alpha, bool is_interlace); +void wm_triple_draw_textures (struct wmWindow *win, struct wmDrawTriple *triple, float alpha); void wm_draw_data_free (struct wmWindow *win); diff --git a/source/blender/windowmanager/wm_event_system.h b/source/blender/windowmanager/wm_event_system.h index efc01b1f8a8..2f7ebbc1def 100644 --- a/source/blender/windowmanager/wm_event_system.h +++ b/source/blender/windowmanager/wm_event_system.h @@ -52,7 +52,7 @@ typedef struct wmEventHandler { wmKeyMap *keymap; /* pointer to builtin/custom keymaps */ const rcti *bblocal, *bbwin; /* optional local and windowspace bb */ - /* modal operator handler */ + /* modal operator handler and WM_HANDLER_FILESELECT */ wmOperator *op; /* for derived/modal handlers */ struct ScrArea *op_area; /* for derived/modal handlers */ struct ARegion *op_region; /* for derived/modal handlers */ @@ -68,7 +68,8 @@ typedef struct wmEventHandler { /* drop box handler */ ListBase *dropboxes; - + /* manipulator handler */ + struct wmManipulatorMap *manipulator_map; } wmEventHandler; /* custom types for handlers, for signalling, freeing */ diff --git a/source/blender/windowmanager/wm_event_types.h b/source/blender/windowmanager/wm_event_types.h index 3085f138846..9d34bc24e6c 100644 --- a/source/blender/windowmanager/wm_event_types.h +++ b/source/blender/windowmanager/wm_event_types.h @@ -339,6 +339,8 @@ enum { EVT_DROP = 0x5023, EVT_BUT_CANCEL = 0x5024, + /* could become manipulator callback */ + EVT_MANIPULATOR_UPDATE = 0x5025, /* ********** End of Blender internal events. ********** */ }; |