diff options
Diffstat (limited to 'source/blender')
492 files changed, 10755 insertions, 5099 deletions
diff --git a/source/blender/blenfont/BLF_api.h b/source/blender/blenfont/BLF_api.h index d8dee7110a5..9527c4edcf0 100644 --- a/source/blender/blenfont/BLF_api.h +++ b/source/blender/blenfont/BLF_api.h @@ -36,6 +36,7 @@ struct rctf; struct ColorManagedDisplay; +struct ResultBLF; int BLF_init(int points, int dpi); void BLF_exit(void); @@ -79,9 +80,11 @@ void BLF_draw_default(float x, float y, float z, const char *str, size_t len) AT void BLF_draw_default_ascii(float x, float y, float z, const char *str, size_t len) ATTR_NONNULL(); /* Draw the string using the current font. */ -void BLF_draw(int fontid, const char *str, size_t len); -void BLF_draw_ascii(int fontid, const char *str, size_t len); -int BLF_draw_mono(int fontid, const char *str, size_t len, int cwidth); +void BLF_draw_ex(int fontid, const char *str, size_t len, struct ResultBLF *r_info) ATTR_NONNULL(2); +void BLF_draw(int fontid, const char *str, size_t len) ATTR_NONNULL(2); +void BLF_draw_ascii_ex(int fontid, const char *str, size_t len, struct ResultBLF *r_info) ATTR_NONNULL(2); +void BLF_draw_ascii(int fontid, const char *str, size_t len) ATTR_NONNULL(2); +int BLF_draw_mono(int fontid, const char *str, size_t len, int cwidth) ATTR_NONNULL(2); /* Get the string byte offset that fits within a given width */ size_t BLF_width_to_strlen(int fontid, const char *str, size_t len, float width, float *r_width) ATTR_NONNULL(2); @@ -91,17 +94,20 @@ size_t BLF_width_to_rstrlen(int fontid, const char *str, size_t len, float width /* This function return the bounding box of the string * and are not multiplied by the aspect. */ +void BLF_boundbox_ex(int fontid, const char *str, size_t len, struct rctf *box, struct ResultBLF *r_info) ATTR_NONNULL(2); void BLF_boundbox(int fontid, const char *str, size_t len, struct rctf *box) ATTR_NONNULL(); /* The next both function return the width and height * of the string, using the current font and both value * are multiplied by the aspect of the font. */ +float BLF_width_ex(int fontid, const char *str, size_t len, struct ResultBLF *r_info) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(2); float BLF_width(int fontid, const char *str, size_t len) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); +float BLF_height_ex(int fontid, const char *str, size_t len, struct ResultBLF *r_info) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(2); float BLF_height(int fontid, const char *str, size_t len) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); /* Return dimensions of the font without any sample text. */ -float BLF_height_max(int fontid) ATTR_WARN_UNUSED_RESULT; +int BLF_height_max(int fontid) ATTR_WARN_UNUSED_RESULT; float BLF_width_max(int fontid) ATTR_WARN_UNUSED_RESULT; float BLF_descender(int fontid) ATTR_WARN_UNUSED_RESULT; float BLF_ascender(int fontid) ATTR_WARN_UNUSED_RESULT; @@ -137,6 +143,7 @@ void BLF_disable_default(int option); 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); void BLF_blur(int fontid, int size); void BLF_enable(int fontid, int option); @@ -172,7 +179,8 @@ void BLF_buffer_col(int fontid, float r, float g, float b, float a); /* Draw the string into the buffer, this function draw in both buffer, float and unsigned char _BUT_ * it's not necessary set both buffer, NULL is valid here. */ -void BLF_draw_buffer(int fontid, const char *str) ATTR_NONNULL(); +void BLF_draw_buffer_ex(int fontid, const char *str, size_t len, struct ResultBLF *r_info) ATTR_NONNULL(2); +void BLF_draw_buffer(int fontid, const char *str, size_t len) ATTR_NONNULL(2); /* Add a path to the font dir paths. */ void BLF_dir_add(const char *path) ATTR_NONNULL(); @@ -210,6 +218,7 @@ void BLF_state_print(int fontid); #define BLF_MATRIX (1 << 4) #define BLF_ASPECT (1 << 5) #define BLF_HINTING (1 << 6) +#define BLF_WORD_WRAP (1 << 7) #define BLF_DRAW_STR_DUMMY_MAX 1024 @@ -217,4 +226,18 @@ void BLF_state_print(int fontid); extern int blf_mono_font; extern int blf_mono_font_render; /* don't mess drawing with render threads. */ +/** + * Result of drawing/evaluating the string + */ +struct ResultBLF { + /** + * Number of lines drawn when #BLF_WORD_WRAP is enabled (both wrapped and `\n` newline). + */ + int lines; + /** + * The 'cursor' position on completion (ignoring character boundbox). + */ + int width; +}; + #endif /* __BLF_API_H__ */ diff --git a/source/blender/blenfont/intern/blf.c b/source/blender/blenfont/intern/blf.c index 127826f98c8..b7d72bb28bb 100644 --- a/source/blender/blenfont/intern/blf.c +++ b/source/blender/blenfont/intern/blf.c @@ -53,6 +53,8 @@ #include "BIF_gl.h" #include "BLF_api.h" +#include "IMB_colormanagement.h" + #include "blf_internal_types.h" #include "blf_internal.h" @@ -66,6 +68,11 @@ /* call BLF_default_set first! */ #define ASSERT_DEFAULT_SET BLI_assert(global_font_default != -1) +#define BLF_RESULT_CHECK_INIT(r_info) \ +if (r_info) { \ + memset(r_info, 0, sizeof(*(r_info))); \ +} ((void)0) + /* Font array. */ static FontBLF *global_font[BLF_MAX_FONT] = {NULL}; @@ -169,9 +176,6 @@ int BLF_load(const char *name) char *filename; int i; - if (!name) - return -1; - /* check if we already load this font. */ i = blf_search(name); if (i >= 0) { @@ -209,9 +213,6 @@ int BLF_load_unique(const char *name) char *filename; int i; - if (!name) - return -1; - /* Don't search in the cache!! make a new * object font, this is for keep fonts threads safe. */ @@ -253,9 +254,6 @@ int BLF_load_mem(const char *name, const unsigned char *mem, int mem_size) FontBLF *font; int i; - if (!name) - return -1; - i = blf_search(name); if (i >= 0) { /*font = global_font[i];*/ /*UNUSED*/ @@ -268,7 +266,7 @@ int BLF_load_mem(const char *name, const unsigned char *mem, int mem_size) return -1; } - if (!mem || !mem_size) { + if (!mem_size) { printf("Can't load font: %s from memory!!\n", name); return -1; } @@ -288,9 +286,6 @@ int BLF_load_mem_unique(const char *name, const unsigned char *mem, int mem_size FontBLF *font; int i; - if (!name) - return -1; - /* * Don't search in the cache, make a new object font! * this is to keep the font thread safe. @@ -301,7 +296,7 @@ int BLF_load_mem_unique(const char *name, const unsigned char *mem, int mem_size return -1; } - if (!mem || !mem_size) { + if (!mem_size) { printf("Can't load font: %s from memory!!\n", name); return -1; } @@ -491,7 +486,7 @@ void BLF_rotation_default(float angle) } } -static void blf_draw__start(FontBLF *font, GLint *mode, GLint *param) +static void blf_draw_gl__start(FontBLF *font, GLint *mode, GLint *param) { /* * The pixmap alignment hack is handle @@ -515,7 +510,7 @@ static void blf_draw__start(FontBLF *font, GLint *mode, GLint *param) if (font->flags & BLF_MATRIX) glMultMatrixd((GLdouble *)&font->m); - glTranslatef(font->pos[0], font->pos[1], font->pos[2]); + glTranslate3fv(font->pos); if (font->flags & BLF_ASPECT) glScalef(font->aspect[0], font->aspect[1], font->aspect[2]); @@ -535,7 +530,7 @@ static void blf_draw__start(FontBLF *font, GLint *mode, GLint *param) glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); } -static void blf_draw__end(GLint mode, GLint param) +static void blf_draw_gl__end(GLint mode, GLint param) { /* and restore the original value. */ if (param != GL_MODULATE) @@ -554,29 +549,56 @@ static void blf_draw__end(GLint mode, GLint param) glDisable(GL_TEXTURE_2D); } -void BLF_draw(int fontid, const char *str, size_t len) +void BLF_draw_ex( + int fontid, const char *str, size_t len, + struct ResultBLF *r_info) { FontBLF *font = blf_get(fontid); GLint mode, param; + BLF_RESULT_CHECK_INIT(r_info); + if (font && font->glyph_cache) { - blf_draw__start(font, &mode, ¶m); - blf_font_draw(font, str, len); - blf_draw__end(mode, param); + blf_draw_gl__start(font, &mode, ¶m); + 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, param); } } +void BLF_draw(int fontid, const char *str, size_t len) +{ + BLF_draw_ex(fontid, str, len, NULL); +} -void BLF_draw_ascii(int fontid, const char *str, size_t len) +void BLF_draw_ascii_ex( + int fontid, const char *str, size_t len, + struct ResultBLF *r_info) { FontBLF *font = blf_get(fontid); GLint mode, param; + BLF_RESULT_CHECK_INIT(r_info); + if (font && font->glyph_cache) { - blf_draw__start(font, &mode, ¶m); - blf_font_draw_ascii(font, str, len); - blf_draw__end(mode, param); + blf_draw_gl__start(font, &mode, ¶m); + if (font->flags & BLF_WORD_WRAP) { + /* use non-ascii draw function for word-wrap */ + blf_font_draw__wrap(font, str, len, r_info); + } + else { + blf_font_draw_ascii(font, str, len, r_info); + } + blf_draw_gl__end(mode, param); } } +void BLF_draw_ascii(int fontid, const char *str, size_t len) +{ + BLF_draw_ascii_ex(fontid, str, len, NULL); +} int BLF_draw_mono(int fontid, const char *str, size_t len, int cwidth) { @@ -585,9 +607,9 @@ int BLF_draw_mono(int fontid, const char *str, size_t len, int cwidth) int columns = 0; if (font && font->glyph_cache) { - blf_draw__start(font, &mode, ¶m); + blf_draw_gl__start(font, &mode, ¶m); columns = blf_font_draw_mono(font, str, len, cwidth); - blf_draw__end(mode, param); + blf_draw_gl__end(mode, param); } return columns; @@ -633,21 +655,34 @@ size_t BLF_width_to_rstrlen(int fontid, const char *str, size_t len, float width return 0; } -void BLF_boundbox(int fontid, const char *str, size_t len, rctf *box) +void BLF_boundbox_ex( + int fontid, const char *str, size_t len, rctf *r_box, + struct ResultBLF *r_info) { FontBLF *font = blf_get(fontid); + BLF_RESULT_CHECK_INIT(r_info); + if (font) { - blf_font_boundbox(font, str, len, box); + if (font->flags & BLF_WORD_WRAP) { + blf_font_boundbox__wrap(font, str, len, r_box, r_info); + } + else { + blf_font_boundbox(font, str, len, r_box, r_info); + } } } +void BLF_boundbox(int fontid, const char *str, size_t len, rctf *r_box) +{ + BLF_boundbox_ex(fontid, str, len, r_box, NULL); +} void BLF_width_and_height(int fontid, const char *str, size_t len, float *r_width, float *r_height) { FontBLF *font = blf_get(fontid); if (font && font->glyph_cache) { - blf_font_width_and_height(font, str, len, r_width, r_height); + blf_font_width_and_height(font, str, len, r_width, r_height, NULL); } else { *r_width = *r_height = 0.0f; @@ -662,16 +697,24 @@ void BLF_width_and_height_default(const char *str, size_t len, float *r_width, f BLF_width_and_height(global_font_default, str, len, r_width, r_height); } -float BLF_width(int fontid, const char *str, size_t len) +float BLF_width_ex( + int fontid, const char *str, size_t len, + struct ResultBLF *r_info) { FontBLF *font = blf_get(fontid); + BLF_RESULT_CHECK_INIT(r_info); + if (font && font->glyph_cache) { - return blf_font_width(font, str, len); + return blf_font_width(font, str, len, r_info); } return 0.0f; } +float BLF_width(int fontid, const char *str, size_t len) +{ + return BLF_width_ex(fontid, str, len, NULL); +} float BLF_fixed_width(int fontid) { @@ -692,18 +735,26 @@ float BLF_width_default(const char *str, size_t len) return BLF_width(global_font_default, str, len); } -float BLF_height(int fontid, const char *str, size_t len) +float BLF_height_ex( + int fontid, const char *str, size_t len, + struct ResultBLF *r_info) { FontBLF *font = blf_get(fontid); + BLF_RESULT_CHECK_INIT(r_info); + if (font && font->glyph_cache) { - return blf_font_height(font, str, len); + return blf_font_height(font, str, len, r_info); } return 0.0f; } +float BLF_height(int fontid, const char *str, size_t len) +{ + return BLF_height_ex(fontid, str, len, NULL); +} -float BLF_height_max(int fontid) +int BLF_height_max(int fontid) { FontBLF *font = blf_get(fontid); @@ -711,7 +762,7 @@ float BLF_height_max(int fontid) return font->glyph_cache->max_glyph_height; } - return 0.0f; + return 0; } float BLF_width_max(int fontid) @@ -789,6 +840,15 @@ void BLF_clipping_default(float xmin, float ymin, float xmax, float ymax) } } +void BLF_wordwrap(int fontid, int wrap_width) +{ + FontBLF *font = blf_get(fontid); + + if (font) { + font->wrap_width = wrap_width; + } +} + void BLF_shadow(int fontid, int level, float r, float g, float b, float a) { FontBLF *font = blf_get(fontid); @@ -831,21 +891,52 @@ void BLF_buffer_col(int fontid, float r, float g, float b, float a) FontBLF *font = blf_get(fontid); if (font) { - font->buf_info.col[0] = r; - font->buf_info.col[1] = g; - font->buf_info.col[2] = b; - font->buf_info.col[3] = a; + ARRAY_SET_ITEMS(font->buf_info.col_init, r, g, b, a); + } +} + + +void blf_draw_buffer__start(FontBLF *font) +{ + FontBufInfoBLF *buf_info = &font->buf_info; + + buf_info->col_char[0] = buf_info->col_init[0] * 255; + buf_info->col_char[1] = buf_info->col_init[1] * 255; + buf_info->col_char[2] = buf_info->col_init[2] * 255; + buf_info->col_char[3] = buf_info->col_init[3] * 255; + + if (buf_info->display) { + copy_v4_v4(buf_info->col_float, buf_info->col_init); + IMB_colormanagement_display_to_scene_linear_v3(buf_info->col_float, buf_info->display); + } + else { + srgb_to_linearrgb_v4(buf_info->col_float, buf_info->col_init); } } +void blf_draw_buffer__end(void) {} -void BLF_draw_buffer(int fontid, const char *str) +void BLF_draw_buffer_ex( + int fontid, const char *str, size_t len, + struct ResultBLF *r_info) { FontBLF *font = blf_get(fontid); if (font && font->glyph_cache && (font->buf_info.fbuf || font->buf_info.cbuf)) { - blf_font_buffer(font, str); + blf_draw_buffer__start(font); + if (font->flags & BLF_WORD_WRAP) { + blf_font_draw_buffer__wrap(font, str, len, r_info); + } + else { + blf_font_draw_buffer(font, str, len, r_info); + } + blf_draw_buffer__end(); } } +void BLF_draw_buffer( + int fontid, const char *str, size_t len) +{ + BLF_draw_buffer_ex(fontid, str, len, NULL); +} #ifdef DEBUG void BLF_state_print(int fontid) diff --git a/source/blender/blenfont/intern/blf_font.c b/source/blender/blenfont/intern/blf_font.c index 2057b0f6bbf..3f3ca78b6cd 100644 --- a/source/blender/blenfont/intern/blf_font.c +++ b/source/blender/blenfont/intern/blf_font.c @@ -58,8 +58,6 @@ #include "BIF_gl.h" #include "BLF_api.h" -#include "IMB_colormanagement.h" - #include "blf_internal_types.h" #include "blf_internal.h" @@ -153,7 +151,7 @@ static void blf_font_ensure_ascii_table(FontBLF *font) #define BLF_KERNING_VARS(_font, _has_kerning, _kern_mode) \ - const bool _has_kerning = FT_HAS_KERNING((_font)->face); \ + const bool _has_kerning = FT_HAS_KERNING((_font)->face) != 0; \ const FT_UInt _kern_mode = (_has_kerning == 0) ? 0 : \ (((_font)->flags & BLF_KERNING_DEFAULT) ? \ ft_kerning_default : (FT_UInt)FT_KERNING_UNFITTED) \ @@ -174,12 +172,14 @@ static void blf_font_ensure_ascii_table(FontBLF *font) } \ } (void)0 -void blf_font_draw(FontBLF *font, const char *str, size_t len) +static void blf_font_draw_ex( + FontBLF *font, const char *str, size_t len, struct ResultBLF *r_info, + int pen_y) { unsigned int c; GlyphBLF *g, *g_prev = NULL; FT_Vector delta; - int pen_x = 0, pen_y = 0; + int pen_x = 0; size_t i = 0; GlyphBLF **glyph_ascii_table = font->glyph_cache->glyph_ascii_table; @@ -203,15 +203,26 @@ void blf_font_draw(FontBLF *font, const char *str, size_t len) pen_x += g->advance_i; g_prev = g; } + + if (r_info) { + r_info->lines = 1; + r_info->width = pen_x; + } +} +void blf_font_draw(FontBLF *font, const char *str, size_t len, struct ResultBLF *r_info) +{ + blf_font_draw_ex(font, str, len, r_info, 0); } /* faster version of blf_font_draw, ascii only for view dimensions */ -void blf_font_draw_ascii(FontBLF *font, const char *str, size_t len) +static void blf_font_draw_ascii_ex( + FontBLF *font, const char *str, size_t len, struct ResultBLF *r_info, + int pen_y) { unsigned char c; GlyphBLF *g, *g_prev = NULL; FT_Vector delta; - int pen_x = 0, pen_y = 0; + int pen_x = 0; GlyphBLF **glyph_ascii_table = font->glyph_cache->glyph_ascii_table; BLF_KERNING_VARS(font, has_kerning, kern_mode); @@ -231,6 +242,15 @@ void blf_font_draw_ascii(FontBLF *font, const char *str, size_t len) pen_x += g->advance_i; g_prev = g; } + + if (r_info) { + r_info->lines = 1; + r_info->width = pen_x; + } +} +void blf_font_draw_ascii(FontBLF *font, const char *str, size_t len, struct ResultBLF *r_info) +{ + blf_font_draw_ascii_ex(font, str, len, r_info, 0); } /* use fixed column width, but an utf8 character may occupy multiple columns */ @@ -268,24 +288,22 @@ int blf_font_draw_mono(FontBLF *font, const char *str, size_t len, int cwidth) } /* Sanity checks are done by BLF_draw_buffer() */ -void blf_font_buffer(FontBLF *font, const char *str) +static void blf_font_draw_buffer_ex( + FontBLF *font, const char *str, size_t len, struct ResultBLF *r_info, + int pen_y) { unsigned int c; GlyphBLF *g, *g_prev = NULL; FT_Vector delta; - int pen_x = (int)font->pos[0], pen_y = 0; + int pen_x = (int)font->pos[0]; + int pen_y_basis = (int)font->pos[1] + pen_y; size_t i = 0; GlyphBLF **glyph_ascii_table = font->glyph_cache->glyph_ascii_table; /* buffer specific vars */ FontBufInfoBLF *buf_info = &font->buf_info; - float b_col_float[4]; - const unsigned char b_col_char[4] = { - (unsigned char)(buf_info->col[0] * 255), - (unsigned char)(buf_info->col[1] * 255), - (unsigned char)(buf_info->col[2] * 255), - (unsigned char)(buf_info->col[3] * 255)}; - + const float *b_col_float = buf_info->col_float; + const unsigned char *b_col_char = buf_info->col_char; int chx, chy; int y, x; float a; @@ -295,15 +313,8 @@ void blf_font_buffer(FontBLF *font, const char *str) blf_font_ensure_ascii_table(font); /* another buffer specific call for color conversion */ - if (buf_info->display) { - copy_v4_v4(b_col_float, buf_info->col); - IMB_colormanagement_display_to_scene_linear_v3(b_col_float, buf_info->display); - } - else { - srgb_to_linearrgb_v4(b_col_float, buf_info->col); - } - while (str[i]) { + while ((i < len) && str[i]) { BLF_UTF8_NEXT_FAST(font, g, str, i, c, glyph_ascii_table); if (UNLIKELY(c == BLI_UTF8_ERR)) @@ -314,13 +325,13 @@ void blf_font_buffer(FontBLF *font, const char *str) BLF_KERNING_STEP(font, kern_mode, g_prev, g, delta, pen_x); chx = pen_x + ((int)g->pos_x); - chy = (int)font->pos[1] + g->height; + chy = pen_y_basis + g->height; if (g->pitch < 0) { - pen_y = (int)font->pos[1] + (g->height - (int)g->pos_y); + pen_y = pen_y_basis + (g->height - (int)g->pos_y); } else { - pen_y = (int)font->pos[1] - (g->height - (int)g->pos_y); + pen_y = pen_y_basis - (g->height - (int)g->pos_y); } if ((chx + g->width) >= 0 && chx < buf_info->w && (pen_y + g->height) >= 0 && pen_y < buf_info->h) { @@ -429,6 +440,16 @@ void blf_font_buffer(FontBLF *font, const char *str) pen_x += g->advance_i; g_prev = g; } + + if (r_info) { + r_info->lines = 1; + r_info->width = pen_x; + } +} +void blf_font_draw_buffer( + FontBLF *font, const char *str, size_t len, struct ResultBLF *r_info) +{ + blf_font_draw_buffer_ex(font, str, len, r_info, 0); } size_t blf_font_width_to_strlen(FontBLF *font, const char *str, size_t len, float width, float *r_width) @@ -558,12 +579,14 @@ size_t blf_font_width_to_rstrlen(FontBLF *font, const char *str, size_t len, flo return i_prev; } -void blf_font_boundbox(FontBLF *font, const char *str, size_t len, rctf *box) +static void blf_font_boundbox_ex( + FontBLF *font, const char *str, size_t len, rctf *box, struct ResultBLF *r_info, + int pen_y) { unsigned int c; GlyphBLF *g, *g_prev = NULL; FT_Vector delta; - int pen_x = 0, pen_y = 0; + int pen_x = 0; size_t i = 0; GlyphBLF **glyph_ascii_table = font->glyph_cache->glyph_ascii_table; @@ -609,9 +632,168 @@ void blf_font_boundbox(FontBLF *font, const char *str, size_t len, rctf *box) box->xmax = 0.0f; box->ymax = 0.0f; } + + if (r_info) { + r_info->lines = 1; + r_info->width = pen_x; + } } +void blf_font_boundbox(FontBLF *font, const char *str, size_t len, rctf *r_box, struct ResultBLF *r_info) +{ + blf_font_boundbox_ex(font, str, len, r_box, r_info, 0); +} + + +/* -------------------------------------------------------------------- */ +/** \name Word-Wrap Support + * \{ */ + -void blf_font_width_and_height(FontBLF *font, const char *str, size_t len, float *width, float *height) +/** + * Generic function to add word-wrap support for other existing functions. + * + * Wraps on spaces and respects newlines. + * Intentionally ignores non-unix newlines, tabs and more advanced text formatting. + * + * \note If we want rich text - we better have a higher level API to handle that + * (color, bold, switching fonts... etc). + */ +static void blf_font_wrap_apply( + FontBLF *font, const char *str, size_t len, struct ResultBLF *r_info, + void (*callback)(FontBLF *font, const char *str, size_t len, int pen_y, void *userdata), + void *userdata) +{ + unsigned int c; + GlyphBLF *g, *g_prev = NULL; + FT_Vector delta; + int pen_x = 0, pen_y = 0; + size_t i = 0; + GlyphBLF **glyph_ascii_table = font->glyph_cache->glyph_ascii_table; + int lines = 0; + int pen_x_next = 0; + + BLF_KERNING_VARS(font, has_kerning, kern_mode); + + struct WordWrapVars { + int wrap_width; + size_t start, last[2]; + } wrap = {font->wrap_width != -1 ? font->wrap_width : INT_MAX, 0, {0, 0}}; + + blf_font_ensure_ascii_table(font); + // printf("%s wrapping (%d, %d) `%s`:\n", __func__, len, strlen(str), str); + while ((i < len) && str[i]) { + + /* wrap vars */ + size_t i_curr = i; + bool do_draw = false; + + BLF_UTF8_NEXT_FAST(font, g, str, i, c, glyph_ascii_table); + + if (UNLIKELY(c == BLI_UTF8_ERR)) + break; + if (UNLIKELY(g == NULL)) + continue; + if (has_kerning) + BLF_KERNING_STEP(font, kern_mode, g_prev, g, delta, pen_x); + + /** + * Implementation Detail (utf8). + * + * Take care with single byte offsets here, + * since this is utf8 we can't be sure a single byte is a single character. + * + * This is _only_ done when we know for sure the character is ascii (newline or a space). + */ + pen_x_next = pen_x + g->advance_i; + if (UNLIKELY((pen_x_next >= wrap.wrap_width) && (wrap.start != wrap.last[0]))) { + do_draw = true; + } + else if (UNLIKELY(((i < len) && str[i]) == 0)) { + /* need check here for trailing newline, else we draw it */ + wrap.last[0] = i + ((g->c != '\n') ? 1 : 0); + wrap.last[1] = i; + do_draw = true; + } + else if (UNLIKELY(g->c == '\n')) { + wrap.last[0] = i_curr + 1; + wrap.last[1] = i; + do_draw = true; + } + else if (UNLIKELY(g->c != ' ' && (g_prev ? g_prev->c == ' ' : false))) { + wrap.last[0] = i_curr; + wrap.last[1] = i; + } + + if (UNLIKELY(do_draw)) { + // printf("(%d..%d) `%.*s`\n", wrap.start, wrap.last[0], (wrap.last[0] - wrap.start) - 1, &str[wrap.start]); + callback(font, &str[wrap.start], (wrap.last[0] - wrap.start) - 1, pen_y, userdata); + wrap.start = wrap.last[0]; + i = wrap.last[1]; + pen_x = 0; + pen_y -= font->glyph_cache->max_glyph_height; + g_prev = NULL; + lines += 1; + continue; + } + + pen_x = pen_x_next; + g_prev = g; + } + + // printf("done! %d lines\n", lines); + + if (r_info) { + r_info->lines = lines; + /* width of last line only (with wrapped lines) */ + r_info->width = pen_x_next; + } +} + +/* blf_font_draw__wrap */ +static void blf_font_draw__wrap_cb(FontBLF *font, const char *str, size_t len, int pen_y, void *UNUSED(userdata)) +{ + blf_font_draw_ex(font, str, len, NULL, pen_y); +} +void blf_font_draw__wrap(FontBLF *font, const char *str, size_t len, struct ResultBLF *r_info) +{ + blf_font_wrap_apply(font, str, len, r_info, blf_font_draw__wrap_cb, NULL); +} + +/* blf_font_boundbox__wrap */ +static void blf_font_boundbox_wrap_cb(FontBLF *font, const char *str, size_t len, int pen_y, void *userdata) +{ + rctf *box = userdata; + rctf box_single; + + blf_font_boundbox_ex(font, str, len, &box_single, NULL, pen_y); + BLI_rctf_union(box, &box_single); +} +void blf_font_boundbox__wrap(FontBLF *font, const char *str, size_t len, rctf *box, struct ResultBLF *r_info) +{ + box->xmin = 32000.0f; + box->xmax = -32000.0f; + box->ymin = 32000.0f; + box->ymax = -32000.0f; + + blf_font_wrap_apply(font, str, len, r_info, blf_font_boundbox_wrap_cb, box); +} + +/* blf_font_draw_buffer__wrap */ +static void blf_font_draw_buffer__wrap_cb(FontBLF *font, const char *str, size_t len, int pen_y, void *UNUSED(userdata)) +{ + blf_font_draw_buffer_ex(font, str, len, NULL, pen_y); +} +void blf_font_draw_buffer__wrap(FontBLF *font, const char *str, size_t len, struct ResultBLF *r_info) +{ + blf_font_wrap_apply(font, str, len, r_info, blf_font_draw_buffer__wrap_cb, NULL); +} + +/** \} */ + + +void blf_font_width_and_height( + FontBLF *font, const char *str, size_t len, + float *r_width, float *r_height, struct ResultBLF *r_info) { float xa, ya; rctf box; @@ -625,12 +807,17 @@ void blf_font_width_and_height(FontBLF *font, const char *str, size_t len, float ya = 1.0f; } - blf_font_boundbox(font, str, len, &box); - *width = (BLI_rctf_size_x(&box) * xa); - *height = (BLI_rctf_size_y(&box) * ya); + if (font->flags & BLF_WORD_WRAP) { + blf_font_boundbox__wrap(font, str, len, &box, r_info); + } + else { + blf_font_boundbox(font, str, len, &box, r_info); + } + *r_width = (BLI_rctf_size_x(&box) * xa); + *r_height = (BLI_rctf_size_y(&box) * ya); } -float blf_font_width(FontBLF *font, const char *str, size_t len) +float blf_font_width(FontBLF *font, const char *str, size_t len, struct ResultBLF *r_info) { float xa; rctf box; @@ -640,11 +827,16 @@ float blf_font_width(FontBLF *font, const char *str, size_t len) else xa = 1.0f; - blf_font_boundbox(font, str, len, &box); + if (font->flags & BLF_WORD_WRAP) { + blf_font_boundbox__wrap(font, str, len, &box, r_info); + } + else { + blf_font_boundbox(font, str, len, &box, r_info); + } return BLI_rctf_size_x(&box) * xa; } -float blf_font_height(FontBLF *font, const char *str, size_t len) +float blf_font_height(FontBLF *font, const char *str, size_t len, struct ResultBLF *r_info) { float ya; rctf box; @@ -654,7 +846,12 @@ float blf_font_height(FontBLF *font, const char *str, size_t len) else ya = 1.0f; - blf_font_boundbox(font, str, len, &box); + if (font->flags & BLF_WORD_WRAP) { + blf_font_boundbox__wrap(font, str, len, &box, r_info); + } + else { + blf_font_boundbox(font, str, len, &box, r_info); + } return BLI_rctf_size_y(&box) * ya; } @@ -744,10 +941,10 @@ static void blf_font_fill(FontBLF *font) font->buf_info.w = 0; font->buf_info.h = 0; font->buf_info.ch = 0; - font->buf_info.col[0] = 0; - font->buf_info.col[1] = 0; - font->buf_info.col[2] = 0; - font->buf_info.col[3] = 0; + font->buf_info.col_init[0] = 0; + font->buf_info.col_init[1] = 0; + font->buf_info.col_init[2] = 0; + font->buf_info.col_init[3] = 0; font->ft_lib = ft_lib; font->ft_lib_mutex = &ft_lib_mutex; diff --git a/source/blender/blenfont/intern/blf_internal.h b/source/blender/blenfont/intern/blf_internal.h index 85410a4d856..d9d758ce548 100644 --- a/source/blender/blenfont/intern/blf_internal.h +++ b/source/blender/blenfont/intern/blf_internal.h @@ -31,6 +31,7 @@ #ifndef __BLF_INTERNAL_H__ #define __BLF_INTERNAL_H__ +struct ResultBLF; struct FontBLF; struct GlyphBLF; struct GlyphCacheBLF; @@ -46,21 +47,27 @@ char *blf_dir_metrics_search(const char *filename); int blf_font_init(void); void blf_font_exit(void); +void blf_draw_buffer__start(struct FontBLF *font); +void blf_draw_buffer__end(void); + struct FontBLF *blf_font_new(const char *name, const char *filename); struct FontBLF *blf_font_new_from_mem(const char *name, const unsigned char *mem, int mem_size); void blf_font_attach_from_mem(struct FontBLF *font, const unsigned char *mem, int mem_size); void blf_font_size(struct FontBLF *font, unsigned int size, unsigned int dpi); -void blf_font_draw(struct FontBLF *font, const char *str, size_t len); -void blf_font_draw_ascii(struct FontBLF *font, const char *str, size_t len); +void blf_font_draw(struct FontBLF *font, const char *str, size_t len, struct ResultBLF *r_info); +void blf_font_draw__wrap(struct FontBLF *font, const char *str, size_t len, struct ResultBLF *r_info); +void blf_font_draw_ascii(struct FontBLF *font, const char *str, size_t len, struct ResultBLF *r_info); int blf_font_draw_mono(struct FontBLF *font, const char *str, size_t len, int cwidth); -void blf_font_buffer(struct FontBLF *font, const char *str); +void blf_font_draw_buffer(struct FontBLF *font, const char *str, size_t len, struct ResultBLF *r_info); +void blf_font_draw_buffer__wrap(struct FontBLF *font, const char *str, size_t len, struct ResultBLF *r_info); size_t blf_font_width_to_strlen(struct FontBLF *font, const char *str, size_t len, float width, float *r_width); size_t blf_font_width_to_rstrlen(struct FontBLF *font, const char *str, size_t len, float width, float *r_width); -void blf_font_boundbox(struct FontBLF *font, const char *str, size_t len, struct rctf *box); -void blf_font_width_and_height(struct FontBLF *font, const char *str, size_t len, float *width, float *height); -float blf_font_width(struct FontBLF *font, const char *str, size_t len); -float blf_font_height(struct FontBLF *font, const char *str, size_t len); +void blf_font_boundbox(struct FontBLF *font, const char *str, size_t len, struct rctf *r_box, struct ResultBLF *r_info); +void blf_font_boundbox__wrap(struct FontBLF *font, const char *str, size_t len, struct rctf *r_box, struct ResultBLF *r_info); +void blf_font_width_and_height(struct FontBLF *font, const char *str, size_t len, float *r_width, float *r_height, struct ResultBLF *r_info); +float blf_font_width(struct FontBLF *font, const char *str, size_t len, struct ResultBLF *r_info); +float blf_font_height(struct FontBLF *font, const char *str, size_t len, struct ResultBLF *r_info); float blf_font_fixed_width(struct FontBLF *font); int blf_font_count_missing_chars(struct FontBLF *font, const char *str, const size_t len, int *r_tot_chars); diff --git a/source/blender/blenfont/intern/blf_internal_types.h b/source/blender/blenfont/intern/blf_internal_types.h index 1404b9de250..f17401a9991 100644 --- a/source/blender/blenfont/intern/blf_internal_types.h +++ b/source/blender/blenfont/intern/blf_internal_types.h @@ -152,7 +152,11 @@ typedef struct FontBufInfoBLF { /* and the color, the alphas is get from the glyph! * color is srgb space */ - float col[4]; + float col_init[4]; + /* cached conversion from 'col_init' */ + unsigned char col_char[4]; + float col_float[4]; + } FontBufInfoBLF; typedef struct FontBLF { @@ -195,6 +199,9 @@ typedef struct FontBLF { /* clipping rectangle. */ rctf clip_rec; + /* the width to wrap the text, see BLF_WORD_WRAP */ + int wrap_width; + /* font dpi (default 72). */ unsigned int dpi; diff --git a/source/blender/blenfont/intern/blf_thumbs.c b/source/blender/blenfont/intern/blf_thumbs.c index 4eea5d581d0..133168fccf2 100644 --- a/source/blender/blenfont/intern/blf_thumbs.c +++ b/source/blender/blenfont/intern/blf_thumbs.c @@ -84,11 +84,13 @@ void BLF_thumb_preview( /* Always create the image with a white font, * the caller can theme how it likes */ - memcpy(font->buf_info.col, font_color, sizeof(font->buf_info.col)); + memcpy(font->buf_info.col_init, font_color, sizeof(font->buf_info.col_init)); font->pos[1] = (float)h; font_size_curr = font_size; + blf_draw_buffer__start(font); + for (i = 0; i < draw_str_lines; i++) { const char *draw_str_i18n = BLT_translate_do(BLT_I18NCONTEXT_DEFAULT, draw_str[i]); const size_t draw_str_i18n_len = strlen(draw_str_i18n); @@ -110,12 +112,13 @@ void BLF_thumb_preview( if (blf_font_count_missing_chars( font, draw_str_i18n, draw_str_i18n_len, &draw_str_i18n_nbr) > (draw_str_i18n_nbr / 2)) { - blf_font_buffer(font, draw_str[i]); + blf_font_draw_buffer(font, draw_str[i], strlen(draw_str[i]), NULL); } else { - blf_font_buffer(font, draw_str_i18n); + blf_font_draw_buffer(font, draw_str_i18n, draw_str_i18n_len, NULL); } } + blf_draw_buffer__end(); blf_font_free(font); } diff --git a/source/blender/blenkernel/BKE_DerivedMesh.h b/source/blender/blenkernel/BKE_DerivedMesh.h index 3883b69c0d4..fad177df978 100644 --- a/source/blender/blenkernel/BKE_DerivedMesh.h +++ b/source/blender/blenkernel/BKE_DerivedMesh.h @@ -499,6 +499,11 @@ void DM_init( DerivedMesh *dm, DerivedMeshType type, int numVerts, int numEdges, int numFaces, int numLoops, int numPolys); +void DM_from_template_ex( + DerivedMesh *dm, DerivedMesh *source, DerivedMeshType type, + int numVerts, int numEdges, int numTessFaces, + int numLoops, int numPolys, + CustomDataMask mask); void DM_from_template( DerivedMesh *dm, DerivedMesh *source, DerivedMeshType type, diff --git a/source/blender/blenkernel/BKE_armature.h b/source/blender/blenkernel/BKE_armature.h index a834a83ca00..e1885e46b24 100644 --- a/source/blender/blenkernel/BKE_armature.h +++ b/source/blender/blenkernel/BKE_armature.h @@ -80,6 +80,8 @@ struct bArmature *BKE_armature_copy(struct bArmature *arm); /* Bounding box. */ struct BoundBox *BKE_armature_boundbox_get(struct Object *ob); +bool BKE_pose_minmax(struct Object *ob, float r_min[3], float r_max[3], bool use_hidden, bool use_select); + int bone_autoside_name(char name[64], int strip_number, short axis, float head, float tail); struct Bone *BKE_armature_find_bone_name(struct bArmature *arm, const char *name); @@ -89,7 +91,7 @@ bool BKE_armature_bone_flag_test_recursive(const struct Bone *bone, int float distfactor_to_bone(const float vec[3], const float b1[3], const float b2[3], float r1, float r2, float rdist); void BKE_armature_where_is(struct bArmature *arm); -void BKE_armature_where_is_bone(struct Bone *bone, struct Bone *prevbone); +void BKE_armature_where_is_bone(struct Bone *bone, struct Bone *prevbone, const bool use_recursion); void BKE_pose_rebuild(struct Object *ob, struct bArmature *arm); 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); diff --git a/source/blender/blenkernel/BKE_blender.h b/source/blender/blenkernel/BKE_blender.h index a13bd0c48ec..607f2a98939 100644 --- a/source/blender/blenkernel/BKE_blender.h +++ b/source/blender/blenkernel/BKE_blender.h @@ -41,8 +41,8 @@ extern "C" { /* these lines are grep'd, watch out for our not-so-awesome regex * and keep comment above the defines. * Use STRINGIFY() rather than defining with quotes */ -#define BLENDER_VERSION 275 -#define BLENDER_SUBVERSION 6 +#define BLENDER_VERSION 276 +#define BLENDER_SUBVERSION 2 /* Several breakages with 270, e.g. constraint deg vs rad */ #define BLENDER_MINVERSION 270 #define BLENDER_MINSUBVERSION 5 diff --git a/source/blender/blenkernel/BKE_brush.h b/source/blender/blenkernel/BKE_brush.h index 042fba7294c..bb3ad0efb63 100644 --- a/source/blender/blenkernel/BKE_brush.h +++ b/source/blender/blenkernel/BKE_brush.h @@ -40,7 +40,9 @@ void BKE_brush_system_init(void); void BKE_brush_system_exit(void); /* datablock functions */ -struct Brush *BKE_brush_add(struct Main *bmain, const char *name); +void BKE_brush_init(struct Brush *brush); +struct Brush *BKE_brush_add(struct Main *bmain, const char *name, short ob_mode); +struct Brush *BKE_brush_first_search(struct Main *bmain, short ob_mode); struct Brush *BKE_brush_copy(struct Brush *brush); void BKE_brush_make_local(struct Brush *brush); void BKE_brush_free(struct Brush *brush); diff --git a/source/blender/blenkernel/BKE_bvhutils.h b/source/blender/blenkernel/BKE_bvhutils.h index 18eda63bcf1..749b0db7c27 100644 --- a/source/blender/blenkernel/BKE_bvhutils.h +++ b/source/blender/blenkernel/BKE_bvhutils.h @@ -68,7 +68,8 @@ typedef struct BVHTreeFromMesh { float sphere_radius; /* Private data */ - void *em_evil; /* var only for snapping */ + void *em_evil; + bool em_evil_all; /* ignore selection/hidden state, adding all loops to the tree */ bool cached; } BVHTreeFromMesh; @@ -141,8 +142,11 @@ enum { BVHTREE_FROM_VERTS = 0, BVHTREE_FROM_EDGES = 1, BVHTREE_FROM_FACES = 2, - BVHTREE_FROM_FACES_EDITMESH = 3, - BVHTREE_FROM_LOOPTRI = 4, + BVHTREE_FROM_LOOPTRI = 3, + /* all faces */ + BVHTREE_FROM_FACES_EDITMESH_ALL = 4, + /* visible unselected, only used for transform snapping */ + BVHTREE_FROM_FACES_EDITMESH_SNAP = 5, }; typedef struct LinkNode *BVHCache; diff --git a/source/blender/blenkernel/BKE_camera.h b/source/blender/blenkernel/BKE_camera.h index aacb7a4066b..118153a9163 100644 --- a/source/blender/blenkernel/BKE_camera.h +++ b/source/blender/blenkernel/BKE_camera.h @@ -50,6 +50,7 @@ struct GPUFXSettings; /* Camera Datablock */ +void BKE_camera_init(struct Camera *cam); void *BKE_camera_add(struct Main *bmain, const char *name); struct Camera *BKE_camera_copy(struct Camera *cam); void BKE_camera_make_local(struct Camera *cam); diff --git a/source/blender/blenkernel/BKE_cdderivedmesh.h b/source/blender/blenkernel/BKE_cdderivedmesh.h index c7ad6419560..9948f21ba90 100644 --- a/source/blender/blenkernel/BKE_cdderivedmesh.h +++ b/source/blender/blenkernel/BKE_cdderivedmesh.h @@ -84,9 +84,15 @@ struct DerivedMesh *CDDM_copy_from_tessface(struct DerivedMesh *dm); * given DerivedMesh and containing the requested numbers of elements. * elements are initialized to all zeros */ -struct DerivedMesh *CDDM_from_template(struct DerivedMesh *source, - int numVerts, int numEdges, int numFaces, - int numLoops, int numPolys); +struct DerivedMesh *CDDM_from_template_ex( + struct DerivedMesh *source, + int numVerts, int numEdges, int numFaces, + int numLoops, int numPolys, + CustomDataMask mask); +struct DerivedMesh *CDDM_from_template( + struct DerivedMesh *source, + int numVerts, int numEdges, int numFaces, + int numLoops, int numPolys); /* converts mfaces to mpolys. note things may break if there are not valid * medges surrounding each mface. diff --git a/source/blender/blenkernel/BKE_curve.h b/source/blender/blenkernel/BKE_curve.h index a03dd287146..061270b8b41 100644 --- a/source/blender/blenkernel/BKE_curve.h +++ b/source/blender/blenkernel/BKE_curve.h @@ -69,6 +69,7 @@ typedef struct CurveCache { void BKE_curve_unlink(struct Curve *cu); void BKE_curve_free(struct Curve *cu); void BKE_curve_editfont_free(struct Curve *cu); +void BKE_curve_init(struct Curve *cu); struct Curve *BKE_curve_add(struct Main *bmain, const char *name, int type); struct Curve *BKE_curve_copy(struct Curve *cu); void BKE_curve_make_local(struct Curve *cu); diff --git a/source/blender/blenkernel/BKE_customdata.h b/source/blender/blenkernel/BKE_customdata.h index 6fb27cf7577..a7c5c210061 100644 --- a/source/blender/blenkernel/BKE_customdata.h +++ b/source/blender/blenkernel/BKE_customdata.h @@ -381,6 +381,10 @@ void CustomData_bmesh_update_active_layers(struct CustomData *fdata, struct Cust void CustomData_bmesh_do_versions_update_active_layers(struct CustomData *fdata, struct CustomData *pdata, struct CustomData *ldata); void CustomData_bmesh_init_pool(struct CustomData *data, int totelem, const char htype); +#ifndef NDEBUG +bool CustomData_from_bmeshpoly_test(CustomData *fdata, CustomData *pdata, CustomData *ldata, bool fallback); +#endif + /* External file storage */ void CustomData_external_add(struct CustomData *data, @@ -468,6 +472,8 @@ typedef struct CustomDataTransferLayerMap { size_t data_offset; /* Offset of actual data we transfer (in element contained in data_src/dst). */ uint64_t data_flag; /* For bitflag transfer, flag(s) to affect in transfered data. */ + void *interp_data; /* Opaque pointer, to be used by specific interp callback (e.g. transformspace for normals). */ + cd_datatransfer_interp interp; } CustomDataTransferLayerMap; diff --git a/source/blender/blenkernel/BKE_depsgraph.h b/source/blender/blenkernel/BKE_depsgraph.h index 7d7db332dd2..40564aeabe9 100644 --- a/source/blender/blenkernel/BKE_depsgraph.h +++ b/source/blender/blenkernel/BKE_depsgraph.h @@ -147,7 +147,10 @@ void DAG_pose_sort(struct Object *ob); /* Editors: callbacks to notify editors of datablock changes */ void DAG_editors_update_cb(void (*id_func)(struct Main *bmain, struct ID *id), - void (*scene_func)(struct Main *bmain, struct Scene *scene, int updated)); + void (*scene_func)(struct Main *bmain, struct Scene *scene, int updated), + void (*scene_pre_func)(struct Main *bmain, struct Scene *scene, bool time)); + +void DAG_editors_update_pre(struct Main *bmain, struct Scene *scene, bool time); /* ** Threaded update ** */ diff --git a/source/blender/blenkernel/BKE_font.h b/source/blender/blenkernel/BKE_font.h index 137670215cc..5dcc6f8d981 100644 --- a/source/blender/blenkernel/BKE_font.h +++ b/source/blender/blenkernel/BKE_font.h @@ -79,8 +79,11 @@ void BKE_vfont_builtin_register(void *mem, int size); void BKE_vfont_free_data(struct VFont *vfont); void BKE_vfont_free(struct VFont *sc); +void BKE_vfont_init(struct VFont *vfont); struct VFont *BKE_vfont_builtin_get(void); -struct VFont *BKE_vfont_load(struct Main *bmain, const char *name); +struct VFont *BKE_vfont_load(struct Main *bmain, const char *filepath); +struct VFont *BKE_vfont_load_exists_ex(struct Main *bmain, const char *filepath, bool *r_exists); +struct VFont *BKE_vfont_load_exists(struct Main *bmain, const char *filepath); bool BKE_vfont_to_curve_ex(struct Main *bmain, struct Object *ob, int mode, struct ListBase *r_nubase, diff --git a/source/blender/blenkernel/BKE_idcode.h b/source/blender/blenkernel/BKE_idcode.h index ebad0d42232..6de0efe2709 100644 --- a/source/blender/blenkernel/BKE_idcode.h +++ b/source/blender/blenkernel/BKE_idcode.h @@ -32,15 +32,15 @@ * \ingroup bke */ -const char *BKE_idcode_to_name(int code); -const char *BKE_idcode_to_name_plural(int code); -const char *BKE_idcode_to_translation_context(int code); -int BKE_idcode_from_name(const char *name); -bool BKE_idcode_is_linkable(int code); -bool BKE_idcode_is_valid(int code); +const char *BKE_idcode_to_name(short idcode); +const char *BKE_idcode_to_name_plural(short idcode); +const char *BKE_idcode_to_translation_context(short idcode); +short BKE_idcode_from_name(const char *name); +bool BKE_idcode_is_linkable(short idcode); +bool BKE_idcode_is_valid(short idcode); -int BKE_idcode_to_idfilter(const int idcode); -int BKE_idcode_from_idfilter(const int idfilter); +int BKE_idcode_to_idfilter(const short idcode); +short BKE_idcode_from_idfilter(const int idfilter); /** * Return an ID code and steps the index forward 1. @@ -48,6 +48,6 @@ int BKE_idcode_from_idfilter(const int idfilter); * \param index start as 0. * \return the code, 0 when all codes have been returned. */ -int BKE_idcode_iter_step(int *index); +short BKE_idcode_iter_step(int *index); #endif diff --git a/source/blender/blenkernel/BKE_image.h b/source/blender/blenkernel/BKE_image.h index 94afc8a16ea..ea63161e008 100644 --- a/source/blender/blenkernel/BKE_image.h +++ b/source/blender/blenkernel/BKE_image.h @@ -212,6 +212,8 @@ void BKE_image_multiview_index(struct Image *ima, struct ImageUser *iuser); /* for multilayer images as well as for render-viewer */ bool BKE_image_is_multilayer(struct Image *ima); +bool BKE_image_is_multiview(struct Image *ima); +bool BKE_image_is_stereo(struct Image *ima); struct RenderResult *BKE_image_acquire_renderresult(struct Scene *scene, struct Image *ima); void BKE_image_release_renderresult(struct Scene *scene, struct Image *ima); diff --git a/source/blender/blenkernel/BKE_key.h b/source/blender/blenkernel/BKE_key.h index abe12282a1b..1edbb455ca4 100644 --- a/source/blender/blenkernel/BKE_key.h +++ b/source/blender/blenkernel/BKE_key.h @@ -65,6 +65,8 @@ float *BKE_key_evaluate_object_ex( float *BKE_key_evaluate_object( struct Object *ob, int *r_totelem); +struct Key **BKE_key_from_id_p(struct ID *id); +struct Key *BKE_key_from_id(struct ID *id); struct Key **BKE_key_from_object_p(struct Object *ob); struct Key *BKE_key_from_object(struct Object *ob); struct KeyBlock *BKE_keyblock_from_object(struct Object *ob); @@ -101,6 +103,8 @@ void BKE_keyblock_convert_to_curve(struct KeyBlock *kb, struct Curve *cu, st void BKE_keyblock_update_from_mesh(struct Mesh *me, struct KeyBlock *kb); void BKE_keyblock_convert_from_mesh(struct Mesh *me, struct KeyBlock *kb); void BKE_keyblock_convert_to_mesh(struct KeyBlock *kb, struct Mesh *me); +void BKE_keyblock_mesh_calc_normals( + struct KeyBlock *kb, struct Mesh *mesh, float (*r_vertnors)[3], float (*r_polynors)[3], float (*r_loopnors)[3]); void BKE_keyblock_update_from_vertcos(struct Object *ob, struct KeyBlock *kb, float (*vertCos)[3]); void BKE_keyblock_convert_from_vertcos(struct Object *ob, struct KeyBlock *kb, float (*vertCos)[3]); diff --git a/source/blender/blenkernel/BKE_lamp.h b/source/blender/blenkernel/BKE_lamp.h index fb2c4da91ea..d830c19651f 100644 --- a/source/blender/blenkernel/BKE_lamp.h +++ b/source/blender/blenkernel/BKE_lamp.h @@ -42,6 +42,7 @@ struct Lamp; struct Main; struct Scene; +void BKE_lamp_init(struct Lamp *la); struct Lamp *BKE_lamp_add(struct Main *bmain, const char *name) ATTR_WARN_UNUSED_RESULT; struct Lamp *BKE_lamp_copy(struct Lamp *la) ATTR_WARN_UNUSED_RESULT; struct Lamp *localize_lamp(struct Lamp *la) ATTR_WARN_UNUSED_RESULT; diff --git a/source/blender/blenkernel/BKE_lattice.h b/source/blender/blenkernel/BKE_lattice.h index 677d8e34229..828a40de1c9 100644 --- a/source/blender/blenkernel/BKE_lattice.h +++ b/source/blender/blenkernel/BKE_lattice.h @@ -45,6 +45,7 @@ struct BPoint; struct MDeformVert; void BKE_lattice_resize(struct Lattice *lt, int u, int v, int w, struct Object *ltOb); +void BKE_lattice_init(struct Lattice *lt); struct Lattice *BKE_lattice_add(struct Main *bmain, const char *name); struct Lattice *BKE_lattice_copy(struct Lattice *lt); void BKE_lattice_free(struct Lattice *lt); diff --git a/source/blender/blenkernel/BKE_library.h b/source/blender/blenkernel/BKE_library.h index 6ecc955e26c..f46ae5617ac 100644 --- a/source/blender/blenkernel/BKE_library.h +++ b/source/blender/blenkernel/BKE_library.h @@ -38,8 +38,10 @@ extern "C" { #include "BLI_compiler_attrs.h" +struct BlendThumbnail; struct ListBase; struct ID; +struct ImBuf; struct Main; struct Library; struct wmWindowManager; @@ -47,11 +49,14 @@ struct bContext; struct PointerRNA; struct PropertyRNA; +void *BKE_libblock_alloc_notest(short type); void *BKE_libblock_alloc(struct Main *bmain, short type, const char *name) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); +void BKE_libblock_init_empty(struct ID *id); void *BKE_libblock_copy_ex(struct Main *bmain, struct ID *id) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); void *BKE_libblock_copy_nolib(struct ID *id, const bool do_action) ATTR_NONNULL(); void *BKE_libblock_copy(struct ID *id) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); void BKE_libblock_copy_data(struct ID *id, const struct ID *id_from, const bool do_action); +void BKE_libblock_relink(struct ID *id); void BKE_id_lib_local_paths(struct Main *bmain, struct Library *lib, struct ID *id); void id_lib_extern(struct ID *id); @@ -87,6 +92,10 @@ void BKE_main_free(struct Main *mainvar); void BKE_main_lock(struct Main *bmain); void BKE_main_unlock(struct Main *bmain); +struct BlendThumbnail *BKE_main_thumbnail_from_imbuf(struct Main *bmain, struct ImBuf *img); +struct ImBuf *BKE_main_thumbnail_to_imbuf(struct Main *bmain, struct BlendThumbnail *data); +void BKE_main_thumbnail_create(struct Main *bmain); + void BKE_main_id_tag_idcode(struct Main *mainvar, const short type, const bool tag); void BKE_main_id_tag_listbase(struct ListBase *lb, const bool tag); void BKE_main_id_tag_all(struct Main *mainvar, const bool tag); diff --git a/source/blender/blenkernel/BKE_library_query.h b/source/blender/blenkernel/BKE_library_query.h index 50958f8ee80..194b6f0e6b3 100644 --- a/source/blender/blenkernel/BKE_library_query.h +++ b/source/blender/blenkernel/BKE_library_query.h @@ -38,6 +38,16 @@ enum { IDWALK_NOP = 0, IDWALK_NEVER_NULL = (1 << 0), IDWALK_NEVER_SELF = (1 << 1), + + /** + * Adjusts #ID.us reference-count. + * \note keep in sync with 'newlibadr_us' use in readfile.c + */ + IDWALK_USER = (1 << 8), + /** + * Ensure #ID.us is at least 1 on use. + */ + IDWALK_USER_ONE = (1 << 9), }; /* Call a callback for each ID link which the given ID uses. @@ -53,5 +63,6 @@ enum { /* Loop over all of the ID's this datablock links to. */ void BKE_library_foreach_ID_link(struct ID *id, LibraryIDLinkCallback callback, void *user_data, int flag); +void BKE_library_update_ID_link_user(struct ID *id_dst, struct ID *id_src, const int cd_flag); #endif /* __BKE_LIBRARY_QUERY_H__ */ diff --git a/source/blender/blenkernel/BKE_linestyle.h b/source/blender/blenkernel/BKE_linestyle.h index e77b4f5e8fe..e3eead4102c 100644 --- a/source/blender/blenkernel/BKE_linestyle.h +++ b/source/blender/blenkernel/BKE_linestyle.h @@ -49,6 +49,7 @@ struct Object; struct ColorBand; struct bContext; +void BKE_linestyle_init(struct FreestyleLineStyle *linestyle); FreestyleLineStyle *BKE_linestyle_new(struct Main *bmain, const char *name); void BKE_linestyle_free(FreestyleLineStyle *linestyle); FreestyleLineStyle *BKE_linestyle_copy(struct Main *bmain, FreestyleLineStyle *linestyle); diff --git a/source/blender/blenkernel/BKE_main.h b/source/blender/blenkernel/BKE_main.h index ec654ea4b71..6a00961fbb3 100644 --- a/source/blender/blenkernel/BKE_main.h +++ b/source/blender/blenkernel/BKE_main.h @@ -50,6 +50,13 @@ struct EvaluationContext; struct Library; struct MainLock; +/* Blender thumbnail, as written on file (width, height, and data as char RGBA). */ +/* We pack pixel data after that struct. */ +typedef struct BlendThumbnail { + int width, height; + char rect[0]; +} BlendThumbnail; + typedef struct Main { struct Main *next, *prev; char name[1024]; /* 1024 = FILE_MAX */ @@ -58,6 +65,8 @@ typedef struct Main { uint64_t build_commit_timestamp; /* commit's timestamp from buildinfo */ char build_hash[16]; /* hash from buildinfo */ short recovered; /* indicate the main->name (file) is the recovered one */ + + BlendThumbnail *blen_thumb; struct Library *curlib; ListBase scene; @@ -109,7 +118,10 @@ typedef struct Main { #define MAIN_VERSION_OLDER(main, ver, subver) \ ((main)->versionfile < (ver) || (main->versionfile == (ver) && (main)->subversionfile < (subver))) - +#define BLEN_THUMB_SIZE 128 + +#define BLEN_THUMB_MEMSIZE(_x, _y) (sizeof(BlendThumbnail) + (size_t)((_x) * (_y)) * sizeof(int)) + #ifdef __cplusplus } #endif diff --git a/source/blender/blenkernel/BKE_material.h b/source/blender/blenkernel/BKE_material.h index a3c61f44ff2..d32d679e7ed 100644 --- a/source/blender/blenkernel/BKE_material.h +++ b/source/blender/blenkernel/BKE_material.h @@ -49,7 +49,7 @@ void BKE_material_free(struct Material *sc); void BKE_material_free_ex(struct Material *ma, bool do_id_user); void test_object_materials(struct Main *bmain, struct ID *id); void BKE_material_resize_object(struct Object *ob, const short totcol, bool do_id_user); -void init_material(struct Material *ma); +void BKE_material_init(struct Material *ma); void BKE_material_remap_object(struct Object *ob, const unsigned int *remap); struct Material *BKE_material_add(struct Main *bmain, const char *name); struct Material *BKE_material_copy(struct Material *ma); diff --git a/source/blender/blenkernel/BKE_mball.h b/source/blender/blenkernel/BKE_mball.h index 62cd50099fd..0574b88bef3 100644 --- a/source/blender/blenkernel/BKE_mball.h +++ b/source/blender/blenkernel/BKE_mball.h @@ -40,6 +40,7 @@ struct MetaElem; void BKE_mball_unlink(struct MetaBall *mb); void BKE_mball_free(struct MetaBall *mb); +void BKE_mball_init(struct MetaBall *mb); struct MetaBall *BKE_mball_add(struct Main *bmain, const char *name); struct MetaBall *BKE_mball_copy(struct MetaBall *mb); diff --git a/source/blender/blenkernel/BKE_mesh.h b/source/blender/blenkernel/BKE_mesh.h index 41241988f2b..f35613f8bf7 100644 --- a/source/blender/blenkernel/BKE_mesh.h +++ b/source/blender/blenkernel/BKE_mesh.h @@ -82,6 +82,7 @@ int BKE_mesh_edge_other_vert(const struct MEdge *e, int v); void BKE_mesh_unlink(struct Mesh *me); void BKE_mesh_free(struct Mesh *me, int unlink); +void BKE_mesh_init(struct Mesh *me); struct Mesh *BKE_mesh_add(struct Main *bmain, const char *name); struct Mesh *BKE_mesh_copy_ex(struct Main *bmain, struct Mesh *me); struct Mesh *BKE_mesh_copy(struct Mesh *me); @@ -170,7 +171,7 @@ void BKE_mesh_calc_normals_mapping_ex( const struct MFace *mfaces, int numFaces, const int *origIndexFace, float (*r_faceNors)[3], const bool only_face_normals); void BKE_mesh_calc_normals_poly( - struct MVert *mverts, int numVerts, + struct MVert *mverts, float (*r_vertnors)[3], int numVerts, const struct MLoop *mloop, const struct MPoly *mpolys, int numLoops, int numPolys, float (*r_polyNors)[3], const bool only_face_normals); @@ -234,11 +235,11 @@ void BKE_mesh_normals_loop_split( void BKE_mesh_normals_loop_custom_set( const struct MVert *mverts, const int numVerts, struct MEdge *medges, const int numEdges, - struct MLoop *mloops, float (*custom_loopnors)[3], const int numLoops, + struct MLoop *mloops, float (*r_custom_loopnors)[3], const int numLoops, struct MPoly *mpolys, const float (*polynors)[3], const int numPolys, short (*r_clnors_data)[2]); void BKE_mesh_normals_loop_custom_from_vertices_set( - const struct MVert *mverts, float (*custom_vertnors)[3], const int numVerts, + const struct MVert *mverts, float (*r_custom_vertnors)[3], const int numVerts, struct MEdge *medges, const int numEdges, struct MLoop *mloops, const int numLoops, struct MPoly *mpolys, const float (*polynors)[3], const int numPolys, short (*r_clnors_data)[2]); diff --git a/source/blender/blenkernel/BKE_modifier.h b/source/blender/blenkernel/BKE_modifier.h index ded6e13e003..455912ab819 100644 --- a/source/blender/blenkernel/BKE_modifier.h +++ b/source/blender/blenkernel/BKE_modifier.h @@ -104,8 +104,9 @@ typedef enum { eModifierTypeFlag_UsesPreview = (1 << 9) } ModifierTypeFlag; -typedef void (*ObjectWalkFunc)(void *userData, struct Object *ob, struct Object **obpoin); -typedef void (*IDWalkFunc)(void *userData, struct Object *ob, struct ID **idpoin); +/* IMPORTANT! Keep ObjectWalkFunc and IDWalkFunc signatures compatible. */ +typedef void (*ObjectWalkFunc)(void *userData, struct Object *ob, struct Object **obpoin, int cd_flag); +typedef void (*IDWalkFunc)(void *userData, struct Object *ob, struct ID **idpoin, int cd_flag); typedef void (*TexWalkFunc)(void *userData, struct Object *ob, struct ModifierData *md, const char *propname); typedef enum ModifierApplyFlag { diff --git a/source/blender/blenkernel/BKE_movieclip.h b/source/blender/blenkernel/BKE_movieclip.h index 7d7675270de..afca326c727 100644 --- a/source/blender/blenkernel/BKE_movieclip.h +++ b/source/blender/blenkernel/BKE_movieclip.h @@ -43,6 +43,8 @@ void BKE_movieclip_free(struct MovieClip *clip); void BKE_movieclip_unlink(struct Main *bmain, struct MovieClip *clip); struct MovieClip *BKE_movieclip_file_add(struct Main *bmain, const char *name); +struct MovieClip *BKE_movieclip_file_add_exists_ex(struct Main *bmain, const char *name, bool *r_exists); +struct MovieClip *BKE_movieclip_file_add_exists(struct Main *bmain, const char *name); void BKE_movieclip_reload(struct MovieClip *clip); void BKE_movieclip_clear_cache(struct MovieClip *clip); void BKE_movieclip_clear_proxy_cache(struct MovieClip *clip); diff --git a/source/blender/blenkernel/BKE_node.h b/source/blender/blenkernel/BKE_node.h index b97bf203a7c..88e54d0ff2c 100644 --- a/source/blender/blenkernel/BKE_node.h +++ b/source/blender/blenkernel/BKE_node.h @@ -337,6 +337,7 @@ struct GHashIterator *ntreeTypeGetIterator(void); void ntreeSetTypes(const struct bContext *C, struct bNodeTree *ntree); +void ntreeInitDefault(struct bNodeTree *ntree); struct bNodeTree *ntreeAddTree(struct Main *bmain, const char *name, const char *idname); /* copy/free funcs, need to manage ID users */ diff --git a/source/blender/blenkernel/BKE_object.h b/source/blender/blenkernel/BKE_object.h index 9482ec778d3..45d14a35539 100644 --- a/source/blender/blenkernel/BKE_object.h +++ b/source/blender/blenkernel/BKE_object.h @@ -85,6 +85,7 @@ bool BKE_object_is_in_editmode(struct Object *ob); bool BKE_object_is_in_editmode_vgroup(struct Object *ob); bool BKE_object_is_in_wpaint_select_vert(struct Object *ob); +void BKE_object_init(struct Object *ob); struct Object *BKE_object_add_only_object( struct Main *bmain, int type, const char *name) @@ -142,6 +143,9 @@ bool BKE_boundbox_ray_hit_check( float *r_lambda); void BKE_boundbox_calc_center_aabb(const struct BoundBox *bb, float r_cent[3]); void BKE_boundbox_calc_size_aabb(const struct BoundBox *bb, float r_size[3]); +void BKE_boundbox_minmax(const struct BoundBox *bb, float obmat[4][4], float r_min[3], float r_max[3]); +struct BoundBox *BKE_boundbox_ensure_minimum_dimensions( + struct BoundBox *bb, struct BoundBox *bb_temp, const float epsilon); struct BoundBox *BKE_object_boundbox_get(struct Object *ob); void BKE_object_dimensions_get(struct Object *ob, float vec[3]); @@ -231,6 +235,7 @@ int BKE_object_is_modified(struct Scene *scene, struct Object *ob); int BKE_object_is_deform_modified(struct Scene *scene, struct Object *ob); void BKE_object_relink(struct Object *ob); +void BKE_object_data_relink(struct Object *ob); struct MovieClip *BKE_object_movieclip_get(struct Scene *scene, struct Object *ob, bool use_default); diff --git a/source/blender/blenkernel/BKE_paint.h b/source/blender/blenkernel/BKE_paint.h index c9192fddec6..bf1cfb263eb 100644 --- a/source/blender/blenkernel/BKE_paint.h +++ b/source/blender/blenkernel/BKE_paint.h @@ -66,13 +66,13 @@ extern const char PAINT_CURSOR_WEIGHT_PAINT[3]; extern const char PAINT_CURSOR_TEXTURE_PAINT[3]; typedef enum PaintMode { - PAINT_SCULPT = 0, - PAINT_VERTEX = 1, - PAINT_WEIGHT = 2, - PAINT_TEXTURE_PROJECTIVE = 3, - PAINT_TEXTURE_2D = 4, - PAINT_SCULPT_UV = 5, - PAINT_INVALID = 6 + ePaintSculpt = 0, + ePaintVertex = 1, + ePaintWeight = 2, + ePaintTextureProjective = 3, + ePaintTexture2D = 4, + ePaintSculptUV = 5, + ePaintInvalid = 6 } PaintMode; /* overlay invalidation */ @@ -108,12 +108,14 @@ void BKE_palette_clear(struct Palette *palette); struct PaintCurve *BKE_paint_curve_add(struct Main *bmain, const char *name); void BKE_paint_curve_free(struct PaintCurve *pc); -void BKE_paint_init(struct UnifiedPaintSettings *ups, struct Paint *p, const char col[3]); +void BKE_paint_init(struct Scene *sce, PaintMode mode, const char col[3]); void BKE_paint_free(struct Paint *p); void BKE_paint_copy(struct Paint *src, struct Paint *tar); void BKE_paint_cavity_curve_preset(struct Paint *p, int preset); +short BKE_paint_object_mode_from_paint_mode(PaintMode mode); +struct Paint *BKE_paint_get_active_from_paintmode(struct Scene *sce, PaintMode mode); struct Paint *BKE_paint_get_active(struct Scene *sce); struct Paint *BKE_paint_get_active_from_context(const struct bContext *C); PaintMode BKE_paintmode_get_active_from_context(const struct bContext *C); diff --git a/source/blender/blenkernel/BKE_particle.h b/source/blender/blenkernel/BKE_particle.h index 32325707c9a..00cc48cf713 100644 --- a/source/blender/blenkernel/BKE_particle.h +++ b/source/blender/blenkernel/BKE_particle.h @@ -378,6 +378,11 @@ void psys_get_birth_coords(struct ParticleSimulationData *sim, struct ParticleDa void particle_system_update(struct Scene *scene, struct Object *ob, struct ParticleSystem *psys); +/* Callback format for performing operations on ID-pointers for particle systems */ +typedef void (*ParticleSystemIDFunc)(struct ParticleSystem *psys, struct ID **idpoin, void *userdata, int cd_flag); + +void BKE_particlesystem_id_loop(struct ParticleSystem *psys, ParticleSystemIDFunc func, void *userdata); + /* ----------- functions needed only inside particlesystem ------------ */ /* particle.c */ void psys_disable_all(struct Object *ob); @@ -464,6 +469,7 @@ typedef struct ParticleRenderData { struct EvaluationContext; void BKE_particle_system_eval(struct EvaluationContext *eval_ctx, + struct Scene *scene, struct Object *ob, struct ParticleSystem *psys); diff --git a/source/blender/blenkernel/BKE_rigidbody.h b/source/blender/blenkernel/BKE_rigidbody.h index a30ce6cda79..272abc42899 100644 --- a/source/blender/blenkernel/BKE_rigidbody.h +++ b/source/blender/blenkernel/BKE_rigidbody.h @@ -53,6 +53,11 @@ struct RigidBodyOb *BKE_rigidbody_copy_object(struct Object *ob); struct RigidBodyCon *BKE_rigidbody_copy_constraint(struct Object *ob); void BKE_rigidbody_relink_constraint(struct RigidBodyCon *rbc); +/* Callback format for performing operations on ID-pointers for rigidbody world. */ +typedef void (*RigidbodyWorldIDFunc)(struct RigidBodyWorld *rbw, struct ID **idpoin, void *userdata, int cd_flag); + +void BKE_rigidbody_world_id_loop(struct RigidBodyWorld *rbw, RigidbodyWorldIDFunc func, void *userdata); + /* -------------- */ /* Setup */ diff --git a/source/blender/blenkernel/BKE_sca.h b/source/blender/blenkernel/BKE_sca.h index ebdd159b40c..fa448aa97b8 100644 --- a/source/blender/blenkernel/BKE_sca.h +++ b/source/blender/blenkernel/BKE_sca.h @@ -73,6 +73,16 @@ void sca_move_sensor(struct bSensor *sens_to_move, struct Object *ob, int move_u void sca_move_controller(struct bController *cont_to_move, struct Object *ob, int move_up); void sca_move_actuator(struct bActuator *act_to_move, struct Object *ob, int move_up); +/* Callback format for performing operations on ID-pointers for sensors/controllers/actuators. */ +typedef void (*SCASensorIDFunc)(struct bSensor *sensor, struct ID **idpoin, void *userdata, int cd_flag); +typedef void (*SCAControllerIDFunc)(struct bController *controller, struct ID **idpoin, void *userdata, int cd_flag); +typedef void (*SCAActuatorIDFunc)(struct bActuator *actuator, struct ID **idpoin, void *userdata, int cd_flag); + +void BKE_sca_sensors_id_loop(struct ListBase *senslist, SCASensorIDFunc func, void *userdata); +void BKE_sca_controllers_id_loop(struct ListBase *contlist, SCAControllerIDFunc func, void *userdata); +void BKE_sca_actuators_id_loop(struct ListBase *atclist, SCAActuatorIDFunc func, void *userdata); + + const char *sca_state_name_get(Object *ob, short bit); #endif diff --git a/source/blender/blenkernel/BKE_scene.h b/source/blender/blenkernel/BKE_scene.h index 027bdbbbe58..aa698317e33 100644 --- a/source/blender/blenkernel/BKE_scene.h +++ b/source/blender/blenkernel/BKE_scene.h @@ -67,6 +67,7 @@ void free_avicodecdata(struct AviCodecData *acd); void free_qtcodecdata(struct QuicktimeCodecData *acd); 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); /* base functions */ diff --git a/source/blender/blenkernel/BKE_sequencer.h b/source/blender/blenkernel/BKE_sequencer.h index f73548373ef..06f46131c68 100644 --- a/source/blender/blenkernel/BKE_sequencer.h +++ b/source/blender/blenkernel/BKE_sequencer.h @@ -35,6 +35,7 @@ struct EvaluationContext; struct StripColorBalance; struct Editing; struct GSet; +struct GPUOffScreen; struct ImBuf; struct Main; struct Mask; @@ -101,6 +102,10 @@ typedef struct SeqRenderData { bool skip_cache; bool is_proxy_render; size_t view_id; + + /* special case for OpenGL render */ + struct GPUOffScreen *gpu_offscreen; + int gpu_samples; } SeqRenderData; void BKE_sequencer_new_render_data( @@ -108,6 +113,8 @@ void BKE_sequencer_new_render_data( int rectx, int recty, int preview_render_size, SeqRenderData *r_context); +int BKE_sequencer_cmp_time_startdisp(const void *a, const void *b); + /* Wipe effect */ enum { DO_SINGLE_WIPE, @@ -406,7 +413,11 @@ struct Sequence *BKE_sequencer_add_sound_strip(struct bContext *C, ListBase *seq struct Sequence *BKE_sequencer_add_movie_strip(struct bContext *C, ListBase *seqbasep, struct SeqLoadInfo *seq_load); /* view3d draw callback, run when not in background view */ -typedef struct ImBuf *(*SequencerDrawView)(struct Scene *, struct Object *, int, int, unsigned int, int, bool, bool, bool, int, const char *, char[256]); +typedef struct ImBuf *(*SequencerDrawView)( + struct Scene *, struct Object *, int, int, + unsigned int, int, bool, bool, bool, + int, int, const char *, + struct GPUOffScreen *, char[256]); extern SequencerDrawView sequencer_view3d_cb; /* copy/paste */ diff --git a/source/blender/blenkernel/BKE_sound.h b/source/blender/blenkernel/BKE_sound.h index e68be701b61..67db2537c8f 100644 --- a/source/blender/blenkernel/BKE_sound.h +++ b/source/blender/blenkernel/BKE_sound.h @@ -61,7 +61,9 @@ void BKE_sound_exit(void); void BKE_sound_force_device(const char *device); -struct bSound *BKE_sound_new_file(struct Main *main, const char *filename); +struct bSound *BKE_sound_new_file(struct Main *main, const char *filepath); +struct bSound *BKE_sound_new_file_exists_ex(struct Main *bmain, const char *filepath, bool *r_exists); +struct bSound *BKE_sound_new_file_exists(struct Main *bmain, const char *filepath); // XXX unused currently #if 0 diff --git a/source/blender/blenkernel/BKE_speaker.h b/source/blender/blenkernel/BKE_speaker.h index 5d93b9844ab..5f30df1d6e3 100644 --- a/source/blender/blenkernel/BKE_speaker.h +++ b/source/blender/blenkernel/BKE_speaker.h @@ -29,7 +29,9 @@ */ struct Main; +struct Speaker; +void BKE_speaker_init(struct Speaker *spk); void *BKE_speaker_add(struct Main *bmain, const char *name); struct Speaker *BKE_speaker_copy(struct Speaker *spk); void BKE_speaker_make_local(struct Speaker *spk); diff --git a/source/blender/blenkernel/BKE_text.h b/source/blender/blenkernel/BKE_text.h index a5a59d14c92..50e4fa4c41d 100644 --- a/source/blender/blenkernel/BKE_text.h +++ b/source/blender/blenkernel/BKE_text.h @@ -44,6 +44,7 @@ struct TextLine; void BKE_text_free (struct Text *text); void txt_set_undostate (int u); int txt_get_undostate (void); +void BKE_text_init(struct Text *ta); struct Text *BKE_text_add (struct Main *bmain, const char *name); int txt_extended_ascii_as_utf8(char **str); bool BKE_text_reload(struct Text *text); diff --git a/source/blender/blenkernel/BKE_world.h b/source/blender/blenkernel/BKE_world.h index 7f4ba6c615e..8d7ab230919 100644 --- a/source/blender/blenkernel/BKE_world.h +++ b/source/blender/blenkernel/BKE_world.h @@ -38,6 +38,7 @@ struct World; void BKE_world_free(struct World *sc); void BKE_world_free_ex(struct World *sc, bool do_id_user); +void BKE_world_init(struct World *wrld); struct World *add_world(struct Main *bmian, const char *name); struct World *BKE_world_copy(struct World *wrld); struct World *localize_world(struct World *wrld); diff --git a/source/blender/blenkernel/intern/CCGSubSurf_opensubdiv.c b/source/blender/blenkernel/intern/CCGSubSurf_opensubdiv.c index 006cebf4573..9d5ef1079b8 100644 --- a/source/blender/blenkernel/intern/CCGSubSurf_opensubdiv.c +++ b/source/blender/blenkernel/intern/CCGSubSurf_opensubdiv.c @@ -314,9 +314,12 @@ int ccgSubSurf_getNumGLMeshBaseFaces(CCGSubSurf *ss) if (ss->osd_topology_refiner != NULL) { topology_refiner = ss->osd_topology_refiner; } - else { + else if (ss->osd_mesh != NULL) { topology_refiner = openSubdiv_getGLMeshTopologyRefiner(ss->osd_mesh); } + else { + return 0; + } return openSubdiv_topologyRefinerGetNumFaces(topology_refiner); } @@ -327,9 +330,12 @@ int ccgSubSurf_getNumGLMeshBaseFaceVerts(CCGSubSurf *ss, int face) if (ss->osd_topology_refiner != NULL) { topology_refiner = ss->osd_topology_refiner; } - else { + else if (ss->osd_mesh != NULL) { topology_refiner = openSubdiv_getGLMeshTopologyRefiner(ss->osd_mesh); } + else { + return 0; + } return openSubdiv_topologyRefinerGetNumFaceVerts(topology_refiner, face); } @@ -905,6 +911,10 @@ void ccgSubSurf_getMinMax(CCGSubSurf *ss, float r_min[3], float r_max[3]) { int i; BLI_assert(ss->skip_grids == true); + if (ss->osd_num_coarse_coords == 0) { + zero_v3(r_min); + zero_v3(r_max); + } for (i = 0; i < ss->osd_num_coarse_coords; i++) { /* Coarse coordinates has normals interleaved into the array. */ DO_MINMAX(ss->osd_coarse_coords[2 * i], r_min, r_max); diff --git a/source/blender/blenkernel/intern/DerivedMesh.c b/source/blender/blenkernel/intern/DerivedMesh.c index 6249e10d56f..4cf9885c716 100644 --- a/source/blender/blenkernel/intern/DerivedMesh.c +++ b/source/blender/blenkernel/intern/DerivedMesh.c @@ -328,21 +328,17 @@ void DM_init( * Utility function to initialize a DerivedMesh for the desired number * of vertices, edges and faces, with a layer setup copied from source */ -void DM_from_template( +void DM_from_template_ex( DerivedMesh *dm, DerivedMesh *source, DerivedMeshType type, int numVerts, int numEdges, int numTessFaces, - int numLoops, int numPolys) + int numLoops, int numPolys, + CustomDataMask mask) { - CustomData_copy(&source->vertData, &dm->vertData, CD_MASK_DERIVEDMESH, - CD_CALLOC, numVerts); - CustomData_copy(&source->edgeData, &dm->edgeData, CD_MASK_DERIVEDMESH, - CD_CALLOC, numEdges); - CustomData_copy(&source->faceData, &dm->faceData, CD_MASK_DERIVEDMESH, - CD_CALLOC, numTessFaces); - CustomData_copy(&source->loopData, &dm->loopData, CD_MASK_DERIVEDMESH, - CD_CALLOC, numLoops); - CustomData_copy(&source->polyData, &dm->polyData, CD_MASK_DERIVEDMESH, - CD_CALLOC, numPolys); + CustomData_copy(&source->vertData, &dm->vertData, mask, CD_CALLOC, numVerts); + CustomData_copy(&source->edgeData, &dm->edgeData, mask, CD_CALLOC, numEdges); + CustomData_copy(&source->faceData, &dm->faceData, mask, CD_CALLOC, numTessFaces); + CustomData_copy(&source->loopData, &dm->loopData, mask, CD_CALLOC, numLoops); + CustomData_copy(&source->polyData, &dm->polyData, mask, CD_CALLOC, numPolys); dm->cd_flag = source->cd_flag; @@ -358,6 +354,17 @@ void DM_from_template( dm->needsFree = 1; dm->dirty = 0; } +void DM_from_template( + DerivedMesh *dm, DerivedMesh *source, DerivedMeshType type, + int numVerts, int numEdges, int numTessFaces, + int numLoops, int numPolys) +{ + DM_from_template_ex( + dm, source, type, + numVerts, numEdges, numTessFaces, + numLoops, numPolys, + CD_MASK_DERIVEDMESH); +} int DM_release(DerivedMesh *dm) { @@ -593,8 +600,6 @@ void DM_generate_tangent_tessface_data(DerivedMesh *dm, bool generate) if (!polyindex) return; - CustomData_from_bmeshpoly(fdata, pdata, ldata, totface); - if (generate) { for (i = 0; i < ldata->totlayer; i++) { if (ldata->layers[i].type == CD_TANGENT) @@ -603,6 +608,8 @@ void DM_generate_tangent_tessface_data(DerivedMesh *dm, bool generate) CustomData_bmesh_update_active_layers(fdata, pdata, ldata); } + BLI_assert(CustomData_from_bmeshpoly_test(fdata, pdata, ldata, true)); + loopindex = MEM_mallocN(sizeof(*loopindex) * totface, __func__); for (mf_idx = 0, mf = mface; mf_idx < totface; mf_idx++, mf++) { @@ -1554,8 +1561,8 @@ void DM_update_weight_mcol( ml = mloop + mp->loopstart; for (j = 0; j < mp->totloop; j++, ml++, l_index++) { - copy_v4_v4_char((char *)&wtcol_l[l_index], - (char *)&wtcol_v[ml->v]); + copy_v4_v4_uchar(&wtcol_l[l_index][0], + &wtcol_v[ml->v][0]); } } MEM_freeN(wtcol_v); @@ -2266,12 +2273,9 @@ static void editbmesh_calc_modifiers( #if 0 /* XXX Will re-enable this when we have global mod stack options. */ const bool do_final_wmcol = (scene->toolsettings->weights_preview == WP_WPREVIEW_FINAL) && do_wmcol; #endif -#ifndef WITH_OPENSUBDIV const bool do_final_wmcol = false; const bool do_init_wmcol = ((((Mesh *)ob->data)->drawflag & ME_DRAWEIGHT) && !do_final_wmcol); -#else - const bool do_init_wmcol = false; -#endif + const bool do_init_statvis = ((((Mesh *)ob->data)->drawflag & ME_DRAW_STATVIS) && !do_init_wmcol); const bool do_mod_wmcol = do_init_wmcol; VirtualModifierData virtualModifierData; @@ -2539,7 +2543,7 @@ static void editbmesh_calc_modifiers( #ifdef WITH_OPENSUBDIV /* The idea is to skip CPU-side ORCO calculation when * we'll be using GPU backend of OpenSubdiv. This is so - * playback performance is kept as high as posssible. + * playback performance is kept as high as possible. */ static bool calc_modifiers_skip_orco(const Object *ob) { @@ -2622,13 +2626,13 @@ static CustomDataMask object_get_datamask(const Scene *scene, Object *ob, bool * { Object *actob = scene->basact ? scene->basact->object : NULL; CustomDataMask mask = ob->customdata_mask; - bool editing = BKE_paint_select_face_test(ob); if (r_need_mapping) { *r_need_mapping = false; } if (ob == actob) { + bool editing = BKE_paint_select_face_test(ob); /* weight paint and face select need original indices because of selection buffer drawing */ if (r_need_mapping) { @@ -3055,7 +3059,7 @@ static void GetNormal(const SMikkTSpaceContext *pContext, float r_no[3], const i } } else { - const short *no = pMesh->mvert[pMesh->mloop[lt->tri[0]].v].no; + const short *no = pMesh->mvert[pMesh->mloop[lt->tri[vert_index]].v].no; normal_short_to_float_v3(r_no, no); } } @@ -3449,7 +3453,7 @@ void DM_draw_attrib_vertex(DMVertexAttribs *attribs, int a, int index, int vert, if (attribs->mcol[b].array) { const MLoopCol *cp = &attribs->mcol[b].array[loop]; - copy_v4_v4_char((char *)col, &cp->r); + copy_v4_v4_uchar(col, &cp->r); } else { col[0] = 0; col[1] = 0; col[2] = 0; col[3] = 0; diff --git a/source/blender/blenkernel/intern/action.c b/source/blender/blenkernel/intern/action.c index 5b1a6ea7a51..b77ae45e94d 100644 --- a/source/blender/blenkernel/intern/action.c +++ b/source/blender/blenkernel/intern/action.c @@ -485,6 +485,9 @@ bPoseChannel *BKE_pose_channel_verify(bPose *pose, const char *name) chan = MEM_callocN(sizeof(bPoseChannel), "verifyPoseChannel"); BLI_strncpy(chan->name, name, sizeof(chan->name)); + + chan->custom_scale = 1.0f; + /* init vars to prevent math errors */ unit_qt(chan->quat); unit_axis_angle(chan->rotAxis, &chan->rotAngle); diff --git a/source/blender/blenkernel/intern/appdir.c b/source/blender/blenkernel/intern/appdir.c index ee6710e1130..639a502fb83 100644 --- a/source/blender/blenkernel/intern/appdir.c +++ b/source/blender/blenkernel/intern/appdir.c @@ -548,15 +548,7 @@ static void where_am_i(char *fullname, const size_t maxlen, const char *name) BLI_strncpy(fullname, name, maxlen); if (name[0] == '.') { - char wdir[FILE_MAX] = ""; - BLI_current_working_dir(wdir, sizeof(wdir)); /* backup cwd to restore after */ - - // not needed but avoids annoying /./ in name - if (name[1] == SEP) - BLI_join_dirfile(fullname, maxlen, wdir, name + 2); - else - BLI_join_dirfile(fullname, maxlen, wdir, name); - + BLI_path_cwd(fullname, maxlen); #ifdef _WIN32 BLI_path_program_extensions_add_win32(fullname, maxlen); #endif diff --git a/source/blender/blenkernel/intern/armature.c b/source/blender/blenkernel/intern/armature.c index 3643aa23998..6afe7f1abe9 100644 --- a/source/blender/blenkernel/intern/armature.c +++ b/source/blender/blenkernel/intern/armature.c @@ -1141,8 +1141,7 @@ void BKE_armature_loc_world_to_pose(Object *ob, const float inloc[3], float outl * Not exported, as it is only used in this file currently... */ static void get_offset_bone_mat(Bone *bone, float offs_bone[4][4]) { - if (!bone->parent) - return; + BLI_assert(bone->parent != NULL); /* Bone transform itself. */ copy_m4_m3(offs_bone, bone->bone_mat); @@ -1506,6 +1505,8 @@ void vec_roll_to_mat3_normalized(const float nor[3], const float roll, float mat float theta; float rMatrix[3][3], bMatrix[3][3]; + BLI_ASSERT_UNIT_V3(nor); + theta = 1.0f + nor[1]; /* With old algo, 1.0e-13f caused T23954 and T31333, 1.0e-6f caused T27675 and T30438, @@ -1566,16 +1567,15 @@ void vec_roll_to_mat3(const float vec[3], const float roll, float mat[3][3]) /* recursive part, calculates restposition of entire tree of children */ /* used by exiting editmode too */ -void BKE_armature_where_is_bone(Bone *bone, Bone *prevbone) +void BKE_armature_where_is_bone(Bone *bone, Bone *prevbone, const bool use_recursion) { float vec[3]; /* Bone Space */ sub_v3_v3v3(vec, bone->tail, bone->head); + bone->length = len_v3(vec); vec_roll_to_mat3(vec, bone->roll, bone->bone_mat); - bone->length = len_v3v3(bone->head, bone->tail); - /* this is called on old file reading too... */ if (bone->xwidth == 0.0f) { bone->xwidth = 0.1f; @@ -1597,9 +1597,11 @@ void BKE_armature_where_is_bone(Bone *bone, Bone *prevbone) } /* and the kiddies */ - prevbone = bone; - for (bone = bone->childbase.first; bone; bone = bone->next) { - BKE_armature_where_is_bone(bone, prevbone); + if (use_recursion) { + prevbone = bone; + for (bone = bone->childbase.first; bone; bone = bone->next) { + BKE_armature_where_is_bone(bone, prevbone, use_recursion); + } } } @@ -1611,7 +1613,7 @@ void BKE_armature_where_is(bArmature *arm) /* hierarchical from root to children */ for (bone = arm->bonebase.first; bone; bone = bone->next) { - BKE_armature_where_is_bone(bone, NULL); + BKE_armature_where_is_bone(bone, NULL, true); } } @@ -2207,6 +2209,46 @@ BoundBox *BKE_armature_boundbox_get(Object *ob) return ob->bb; } +bool BKE_pose_minmax(Object *ob, float r_min[3], float r_max[3], bool use_hidden, bool use_select) +{ + bool changed = false; + + if (ob->pose) { + bArmature *arm = ob->data; + bPoseChannel *pchan; + + for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) { + /* XXX pchan->bone may be NULL for duplicated bones, see duplicateEditBoneObjects() comment + * (editarmature.c:2592)... Skip in this case too! */ + if (pchan->bone && + (!((use_hidden == false) && (PBONE_VISIBLE(arm, pchan->bone) == false)) && + !((use_select == true) && ((pchan->bone->flag & BONE_SELECTED) == 0)))) + { + bPoseChannel *pchan_tx = (pchan->custom && pchan->custom_tx) ? pchan->custom_tx : pchan; + BoundBox *bb_custom = ((pchan->custom) && !(arm->flag & ARM_NO_CUSTOM)) ? + BKE_object_boundbox_get(pchan->custom) : NULL; + if (bb_custom) { + float mat[4][4], smat[4][4]; + scale_m4_fl(smat, PCHAN_CUSTOM_DRAW_SIZE(pchan)); + mul_m4_series(mat, ob->obmat, pchan_tx->pose_mat, smat); + BKE_boundbox_minmax(bb_custom, mat, r_min, r_max); + } + else { + float vec[3]; + mul_v3_m4v3(vec, ob->obmat, pchan_tx->pose_head); + minmax_v3v3_v3(r_min, r_max, vec); + mul_v3_m4v3(vec, ob->obmat, pchan_tx->pose_tail); + minmax_v3v3_v3(r_min, r_max, vec); + } + + changed = true; + } + } + } + + return changed; +} + /************** Graph evaluation ********************/ bPoseChannel *BKE_armature_ik_solver_find_root( diff --git a/source/blender/blenkernel/intern/blender.c b/source/blender/blenkernel/intern/blender.c index 0923ac7e743..f1300697b85 100644 --- a/source/blender/blenkernel/intern/blender.c +++ b/source/blender/blenkernel/intern/blender.c @@ -417,6 +417,7 @@ static void setup_app_data(bContext *C, BlendFileData *bfd, const char *filepath BKE_scene_set_background(G.main, curscene); if (mode != LOAD_UNDO) { + RE_FreeAllPersistentData(); IMB_colormanagement_check_file_config(G.main); } @@ -1068,11 +1069,11 @@ int BKE_copybuffer_paste(bContext *C, const char *libname, ReportList *reports) BKE_main_id_flag_all(bmain, LIB_PRE_EXISTING, true); /* here appending/linking starts */ - mainl = BLO_library_append_begin(bmain, &bh, libname); + mainl = BLO_library_link_begin(bmain, &bh, libname); - BLO_library_append_all(mainl, bh); + BLO_library_link_all(mainl, bh); - BLO_library_append_end(C, mainl, &bh, 0, 0); + BLO_library_link_end(mainl, &bh, 0, scene, CTX_wm_view3d(C)); /* mark all library linked objects to be updated */ BKE_main_lib_objects_recalc_all(bmain); diff --git a/source/blender/blenkernel/intern/boids.c b/source/blender/blenkernel/intern/boids.c index 489e26c5cbe..64b9bf48c98 100644 --- a/source/blender/blenkernel/intern/boids.c +++ b/source/blender/blenkernel/intern/boids.c @@ -80,6 +80,9 @@ static int rule_goal_avoid(BoidRule *rule, BoidBrainData *bbd, BoidValues *val, float priority = 0.0f, len = 0.0f; int ret = 0; + int p = 0; + efd.index = cur_efd.index = &p; + pd_point_from_particle(bbd->sim, pa, &pa->state, &epoint); /* first find out goal/predator with highest priority */ @@ -1006,9 +1009,11 @@ void boid_brain(BoidBrainData *bbd, int p, ParticleData *pa) case eBoidRulesetType_Random: { /* use random rule for each particle (always same for same particle though) */ - rule = BLI_findlink(&state->rules, rand % BLI_listbase_count(&state->rules)); - - apply_boid_rule(bbd, rule, &val, pa, -1.0); + const int n = BLI_listbase_count(&state->rules); + if (n) { + rule = BLI_findlink(&state->rules, rand % n); + apply_boid_rule(bbd, rule, &val, pa, -1.0); + } break; } case eBoidRulesetType_Average: diff --git a/source/blender/blenkernel/intern/brush.c b/source/blender/blenkernel/intern/brush.c index c7bb6d4f5ce..c2a66adbf92 100644 --- a/source/blender/blenkernel/intern/brush.c +++ b/source/blender/blenkernel/intern/brush.c @@ -131,11 +131,9 @@ static void brush_defaults(Brush *brush) /* Datablock add/copy/free/make_local */ -Brush *BKE_brush_add(Main *bmain, const char *name) +void BKE_brush_init(Brush *brush) { - Brush *brush; - - brush = BKE_libblock_alloc(bmain, ID_BR, name); + BLI_assert(MEMCMP_STRUCT_OFS_IS_ZERO(brush, id)); /* enable fake user by default */ brush->id.flag |= LIB_FAKEUSER; @@ -146,10 +144,32 @@ Brush *BKE_brush_add(Main *bmain, const char *name) /* the default alpha falloff curve */ BKE_brush_curve_preset(brush, CURVE_PRESET_SMOOTH); +} + +Brush *BKE_brush_add(Main *bmain, const char *name, short ob_mode) +{ + Brush *brush; + + brush = BKE_libblock_alloc(bmain, ID_BR, name); + + BKE_brush_init(brush); + + brush->ob_mode = ob_mode; return brush; } +struct Brush *BKE_brush_first_search(struct Main *bmain, short ob_mode) +{ + Brush *brush; + + for (brush = bmain->brush.first; brush; brush = brush->id.next) { + if (brush->ob_mode & ob_mode) + return brush; + } + return NULL; +} + Brush *BKE_brush_copy(Brush *brush) { Brush *brushn; diff --git a/source/blender/blenkernel/intern/bvhutils.c b/source/blender/blenkernel/intern/bvhutils.c index fa2fcd97ec3..9004985aebd 100644 --- a/source/blender/blenkernel/intern/bvhutils.c +++ b/source/blender/blenkernel/intern/bvhutils.c @@ -538,7 +538,7 @@ BVHTree *bvhtree_from_mesh_edges(BVHTreeFromMesh *data, DerivedMesh *dm, float e tree = BLI_bvhtree_new(numEdges, epsilon, tree_type, axis); if (tree != NULL) { for (i = 0; i < numEdges; i++) { - float co[4][3]; + float co[2][3]; copy_v3_v3(co[0], vert[edge[i].v1].co); copy_v3_v3(co[1], vert[edge[i].v2].co); @@ -597,7 +597,8 @@ BVHTree *bvhtree_from_mesh_edges(BVHTreeFromMesh *data, DerivedMesh *dm, float e static BVHTree *bvhtree_from_mesh_faces_create_tree( float epsilon, int tree_type, int axis, - BMEditMesh *em, MVert *vert, MFace *face, const int numFaces, + BMEditMesh *em, const bool em_all, + MVert *vert, MFace *face, const int numFaces, BLI_bitmap *mask, int numFaces_active) { BVHTree *tree = NULL; @@ -646,7 +647,10 @@ static BVHTree *bvhtree_from_mesh_faces_create_tree( insert = insert_prev; } else if (insert) { - if (BM_elem_flag_test(f, BM_ELEM_SELECT) || BM_elem_flag_test(f, BM_ELEM_HIDDEN)) { + if (em_all) { + /* pass */ + } + else if (BM_elem_flag_test(f, BM_ELEM_SELECT) || BM_elem_flag_test(f, BM_ELEM_HIDDEN)) { /* Don't insert triangles tessellated from faces that are hidden or selected */ insert = false; } @@ -746,7 +750,9 @@ static void bvhtree_from_mesh_faces_setup_data( BVHTree *bvhtree_from_mesh_faces(BVHTreeFromMesh *data, DerivedMesh *dm, float epsilon, int tree_type, int axis) { BMEditMesh *em = data->em_evil; - const int bvhcache_type = em ? BVHTREE_FROM_FACES_EDITMESH : BVHTREE_FROM_FACES; + const int bvhcache_type = em ? + (data->em_evil_all ? BVHTREE_FROM_FACES_EDITMESH_ALL : BVHTREE_FROM_FACES_EDITMESH_SNAP) : + BVHTREE_FROM_FACES; BVHTree *tree; MVert *vert = NULL; MFace *face = NULL; @@ -781,7 +787,10 @@ BVHTree *bvhtree_from_mesh_faces(BVHTreeFromMesh *data, DerivedMesh *dm, float e BLI_assert(!(numFaces == 0 && dm->getNumPolys(dm) != 0)); } - tree = bvhtree_from_mesh_faces_create_tree(epsilon, tree_type, axis, em, vert, face, numFaces, NULL, -1); + tree = bvhtree_from_mesh_faces_create_tree( + epsilon, tree_type, axis, + em, (bvhcache_type == BVHTREE_FROM_FACES_EDITMESH_ALL), + vert, face, numFaces, NULL, -1); if (tree) { /* Save on cache for later use */ /* printf("BVHTree built and saved on cache\n"); */ @@ -813,7 +822,9 @@ BVHTree *bvhtree_from_mesh_faces_ex( BLI_bitmap *mask, int numFaces_active, float epsilon, int tree_type, int axis) { BVHTree *tree = bvhtree_from_mesh_faces_create_tree( - epsilon, tree_type, axis, NULL, vert, face, numFaces, + epsilon, tree_type, axis, + NULL, false, + vert, face, numFaces, mask, numFaces_active); /* Setup BVHTreeFromMesh */ @@ -832,7 +843,8 @@ BVHTree *bvhtree_from_mesh_faces_ex( static BVHTree *bvhtree_from_mesh_looptri_create_tree( float epsilon, int tree_type, int axis, - BMEditMesh *em, const MVert *vert, const MLoop *mloop, const MLoopTri *looptri, const int looptri_num, + BMEditMesh *em, const bool em_all, + const MVert *vert, const MLoop *mloop, const MLoopTri *looptri, const int looptri_num, BLI_bitmap *mask, int looptri_num_active) { BVHTree *tree = NULL; @@ -881,7 +893,10 @@ static BVHTree *bvhtree_from_mesh_looptri_create_tree( insert = insert_prev; } else if (insert) { - if (BM_elem_flag_test(f, BM_ELEM_SELECT) || BM_elem_flag_test(f, BM_ELEM_HIDDEN)) { + if (em_all) { + /* pass */ + } + else if (BM_elem_flag_test(f, BM_ELEM_SELECT) || BM_elem_flag_test(f, BM_ELEM_HIDDEN)) { /* Don't insert triangles tessellated from faces that are hidden or selected */ insert = false; } @@ -916,7 +931,7 @@ static BVHTree *bvhtree_from_mesh_looptri_create_tree( else { if (vert && looptri) { for (i = 0; i < looptri_num; i++) { - float co[4][3]; + float co[3][3]; if (mask && !BLI_BITMAP_TEST_BOOL(mask, i)) { continue; } @@ -972,6 +987,9 @@ static void bvhtree_from_mesh_looptri_setup_data( if (vert_allocated) { MEM_freeN((void *)vert); } + if (loop_allocated) { + MEM_freeN((void *)mloop); + } if (looptri_allocated) { MEM_freeN((void *)looptri); } @@ -986,7 +1004,9 @@ static void bvhtree_from_mesh_looptri_setup_data( BVHTree *bvhtree_from_mesh_looptri(BVHTreeFromMesh *data, DerivedMesh *dm, float epsilon, int tree_type, int axis) { BMEditMesh *em = data->em_evil; - const int bvhcache_type = em ? BVHTREE_FROM_FACES_EDITMESH : BVHTREE_FROM_LOOPTRI; + const int bvhcache_type = em ? + (data->em_evil_all ? BVHTREE_FROM_FACES_EDITMESH_ALL : BVHTREE_FROM_FACES_EDITMESH_SNAP) : + BVHTREE_FROM_LOOPTRI; BVHTree *tree; MVert *mvert = NULL; MLoop *mloop = NULL; @@ -1041,7 +1061,8 @@ BVHTree *bvhtree_from_mesh_looptri(BVHTreeFromMesh *data, DerivedMesh *dm, float } tree = bvhtree_from_mesh_looptri_create_tree( - epsilon, tree_type, axis, em, + epsilon, tree_type, axis, + em, (bvhcache_type == BVHTREE_FROM_FACES_EDITMESH_ALL), mvert, mloop, looptri, looptri_num, NULL, -1); if (tree) { /* Save on cache for later use */ @@ -1074,7 +1095,9 @@ BVHTree *bvhtree_from_mesh_looptri_ex( float epsilon, int tree_type, int axis) { BVHTree *tree = bvhtree_from_mesh_looptri_create_tree( - epsilon, tree_type, axis, NULL, vert, mloop, looptri, looptri_num, + epsilon, tree_type, axis, + NULL, false, + vert, mloop, looptri, looptri_num, mask, looptri_num_active); /* Setup BVHTreeFromMesh */ diff --git a/source/blender/blenkernel/intern/camera.c b/source/blender/blenkernel/intern/camera.c index af3608901f8..46b74c58965 100644 --- a/source/blender/blenkernel/intern/camera.c +++ b/source/blender/blenkernel/intern/camera.c @@ -57,11 +57,9 @@ /****************************** Camera Datablock *****************************/ -void *BKE_camera_add(Main *bmain, const char *name) +void BKE_camera_init(Camera *cam) { - Camera *cam; - - cam = BKE_libblock_alloc(bmain, ID_CA, name); + BLI_assert(MEMCMP_STRUCT_OFS_IS_ZERO(cam, id)); cam->lens = 35.0f; cam->sensor_x = DEFAULT_SENSOR_WIDTH; @@ -78,6 +76,15 @@ void *BKE_camera_add(Main *bmain, const char *name) /* stereoscopy 3d */ cam->stereo.interocular_distance = 0.065f; cam->stereo.convergence_distance = 30.f * 0.065f; +} + +void *BKE_camera_add(Main *bmain, const char *name) +{ + Camera *cam; + + cam = BKE_libblock_alloc(bmain, ID_CA, name); + + BKE_camera_init(cam); return cam; } @@ -169,15 +176,15 @@ float BKE_camera_object_dof_distance(Object *ob) if (ob->type != OB_CAMERA) return 0.0f; if (cam->dof_ob) { - /* too simple, better to return the distance on the view axis only - * return len_v3v3(ob->obmat[3], cam->dof_ob->obmat[3]); */ - float mat[4][4], imat[4][4], obmat[4][4]; - - copy_m4_m4(obmat, ob->obmat); - normalize_m4(obmat); - invert_m4_m4(imat, obmat); - mul_m4_m4m4(mat, imat, cam->dof_ob->obmat); - return fabsf(mat[3][2]); +#if 0 + /* too simple, better to return the distance on the view axis only */ + return len_v3v3(ob->obmat[3], cam->dof_ob->obmat[3]); +#else + float view_dir[3], dof_dir[3]; + normalize_v3_v3(view_dir, ob->obmat[2]); + sub_v3_v3v3(dof_dir, ob->obmat[3], cam->dof_ob->obmat[3]); + return fabsf(dot_v3v3(view_dir, dof_dir)); +#endif } return cam->YF_dofdist; } @@ -442,8 +449,8 @@ void BKE_camera_view_frame_ex( *r_drawsize = 1.0f; depth = -(camera->clipsta + 0.1f) * scale[2]; fac = depth / (camera->lens / (-half_sensor)); - scale_x = 1.0f; - scale_y = 1.0f; + scale_x = scale[0] / scale[2]; + scale_y = scale[1] / scale[2]; } else { /* fixed size, variable depth (stays a reasonable size in the 3D view) */ @@ -565,7 +572,7 @@ static void camera_frame_fit_data_init( static bool camera_frame_fit_calc_from_data( CameraParams *params, CameraViewFrameData *data, float r_co[3], float *r_scale) { - float plane_tx[CAMERA_VIEWFRAME_NUM_PLANES][3]; + float plane_tx[CAMERA_VIEWFRAME_NUM_PLANES][4]; unsigned int i; if (data->tot <= 1) { @@ -609,15 +616,13 @@ static bool camera_frame_fit_calc_from_data( /* apply the dist-from-plane's to the transformed plane points */ for (i = 0; i < CAMERA_VIEWFRAME_NUM_PLANES; i++) { - mul_v3_v3fl(plane_tx[i], data->normal_tx[i], sqrtf_signed(data->dist_vals_sq[i])); + float co[3]; + mul_v3_v3fl(co, data->normal_tx[i], sqrtf_signed(data->dist_vals_sq[i])); + plane_from_point_normal_v3(plane_tx[i], co, data->normal_tx[i]); } - if ((!isect_plane_plane_v3(plane_isect_1, plane_isect_1_no, - plane_tx[0], data->normal_tx[0], - plane_tx[2], data->normal_tx[2])) || - (!isect_plane_plane_v3(plane_isect_2, plane_isect_2_no, - plane_tx[1], data->normal_tx[1], - plane_tx[3], data->normal_tx[3]))) + if ((!isect_plane_plane_v3(plane_tx[0], plane_tx[2], plane_isect_1, plane_isect_1_no)) || + (!isect_plane_plane_v3(plane_tx[1], plane_tx[3], plane_isect_2, plane_isect_2_no))) { return false; } @@ -960,11 +965,6 @@ void BKE_camera_to_gpu_dof(struct Object *camera, struct GPUFXSettings *r_fx_set r_fx_settings->dof = &cam->gpu_dof; r_fx_settings->dof->focal_length = cam->lens; r_fx_settings->dof->sensor = BKE_camera_sensor_size(cam->sensor_fit, cam->sensor_x, cam->sensor_y); - if (cam->dof_ob) { - r_fx_settings->dof->focus_distance = len_v3v3(cam->dof_ob->obmat[3], camera->obmat[3]); - } - else { - r_fx_settings->dof->focus_distance = cam->YF_dofdist; - } + r_fx_settings->dof->focus_distance = BKE_camera_object_dof_distance(camera); } } diff --git a/source/blender/blenkernel/intern/cdderivedmesh.c b/source/blender/blenkernel/intern/cdderivedmesh.c index c3168c0d6af..3b86c42d8c9 100644 --- a/source/blender/blenkernel/intern/cdderivedmesh.c +++ b/source/blender/blenkernel/intern/cdderivedmesh.c @@ -867,6 +867,7 @@ static void cdDM_drawMappedFacesGLSL( const float (*nors)[3] = dm->getPolyDataArray(dm, CD_NORMAL); const float (*lnors)[3] = dm->getLoopDataArray(dm, CD_NORMAL); const int totpoly = dm->getNumPolys(dm); + const short dm_totmat = dm->totmat; int a, b, matnr, new_matnr; bool do_draw; int orig; @@ -966,7 +967,7 @@ static void cdDM_drawMappedFacesGLSL( int *mat_orig_to_new; int tot_active_mat; GPUBuffer *buffer = NULL; - char *varray; + unsigned char *varray; size_t max_element_size = 0; int tot_loops = 0; @@ -1047,8 +1048,9 @@ static void cdDM_drawMappedFacesGLSL( } for (a = 0; a < totpoly; a++, mpoly++) { + const short mat_nr = ME_MAT_NR_TEST(mpoly->mat_nr, dm_totmat); int j; - int i = mat_orig_to_new[mpoly->mat_nr]; + int i = mat_orig_to_new[mat_nr]; offset = tot_loops * max_element_size; if (matconv[i].numdata != 0) { @@ -1070,17 +1072,15 @@ static void cdDM_drawMappedFacesGLSL( if (matconv[i].attribs.mcol[b].array) { const MLoopCol *mloopcol = matconv[i].attribs.mcol[b].array; for (j = 0; j < mpoly->totloop; j++) - copy_v4_v4_char((char *)&varray[offset + j * max_element_size], &mloopcol[mpoly->loopstart + j].r); + copy_v4_v4_uchar(&varray[offset + j * max_element_size], &mloopcol[mpoly->loopstart + j].r); offset += sizeof(unsigned char) * 4; } } if (matconv[i].attribs.tottang && matconv[i].attribs.tang.array) { - if (matconv[i].attribs.tface[b].array) { - const float (*looptang)[4] = (const float (*)[4])matconv[i].attribs.tang.array; - for (j = 0; j < mpoly->totloop; j++) - copy_v4_v4((float *)&varray[offset + j * max_element_size], looptang[mpoly->loopstart + j]); - offset += sizeof(float) * 4; - } + const float (*looptang)[4] = (const float (*)[4])matconv[i].attribs.tang.array; + for (j = 0; j < mpoly->totloop; j++) + copy_v4_v4((float *)&varray[offset + j * max_element_size], looptang[mpoly->loopstart + j]); + offset += sizeof(float) * 4; } } @@ -1258,14 +1258,15 @@ static void cdDM_buffer_copy_triangles( GPUBufferMaterial *gpumat, *gpumaterials = dm->drawObject->materials; int i, j, start; - const int totmat = dm->drawObject->totmaterial; + const int gpu_totmat = dm->drawObject->totmaterial; + const short dm_totmat = dm->totmat; const MPoly *mpoly = dm->getPolyArray(dm); const MLoopTri *lt = dm->getLoopTriArray(dm); const int totpoly = dm->getNumPolys(dm); - FaceCount *fc = MEM_mallocN(sizeof(*fc) * totmat, "gpumaterial.facecount"); + FaceCount *fc = MEM_mallocN(sizeof(*fc) * gpu_totmat, "gpumaterial.facecount"); - for (i = 0; i < totmat; i++) { + for (i = 0; i < gpu_totmat; i++) { fc[i].i_visible = 0; fc[i].i_tri_visible = 0; fc[i].i_hidden = gpumaterials[i].totpolys - 1; @@ -1273,8 +1274,9 @@ static void cdDM_buffer_copy_triangles( } for (i = 0; i < totpoly; i++) { + const short mat_nr = ME_MAT_NR_TEST(mpoly[i].mat_nr, dm_totmat); int tottri = ME_POLY_TRI_TOT(&mpoly[i]); - int mati = mat_orig_to_new[mpoly[i].mat_nr]; + int mati = mat_orig_to_new[mat_nr]; gpumat = gpumaterials + mati; if (mpoly[i].flag & ME_HIDE) { @@ -1302,7 +1304,7 @@ static void cdDM_buffer_copy_triangles( } /* set the visible polygons */ - for (i = 0; i < totmat; i++) { + for (i = 0; i < gpu_totmat; i++) { gpumaterials[i].totvisiblepolys = fc[i].i_visible; } @@ -1480,7 +1482,7 @@ static void cdDM_buffer_copy_mcol( for (i = 0; i < totpoly; i++, mpoly++) { for (j = 0; j < mpoly->totloop; j++) { - copy_v3_v3_char((char *)&varray[start], &mloopcol[mpoly->loopstart + j].r); + copy_v3_v3_uchar(&varray[start], &mloopcol[mpoly->loopstart + j].r); start += 3; } } @@ -1695,12 +1697,12 @@ static GPUDrawObject *cdDM_GPUobject_new(DerivedMesh *dm) GPUDrawObject *gdo; const MPoly *mpoly; const MLoop *mloop; - int totmat = dm->totmat; + const short dm_totmat = dm->totmat; GPUBufferMaterial *mat_info; int i, totloops, totpolys; /* object contains at least one material (default included) so zero means uninitialized dm */ - BLI_assert(totmat != 0); + BLI_assert(dm_totmat != 0); mpoly = dm->getPolyArray(dm); mloop = dm->getLoopArray(dm); @@ -1710,10 +1712,10 @@ static GPUDrawObject *cdDM_GPUobject_new(DerivedMesh *dm) /* get the number of points used by each material, treating * each quad as two triangles */ - mat_info = MEM_callocN(sizeof(*mat_info) * totmat, "GPU_drawobject_new.mat_orig_to_new"); + mat_info = MEM_callocN(sizeof(*mat_info) * dm_totmat, "GPU_drawobject_new.mat_orig_to_new"); for (i = 0; i < totpolys; i++) { - const int mat_nr = mpoly[i].mat_nr; + const short mat_nr = ME_MAT_NR_TEST(mpoly[i].mat_nr, dm_totmat); mat_info[mat_nr].totpolys++; mat_info[mat_nr].totelements += 3 * ME_POLY_TRI_TOT(&mpoly[i]); mat_info[mat_nr].totloops += mpoly[i].totloop; @@ -1723,7 +1725,7 @@ static GPUDrawObject *cdDM_GPUobject_new(DerivedMesh *dm) gdo->totvert = dm->getNumVerts(dm); gdo->totedge = dm->getNumEdges(dm); - GPU_buffer_material_finalize(gdo, mat_info, totmat); + GPU_buffer_material_finalize(gdo, mat_info, dm_totmat); gdo->tot_loop_verts = totloops; @@ -2419,10 +2421,11 @@ DerivedMesh *CDDM_copy_from_tessface(DerivedMesh *source) /* note, the CD_ORIGINDEX layers are all 0, so if there is a direct * relationship between mesh data this needs to be set by the caller. */ -DerivedMesh *CDDM_from_template( +DerivedMesh *CDDM_from_template_ex( DerivedMesh *source, int numVerts, int numEdges, int numTessFaces, - int numLoops, int numPolys) + int numLoops, int numPolys, + CustomDataMask mask) { CDDerivedMesh *cddm = cdDM_create("CDDM_from_template dest"); DerivedMesh *dm = &cddm->dm; @@ -2434,7 +2437,11 @@ DerivedMesh *CDDM_from_template( source->getPolyDataArray(source, CD_ORIGINDEX); /* this does a copy of all non mvert/medge/mface layers */ - DM_from_template(dm, source, DM_TYPE_CDDM, numVerts, numEdges, numTessFaces, numLoops, numPolys); + DM_from_template_ex( + dm, source, DM_TYPE_CDDM, + numVerts, numEdges, numTessFaces, + numLoops, numPolys, + mask); /* now add mvert/medge/mface layers */ CustomData_add_layer(&dm->vertData, CD_MVERT, CD_CALLOC, NULL, numVerts); @@ -2458,6 +2465,16 @@ DerivedMesh *CDDM_from_template( return dm; } +DerivedMesh *CDDM_from_template( + DerivedMesh *source, + int numVerts, int numEdges, int numTessFaces, + int numLoops, int numPolys) +{ + return CDDM_from_template_ex( + source, numVerts, numEdges, numTessFaces, + numLoops, numPolys, + CD_MASK_DERIVEDMESH); +} void CDDM_apply_vert_coords(DerivedMesh *dm, float (*vertCoords)[3]) { @@ -2530,7 +2547,7 @@ void CDDM_calc_normals_mapping_ex(DerivedMesh *dm, const bool only_face_normals) /* calculate face normals */ BKE_mesh_calc_normals_poly( - cddm->mvert, dm->numVertData, CDDM_get_loops(dm), CDDM_get_polys(dm), + cddm->mvert, NULL, dm->numVertData, CDDM_get_loops(dm), CDDM_get_polys(dm), dm->numLoopData, dm->numPolyData, face_nors, only_face_normals); @@ -2580,7 +2597,7 @@ void CDDM_calc_normals(DerivedMesh *dm) /* we don't want to overwrite any referenced layers */ cddm->mvert = CustomData_duplicate_referenced_layer(&dm->vertData, CD_MVERT, dm->numVertData); - BKE_mesh_calc_normals_poly(cddm->mvert, dm->numVertData, CDDM_get_loops(dm), CDDM_get_polys(dm), + BKE_mesh_calc_normals_poly(cddm->mvert, NULL, dm->numVertData, CDDM_get_loops(dm), CDDM_get_polys(dm), dm->numLoopData, dm->numPolyData, NULL, false); cddm->dm.dirty &= ~DM_DIRTY_NORMALS; @@ -2629,7 +2646,7 @@ void CDDM_calc_loop_normals_spacearr( if (!pnors) { pnors = CustomData_add_layer(pdata, CD_NORMAL, CD_CALLOC, NULL, numPolys); } - BKE_mesh_calc_normals_poly(mverts, numVerts, mloops, mpolys, numLoops, numPolys, pnors, + BKE_mesh_calc_normals_poly(mverts, NULL, numVerts, mloops, mpolys, numLoops, numPolys, pnors, (dm->dirty & DM_DIRTY_NORMALS) ? false : true); dm->dirty &= ~DM_DIRTY_NORMALS; diff --git a/source/blender/blenkernel/intern/colortools.c b/source/blender/blenkernel/intern/colortools.c index aad6681fa2a..7a3cc118eb5 100644 --- a/source/blender/blenkernel/intern/colortools.c +++ b/source/blender/blenkernel/intern/colortools.c @@ -725,6 +725,16 @@ void curvemapping_changed(CurveMapping *cumap, const bool rem_doubles) cmp[a].y -= dy; } } + + /* ensure zoom-level respects clipping */ + if (BLI_rctf_size_x(&cumap->curr) > BLI_rctf_size_x(&cumap->clipr)) { + cumap->curr.xmin = cumap->clipr.xmin; + cumap->curr.xmax = cumap->clipr.xmax; + } + if (BLI_rctf_size_y(&cumap->curr) > BLI_rctf_size_y(&cumap->clipr)) { + cumap->curr.ymin = cumap->clipr.ymin; + cumap->curr.ymax = cumap->clipr.ymax; + } } @@ -975,7 +985,6 @@ void BKE_histogram_update_sample_line(Histogram *hist, ImBuf *ibuf, const ColorM { int i, x, y; const float *fp; - float rgb[3]; unsigned char *cp; int x1 = 0.5f + hist->co[0][0] * ibuf->x; @@ -1004,16 +1013,36 @@ void BKE_histogram_update_sample_line(Histogram *hist, ImBuf *ibuf, const ColorM } else { if (ibuf->rect_float) { + float rgba[4]; fp = (ibuf->rect_float + (ibuf->channels) * (y * ibuf->x + x)); - copy_v3_v3(rgb, fp); - IMB_colormanagement_processor_apply_v3(cm_processor, rgb); + switch (ibuf->channels) { + case 4: + copy_v4_v4(rgba, fp); + IMB_colormanagement_processor_apply_v4(cm_processor, rgba); + break; + case 3: + copy_v3_v3(rgba, fp); + IMB_colormanagement_processor_apply_v3(cm_processor, rgba); + rgba[3] = 1.0f; + break; + case 2: + copy_v3_fl(rgba, fp[0]); + rgba[3] = fp[1]; + break; + case 1: + copy_v3_fl(rgba, fp[0]); + rgba[3] = 1.0f; + break; + default: + BLI_assert(0); + } - hist->data_luma[i] = IMB_colormanagement_get_luminance(rgb); - hist->data_r[i] = rgb[0]; - hist->data_g[i] = rgb[1]; - hist->data_b[i] = rgb[2]; - hist->data_a[i] = fp[3]; + hist->data_luma[i] = IMB_colormanagement_get_luminance(rgba); + hist->data_r[i] = rgba[0]; + hist->data_g[i] = rgba[1]; + hist->data_b[i] = rgba[2]; + hist->data_a[i] = rgba[3]; } else if (ibuf->rect) { cp = (unsigned char *)(ibuf->rect + y * ibuf->x + x); @@ -1148,8 +1177,28 @@ void scopes_update(Scopes *scopes, ImBuf *ibuf, const ColorManagedViewSettings * for (x = 0; x < ibuf->x; x++) { float rgba[4], ycc[3], luma; if (is_float) { - copy_v4_v4(rgba, rf); - IMB_colormanagement_processor_apply_v4(cm_processor, rgba); + + switch (ibuf->channels) { + case 4: + copy_v4_v4(rgba, rf); + IMB_colormanagement_processor_apply_v4(cm_processor, rgba); + break; + case 3: + copy_v3_v3(rgba, rf); + IMB_colormanagement_processor_apply_v3(cm_processor, rgba); + rgba[3] = 1.0f; + break; + case 2: + copy_v3_fl(rgba, rf[0]); + rgba[3] = rf[1]; + break; + case 1: + copy_v3_fl(rgba, rf[0]); + rgba[3] = 1.0f; + break; + default: + BLI_assert(0); + } } else { for (c = 0; c < 4; c++) diff --git a/source/blender/blenkernel/intern/constraint.c b/source/blender/blenkernel/intern/constraint.c index 2aba4fcde27..03406c6c2a0 100644 --- a/source/blender/blenkernel/intern/constraint.c +++ b/source/blender/blenkernel/intern/constraint.c @@ -447,7 +447,7 @@ static void contarget_get_mesh_mat(Object *ob, const char *substring, float mat[ copy_v3_v3(plane, tmat[1]); cross_v3_v3v3(mat[0], normal, plane); - if (len_v3(mat[0]) < 1e-3f) { + if (len_squared_v3(mat[0]) < SQUARE(1e-3f)) { copy_v3_v3(plane, tmat[0]); cross_v3_v3v3(mat[0], normal, plane); } @@ -4882,11 +4882,12 @@ void BKE_constraints_solve(ListBase *conlist, bConstraintOb *cob, float ctime) * since some constraints may not convert the solution back to the input space before blending * but all are guaranteed to end up in good "worldspace" result */ - /* Note: all kind of stuff here before (caused trouble), much easier to just interpolate, or did I miss something? -jahka (r.32105) */ + /* Note: all kind of stuff here before (caused trouble), much easier to just interpolate, + * or did I miss something? -jahka (r.32105) */ if (enf < 1.0f) { float solution[4][4]; copy_m4_m4(solution, cob->matrix); - blend_m4_m4m4(cob->matrix, oldmat, solution, enf); + interp_m4_m4m4(cob->matrix, oldmat, solution, enf); } } } diff --git a/source/blender/blenkernel/intern/curve.c b/source/blender/blenkernel/intern/curve.c index aa9e9567ecf..3e0bdbe31af 100644 --- a/source/blender/blenkernel/intern/curve.c +++ b/source/blender/blenkernel/intern/curve.c @@ -161,15 +161,14 @@ void BKE_curve_free(Curve *cu) MEM_freeN(cu->tb); } -Curve *BKE_curve_add(Main *bmain, const char *name, int type) +void BKE_curve_init(Curve *cu) { - Curve *cu; + /* BLI_assert(MEMCMP_STRUCT_OFS_IS_ZERO(cu, id)); */ /* cu->type is already initialized... */ - cu = BKE_libblock_alloc(bmain, ID_CU, name); copy_v3_fl(cu->size, 1.0f); cu->flag = CU_FRONT | CU_BACK | CU_DEFORM_BOUNDS_OFF | CU_PATH_RADIUS; cu->pathlen = 100; - cu->resolu = cu->resolv = (type == OB_SURF) ? 4 : 12; + cu->resolu = cu->resolv = (cu->type == OB_SURF) ? 4 : 12; cu->width = 1.0; cu->wordspace = 1.0; cu->spacing = cu->linedist = 1.0; @@ -179,7 +178,6 @@ Curve *BKE_curve_add(Main *bmain, const char *name, int type) cu->smallcaps_scale = 0.75f; /* XXX: this one seems to be the best one in most cases, at least for curve deform... */ cu->twist_mode = CU_TWIST_MINIMUM; - cu->type = type; cu->bevfac1 = 0.0f; cu->bevfac2 = 1.0f; cu->bevfac1_mapping = CU_BEVFAC_MAP_RESOLU; @@ -187,7 +185,7 @@ Curve *BKE_curve_add(Main *bmain, const char *name, int type) cu->bb = BKE_boundbox_alloc_unit(); - if (type == OB_FONT) { + if (cu->type == OB_FONT) { cu->vfont = cu->vfontb = cu->vfonti = cu->vfontbi = BKE_vfont_builtin_get(); cu->vfont->id.us += 4; cu->str = MEM_mallocN(12, "str"); @@ -198,6 +196,16 @@ Curve *BKE_curve_add(Main *bmain, const char *name, int type) cu->tb = MEM_callocN(MAXTEXTBOX * sizeof(TextBox), "textbox"); cu->tb[0].w = cu->tb[0].h = 0.0; } +} + +Curve *BKE_curve_add(Main *bmain, const char *name, int type) +{ + Curve *cu; + + cu = BKE_libblock_alloc(bmain, ID_CU, name); + cu->type = type; + + BKE_curve_init(cu); return cu; } @@ -2626,7 +2634,7 @@ void BKE_curve_bevelList_make(Object *ob, ListBase *nurbs, bool for_render) BevPoint *bevp, *bevp2, *bevp1 = NULL, *bevp0; const float treshold = 0.00001f; float min, inp; - float *seglen; + float *seglen = NULL; struct BevelSort *sortdata, *sd, *sd1; int a, b, nr, poly, resolu = 0, len = 0, segcount; int *segbevcount; diff --git a/source/blender/blenkernel/intern/customdata.c b/source/blender/blenkernel/intern/customdata.c index 416125e53ad..c9b059e259e 100644 --- a/source/blender/blenkernel/intern/customdata.c +++ b/source/blender/blenkernel/intern/customdata.c @@ -61,6 +61,8 @@ #include "BKE_mesh_remap.h" #include "BKE_multires.h" +#include "data_transfer_intern.h" + #include "bmesh.h" #include <math.h> @@ -305,13 +307,16 @@ static void layerInterp_normal( const void **sources, const float *weights, const float *UNUSED(sub_weights), int count, void *dest) { + /* Note: This is linear interpolation, which is not optimal for vectors. + * Unfortunately, spherical interpolation of more than two values is hairy, so for now it will do... */ float no[3] = {0.0f}; while (count--) { madd_v3_v3fl(no, (const float *)sources[count], weights[count]); } - copy_v3_v3((float *)dest, no); + /* Weighted sum of normalized vectors will **not** be normalized, even if weights are. */ + normalize_v3_v3((float *)dest, no); } static void layerCopyValue_normal(const void *source, void *dest, const int mixmode, const float mixfactor) @@ -926,6 +931,7 @@ static void layerInterp_mloopuv( } /* delay writing to the destination incase dest is in sources */ + ((MLoopUV *)dest)->flag = ((MLoopUV *)sources)->flag; copy_v2_v2(((MLoopUV *)dest)->uv, uv); } @@ -1373,9 +1379,16 @@ const CustomDataMask CD_MASK_BMESH = CD_MASK_CREASE | CD_MASK_BWEIGHT | CD_MASK_RECAST | CD_MASK_PAINT_MASK | CD_MASK_GRID_PAINT_MASK | CD_MASK_MVERT_SKIN | CD_MASK_FREESTYLE_EDGE | CD_MASK_FREESTYLE_FACE | CD_MASK_CUSTOMLOOPNORMAL | CD_MASK_FACEMAP; -const CustomDataMask CD_MASK_FACECORNERS = /* XXX Not used anywhere! */ - CD_MASK_MTFACE | CD_MASK_MCOL | CD_MASK_MTEXPOLY | CD_MASK_MLOOPUV | - CD_MASK_MLOOPCOL | CD_MASK_NORMAL | CD_MASK_MLOOPTANGENT; +/** + * cover values copied by #BKE_mesh_loops_to_tessdata + */ +const CustomDataMask CD_MASK_FACECORNERS = + CD_MASK_MTFACE | CD_MASK_MTEXPOLY | CD_MASK_MLOOPUV | + CD_MASK_MCOL | CD_MASK_MLOOPCOL | + CD_MASK_PREVIEW_MCOL | CD_MASK_PREVIEW_MLOOPCOL | + CD_MASK_ORIGSPACE | CD_MASK_ORIGSPACE_MLOOP | + CD_MASK_TESSLOOPNORMAL | CD_MASK_NORMAL | + CD_MASK_TANGENT | CD_MASK_MLOOPTANGENT; const CustomDataMask CD_MASK_EVERYTHING = CD_MASK_MVERT | CD_MASK_MDEFORMVERT | CD_MASK_MEDGE | CD_MASK_MFACE | CD_MASK_MTFACE | CD_MASK_MCOL | CD_MASK_ORIGINDEX | CD_MASK_NORMAL /* | CD_MASK_POLYINDEX */ | CD_MASK_PROP_FLT | @@ -2501,6 +2514,10 @@ void CustomData_to_bmeshpoly(CustomData *fdata, CustomData *pdata, CustomData *l void CustomData_from_bmeshpoly(CustomData *fdata, CustomData *pdata, CustomData *ldata, int total) { int i; + + /* avoid accumulating extra layers */ + BLI_assert(!CustomData_from_bmeshpoly_test(fdata, pdata, ldata, false)); + for (i = 0; i < pdata->totlayer; i++) { if (pdata->layers[i].type == CD_MTEXPOLY) { CustomData_add_layer_named(fdata, CD_MTFACE, CD_CALLOC, NULL, total, pdata->layers[i].name); @@ -2527,6 +2544,41 @@ void CustomData_from_bmeshpoly(CustomData *fdata, CustomData *pdata, CustomData CustomData_bmesh_update_active_layers(fdata, pdata, ldata); } +#ifndef NDEBUG +/** + * Debug check, used to assert when we expect layers to be in/out of sync. + * + * \param fallback: Use when there are no layers to handle, + * since callers may expect success or failure. + */ +bool CustomData_from_bmeshpoly_test(CustomData *fdata, CustomData *pdata, CustomData *ldata, bool fallback) +{ + int a_num = 0, b_num = 0; +#define LAYER_CMP(l_a, t_a, l_b, t_b) \ + ((a_num += CustomData_number_of_layers(l_a, t_a)) == (b_num += CustomData_number_of_layers(l_b, t_b))) + + if (!LAYER_CMP(pdata, CD_MTEXPOLY, fdata, CD_MTFACE)) + return false; + if (!LAYER_CMP(ldata, CD_MLOOPCOL, fdata, CD_MCOL)) + return false; + if (!LAYER_CMP(ldata, CD_PREVIEW_MLOOPCOL, fdata, CD_PREVIEW_MCOL)) + return false; + if (!LAYER_CMP(ldata, CD_ORIGSPACE_MLOOP, fdata, CD_ORIGSPACE)) + return false; + if (!LAYER_CMP(ldata, CD_NORMAL, fdata, CD_TESSLOOPNORMAL)) + return false; + if (!LAYER_CMP(ldata, CD_TANGENT, fdata, CD_TANGENT)) + return false; + +#undef TEST_RET + + /* if no layers are on either CustomData's, + * then there was nothing to do... */ + return a_num ? true : fallback; +} +#endif + + void CustomData_bmesh_update_active_layers(CustomData *fdata, CustomData *pdata, CustomData *ldata) { int act; @@ -3878,6 +3930,38 @@ static void customdata_data_transfer_interp_generic( MEM_freeN(tmp_dst); } +/* Normals are special, we need to take care of source & destination spaces... */ +void customdata_data_transfer_interp_normal_normals( + const CustomDataTransferLayerMap *laymap, void *data_dst, + const void **sources, const float *weights, const int count, + const float mix_factor) +{ + const int data_type = laymap->data_type; + const int mix_mode = laymap->mix_mode; + + SpaceTransform *space_transform = laymap->interp_data; + + const LayerTypeInfo *type_info = layerType_getInfo(data_type); + cd_interp interp_cd = type_info->interp; + + float tmp_dst[3]; + + BLI_assert(data_type == CD_NORMAL); + + if (!sources) { + /* Not supported here, abort. */ + return; + } + + interp_cd(sources, weights, NULL, count, tmp_dst); + if (space_transform) { + /* tmp_dst is in source space so far, bring it back in destination space. */ + BLI_space_transform_invert_normal(space_transform, tmp_dst); + } + + CustomData_data_mix_value(data_type, tmp_dst, data_dst, mix_mode, mix_factor); +} + void CustomData_data_transfer(const MeshPairRemap *me_remap, const CustomDataTransferLayerMap *laymap) { MeshPairRemapItem *mapit = me_remap->items; diff --git a/source/blender/blenkernel/intern/data_transfer.c b/source/blender/blenkernel/intern/data_transfer.c index 53b6f4a1019..43d23e92901 100644 --- a/source/blender/blenkernel/intern/data_transfer.c +++ b/source/blender/blenkernel/intern/data_transfer.c @@ -291,7 +291,7 @@ static void data_transfer_dtdata_type_preprocess( poly_nors_dst = CustomData_add_layer(pdata_dst, CD_NORMAL, CD_CALLOC, NULL, num_polys_dst); CustomData_set_layer_flag(pdata_dst, CD_NORMAL, CD_FLAG_TEMPORARY); } - BKE_mesh_calc_normals_poly(verts_dst, num_verts_dst, loops_dst, polys_dst, + BKE_mesh_calc_normals_poly(verts_dst, NULL, num_verts_dst, loops_dst, polys_dst, num_loops_dst, num_polys_dst, poly_nors_dst, true); } /* Cache loop nors into a temp CDLayer. */ @@ -428,7 +428,7 @@ void data_transfer_layersmapping_add_item( ListBase *r_map, const int cddata_type, const int mix_mode, const float mix_factor, const float *mix_weights, const void *data_src, void *data_dst, const int data_src_n, const int data_dst_n, const size_t elem_size, const size_t data_size, const size_t data_offset, const uint64_t data_flag, - cd_datatransfer_interp interp) + cd_datatransfer_interp interp, void *interp_data) { CustomDataTransferLayerMap *item = MEM_mallocN(sizeof(*item), __func__); @@ -450,17 +450,18 @@ void data_transfer_layersmapping_add_item( item->data_flag = data_flag; item->interp = interp; + item->interp_data = interp_data; BLI_addtail(r_map, item); } static void data_transfer_layersmapping_add_item_cd( ListBase *r_map, const int cddata_type, const int mix_mode, const float mix_factor, const float *mix_weights, - void *data_src, void *data_dst) + void *data_src, void *data_dst, cd_datatransfer_interp interp, void *interp_data) { data_transfer_layersmapping_add_item( r_map, cddata_type, mix_mode, mix_factor, mix_weights, data_src, data_dst, - 0, 0, 0, 0, 0, 0, NULL); + 0, 0, 0, 0, 0, 0, interp, interp_data); } /* Note: All those layer mapping handlers return false *only* if they were given invalid parameters. @@ -473,7 +474,8 @@ static bool data_transfer_layersmapping_cdlayers_multisrc_to_dst( ListBase *r_map, const int cddata_type, const int mix_mode, const float mix_factor, const float *mix_weights, const int num_elem_dst, const bool use_create, const bool use_delete, CustomData *cd_src, CustomData *cd_dst, const bool use_dupref_dst, - const int tolayers, bool *use_layers_src, const int num_layers_src) + const int tolayers, bool *use_layers_src, const int num_layers_src, + cd_datatransfer_interp interp, void *interp_data) { void *data_src, *data_dst = NULL; int idx_src = num_layers_src; @@ -527,7 +529,7 @@ static bool data_transfer_layersmapping_cdlayers_multisrc_to_dst( data_dst = CustomData_get_layer_n(cd_dst, cddata_type, idx_src); } data_transfer_layersmapping_add_item_cd(r_map, cddata_type, mix_mode, mix_factor, mix_weights, - data_src, data_dst); + data_src, data_dst, interp, interp_data); } } break; @@ -571,7 +573,7 @@ static bool data_transfer_layersmapping_cdlayers_multisrc_to_dst( data_dst = CustomData_get_layer_n(cd_dst, cddata_type, idx_dst); } data_transfer_layersmapping_add_item_cd(r_map, cddata_type, mix_mode, mix_factor, mix_weights, - data_src, data_dst); + data_src, data_dst, interp, interp_data); } } @@ -599,7 +601,8 @@ static bool data_transfer_layersmapping_cdlayers( ListBase *r_map, const int cddata_type, const int mix_mode, const float mix_factor, const float *mix_weights, const int num_elem_dst, const bool use_create, const bool use_delete, CustomData *cd_src, CustomData *cd_dst, const bool use_dupref_dst, - const int fromlayers, const int tolayers) + const int fromlayers, const int tolayers, + cd_datatransfer_interp interp, void *interp_data) { int idx_src, idx_dst; void *data_src, *data_dst = NULL; @@ -626,7 +629,7 @@ static bool data_transfer_layersmapping_cdlayers( if (r_map) { data_transfer_layersmapping_add_item_cd(r_map, cddata_type, mix_mode, mix_factor, mix_weights, - data_src, data_dst); + data_src, data_dst, interp, interp_data); } } else if (fromlayers == DT_LAYERS_ACTIVE_SRC || fromlayers >= 0) { @@ -719,7 +722,7 @@ static bool data_transfer_layersmapping_cdlayers( if (r_map) { data_transfer_layersmapping_add_item_cd( - r_map, cddata_type, mix_mode, mix_factor, mix_weights, data_src, data_dst); + r_map, cddata_type, mix_mode, mix_factor, mix_weights, data_src, data_dst, interp, interp_data); } } else if (fromlayers == DT_LAYERS_ALL_SRC) { @@ -734,7 +737,8 @@ static bool data_transfer_layersmapping_cdlayers( ret = data_transfer_layersmapping_cdlayers_multisrc_to_dst( r_map, cddata_type, mix_mode, mix_factor, mix_weights, num_elem_dst, use_create, use_delete, cd_src, cd_dst, use_dupref_dst, - tolayers, use_layers_src, num_src); + tolayers, use_layers_src, num_src, + interp, interp_data); if (use_layers_src) { MEM_freeN(use_layers_src); @@ -751,10 +755,14 @@ static bool data_transfer_layersmapping_cdlayers( static bool data_transfer_layersmapping_generate( ListBase *r_map, Object *ob_src, Object *ob_dst, DerivedMesh *dm_src, DerivedMesh *dm_dst, Mesh *me_dst, const int elem_type, int cddata_type, int mix_mode, float mix_factor, const float *mix_weights, - const int num_elem_dst, const bool use_create, const bool use_delete, const int fromlayers, const int tolayers) + const int num_elem_dst, const bool use_create, const bool use_delete, const int fromlayers, const int tolayers, + SpaceTransform *space_transform) { CustomData *cd_src, *cd_dst; + cd_datatransfer_interp interp = NULL; + void *interp_data = NULL; + if (elem_type == ME_VERT) { if (!(cddata_type & CD_FAKE)) { cd_src = dm_src->getVertDataLayout(dm_src); @@ -763,7 +771,8 @@ static bool data_transfer_layersmapping_generate( if (!data_transfer_layersmapping_cdlayers(r_map, cddata_type, mix_mode, mix_factor, mix_weights, num_elem_dst, use_create, use_delete, cd_src, cd_dst, dm_dst != NULL, - fromlayers, tolayers)) + fromlayers, tolayers, + interp, interp_data)) { /* We handle specific source selection cases here. */ return false; @@ -795,7 +804,7 @@ static bool data_transfer_layersmapping_generate( dm_src->getNumVerts(dm_src), dm_dst ? dm_dst->getNumVerts(dm_dst) : me_dst->totvert, elem_size, data_size, data_offset, data_flag, - data_transfer_interp_char); + data_transfer_interp_char, interp_data); } return true; } @@ -827,7 +836,8 @@ static bool data_transfer_layersmapping_generate( if (!data_transfer_layersmapping_cdlayers(r_map, cddata_type, mix_mode, mix_factor, mix_weights, num_elem_dst, use_create, use_delete, cd_src, cd_dst, dm_dst != NULL, - fromlayers, tolayers)) + fromlayers, tolayers, + interp, interp_data)) { /* We handle specific source selection cases here. */ return false; @@ -859,7 +869,7 @@ static bool data_transfer_layersmapping_generate( dm_src->getNumEdges(dm_src), dm_dst ? dm_dst->getNumEdges(dm_dst) : me_dst->totedge, elem_size, data_size, data_offset, data_flag, - data_transfer_interp_char); + data_transfer_interp_char, interp_data); } return true; } @@ -888,7 +898,7 @@ static bool data_transfer_layersmapping_generate( dm_src->getNumEdges(dm_src), dm_dst ? dm_dst->getNumEdges(dm_dst) : me_dst->totedge, elem_size, data_size, data_offset, data_flag, - data_transfer_interp_char); + data_transfer_interp_char, interp_data); } return true; } @@ -904,7 +914,7 @@ static bool data_transfer_layersmapping_generate( dm_dst ? dm_dst->getEdgeArray(dm_dst) : me_dst->medge, dm_src->getNumEdges(dm_src), dm_dst ? dm_dst->getNumEdges(dm_dst) : me_dst->totedge, - elem_size, data_size, data_offset, data_flag, NULL); + elem_size, data_size, data_offset, data_flag, NULL, interp_data); return true; } else { @@ -918,6 +928,8 @@ static bool data_transfer_layersmapping_generate( else if (cddata_type == CD_FAKE_LNOR) { /* Preprocess should have generated it, Postprocess will convert it back to CD_CUSTOMLOOPNORMAL. */ cddata_type = CD_NORMAL; + interp_data = space_transform; + interp = customdata_data_transfer_interp_normal_normals; } if (!(cddata_type & CD_FAKE)) { @@ -927,7 +939,8 @@ static bool data_transfer_layersmapping_generate( if (!data_transfer_layersmapping_cdlayers( r_map, cddata_type, mix_mode, mix_factor, mix_weights, num_elem_dst, use_create, use_delete, cd_src, cd_dst, dm_dst != NULL, - fromlayers, tolayers)) + fromlayers, tolayers, + interp, interp_data)) { /* We handle specific source selection cases here. */ return false; @@ -950,7 +963,8 @@ static bool data_transfer_layersmapping_generate( if (!data_transfer_layersmapping_cdlayers( r_map, cddata_type, mix_mode, mix_factor, mix_weights, num_elem_dst, use_create, use_delete, cd_src, cd_dst, dm_dst != NULL, - fromlayers, tolayers)) + fromlayers, tolayers, + interp, interp_data)) { /* We handle specific source selection cases here. */ return false; @@ -969,7 +983,7 @@ static bool data_transfer_layersmapping_generate( dm_dst ? dm_dst->getPolyArray(dm_dst) : me_dst->mpoly, dm_src->getNumPolys(dm_src), dm_dst ? dm_dst->getNumPolys(dm_dst) : me_dst->totpoly, - elem_size, data_size, data_offset, data_flag, NULL); + elem_size, data_size, data_offset, data_flag, NULL, interp_data); return true; } else { @@ -1035,28 +1049,28 @@ void BKE_object_data_transfer_layout( data_transfer_layersmapping_generate( NULL, ob_src, ob_dst, dm_src, NULL, me_dst, ME_VERT, cddata_type, 0, 0.0f, NULL, - num_elem_dst, use_create, use_delete, fromlayers, tolayers); + num_elem_dst, use_create, use_delete, fromlayers, tolayers, NULL); } if (DT_DATATYPE_IS_EDGE(dtdata_type)) { const int num_elem_dst = me_dst->totedge; data_transfer_layersmapping_generate( NULL, ob_src, ob_dst, dm_src, NULL, me_dst, ME_EDGE, cddata_type, 0, 0.0f, NULL, - num_elem_dst, use_create, use_delete, fromlayers, tolayers); + num_elem_dst, use_create, use_delete, fromlayers, tolayers, NULL); } if (DT_DATATYPE_IS_LOOP(dtdata_type)) { const int num_elem_dst = me_dst->totloop; data_transfer_layersmapping_generate( NULL, ob_src, ob_dst, dm_src, NULL, me_dst, ME_LOOP, cddata_type, 0, 0.0f, NULL, - num_elem_dst, use_create, use_delete, fromlayers, tolayers); + num_elem_dst, use_create, use_delete, fromlayers, tolayers, NULL); } if (DT_DATATYPE_IS_POLY(dtdata_type)) { const int num_elem_dst = me_dst->totpoly; data_transfer_layersmapping_generate( NULL, ob_src, ob_dst, dm_src, NULL, me_dst, ME_POLY, cddata_type, 0, 0.0f, NULL, - num_elem_dst, use_create, use_delete, fromlayers, tolayers); + num_elem_dst, use_create, use_delete, fromlayers, tolayers, NULL); } } } @@ -1198,7 +1212,7 @@ bool BKE_object_data_transfer_dm( if (data_transfer_layersmapping_generate( &lay_map, ob_src, ob_dst, dm_src, dm_dst, me_dst, ME_VERT, cddata_type, mix_mode, mix_factor, weights[VDATA], - num_verts_dst, use_create, use_delete, fromlayers, tolayers)) + num_verts_dst, use_create, use_delete, fromlayers, tolayers, space_transform)) { CustomDataTransferLayerMap *lay_mapit; @@ -1249,7 +1263,7 @@ bool BKE_object_data_transfer_dm( if (data_transfer_layersmapping_generate( &lay_map, ob_src, ob_dst, dm_src, dm_dst, me_dst, ME_EDGE, cddata_type, mix_mode, mix_factor, weights[EDATA], - num_edges_dst, use_create, use_delete, fromlayers, tolayers)) + num_edges_dst, use_create, use_delete, fromlayers, tolayers, space_transform)) { CustomDataTransferLayerMap *lay_mapit; @@ -1312,7 +1326,7 @@ bool BKE_object_data_transfer_dm( if (data_transfer_layersmapping_generate( &lay_map, ob_src, ob_dst, dm_src, dm_dst, me_dst, ME_LOOP, cddata_type, mix_mode, mix_factor, weights[LDATA], - num_loops_dst, use_create, use_delete, fromlayers, tolayers)) + num_loops_dst, use_create, use_delete, fromlayers, tolayers, space_transform)) { CustomDataTransferLayerMap *lay_mapit; @@ -1367,7 +1381,7 @@ bool BKE_object_data_transfer_dm( if (data_transfer_layersmapping_generate( &lay_map, ob_src, ob_dst, dm_src, dm_dst, me_dst, ME_POLY, cddata_type, mix_mode, mix_factor, weights[PDATA], - num_polys_dst, use_create, use_delete, fromlayers, tolayers)) + num_polys_dst, use_create, use_delete, fromlayers, tolayers, space_transform)) { CustomDataTransferLayerMap *lay_mapit; diff --git a/source/blender/blenkernel/intern/data_transfer_intern.h b/source/blender/blenkernel/intern/data_transfer_intern.h index 501b749b464..352eedc6ec2 100644 --- a/source/blender/blenkernel/intern/data_transfer_intern.h +++ b/source/blender/blenkernel/intern/data_transfer_intern.h @@ -45,7 +45,7 @@ void data_transfer_layersmapping_add_item( const float mix_factor, const float *mix_weights, const void *data_src, void *data_dst, const int data_src_n, const int data_dst_n, const size_t elem_size, const size_t data_size, const size_t data_offset, const uint64_t data_flag, - cd_datatransfer_interp interp); + cd_datatransfer_interp interp, void *interp_data); /* Type-specific. */ @@ -55,4 +55,10 @@ bool data_transfer_layersmapping_vgroups( struct Object *ob_src, struct Object *ob_dst, struct CustomData *cd_src, struct CustomData *cd_dst, const bool use_dupref_dst, const int fromlayers, const int tolayers); +/* Defined in customdata.c */ +void customdata_data_transfer_interp_normal_normals( + const CustomDataTransferLayerMap *laymap, void *data_dst, + const void **sources, const float *weights, const int count, + const float mix_factor); + #endif /* __DATA_TRANSFER_INTERN_H__ */ diff --git a/source/blender/blenkernel/intern/deform.c b/source/blender/blenkernel/intern/deform.c index 6670c3359d7..f904369ae97 100644 --- a/source/blender/blenkernel/intern/deform.c +++ b/source/blender/blenkernel/intern/deform.c @@ -1163,7 +1163,7 @@ static bool data_transfer_layersmapping_vgroups_multisrc_to_dst( } data_transfer_layersmapping_add_item(r_map, CD_FAKE_MDEFORMVERT, mix_mode, mix_factor, mix_weights, data_src, data_dst, idx_src, idx_src, - elem_size, 0, 0, 0, vgroups_datatransfer_interp); + elem_size, 0, 0, 0, vgroups_datatransfer_interp, NULL); } } break; @@ -1211,7 +1211,7 @@ static bool data_transfer_layersmapping_vgroups_multisrc_to_dst( data_transfer_layersmapping_add_item( r_map, CD_FAKE_MDEFORMVERT, mix_mode, mix_factor, mix_weights, data_src, data_dst, idx_src, idx_dst, - elem_size, 0, 0, 0, vgroups_datatransfer_interp); + elem_size, 0, 0, 0, vgroups_datatransfer_interp, NULL); } } break; @@ -1317,7 +1317,7 @@ bool data_transfer_layersmapping_vgroups( data_transfer_layersmapping_add_item(r_map, CD_FAKE_MDEFORMVERT, mix_mode, mix_factor, mix_weights, data_src, data_dst, idx_src, idx_dst, - elem_size, 0, 0, 0, vgroups_datatransfer_interp); + elem_size, 0, 0, 0, vgroups_datatransfer_interp, NULL); } } else { diff --git a/source/blender/blenkernel/intern/depsgraph.c b/source/blender/blenkernel/intern/depsgraph.c index 62491f1ff6e..42b6b311dff 100644 --- a/source/blender/blenkernel/intern/depsgraph.c +++ b/source/blender/blenkernel/intern/depsgraph.c @@ -513,7 +513,6 @@ static void build_dag_object(DagForest *dag, DagNode *scenenode, Main *bmain, Sc } /* also build a custom data mask for dependencies that need certain layers */ - node->customdata_mask = 0; if (ob->type == OB_ARMATURE) { if (ob->pose) { @@ -1143,9 +1142,12 @@ void dag_add_relation(DagForest *forest, DagNode *fob1, DagNode *fob2, short rel if ((rel & DAG_RL_DATA_DATA) != 0) { if (fob1->type == ID_OB) { if ((fob1->eval_flags & DAG_EVAL_NEED_CPU) == 0) { - Object *object = fob1->ob; - /* Make sure object has all the data on CPU. */ - object->recalc |= OB_RECALC_DATA; + 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; } } @@ -1349,16 +1351,32 @@ void graph_print_adj_list(DagForest *dag) * 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 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); + 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); } } @@ -1428,7 +1446,7 @@ static void dag_scene_free(Scene *sce) } } -/* Chech whether object data needs to be evaluated before it +/* Check whether object data needs to be evaluated before it * might be used by others. * * Means that mesh object needs to have proper derivedFinal, @@ -1640,7 +1658,7 @@ static void dag_scene_build(Main *bmain, Scene *sce) /* temporal...? */ sce->recalc |= SCE_PRV_CHANGED; /* test for 3d preview */ - /* Make sure that new dependencies which came from invisble layers + /* 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). */ @@ -2000,25 +2018,50 @@ void DAG_scene_flush_update(Main *bmain, Scene *sce, unsigned int lay, const sho dag_tag_renderlayers(sce, lay); } -static int object_modifiers_use_time(Object *ob) +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) + for (md = ob->modifiers.first; md; md = md->next) { if (modifier_dependsOnTime(md)) - return 1; + 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 1; + return true; } } @@ -2030,14 +2073,17 @@ static int object_modifiers_use_time(Object *ob) */ for (fcu = adt->drivers.first; fcu; fcu = fcu->next) { if (fcu->rna_path && strstr(fcu->rna_path, "modifiers[")) - return 1; + return true; } - /* XXX: also, should check NLA strips, though for now assume that nobody uses - * that and we can omit that for performance reasons... */ + /* 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 0; + return false; } static short animdata_use_time(AnimData *adt) @@ -2474,7 +2520,8 @@ void DAG_on_visible_update(Main *bmain, const bool do_time) } } -static void dag_id_flush_update__isDependentTexture(void *userData, Object *UNUSED(ob), ID **idpoin) +static void dag_id_flush_update__isDependentTexture( + void *userData, Object *UNUSED(ob), ID **idpoin, int UNUSED(cd_flag)) { struct { ID *id; bool is_dependent; } *data = userData; @@ -3485,9 +3532,15 @@ void DAG_exit(void) /* ************************ API *********************** */ void DAG_editors_update_cb(DEG_EditorUpdateIDCb id_func, - DEG_EditorUpdateSceneCb scene_func) + DEG_EditorUpdateSceneCb scene_func, + DEG_EditorUpdateScenePreCb scene_func_pre) +{ + DEG_editors_set_update_cb(id_func, scene_func, scene_func_pre); +} + +void DAG_editors_update_pre(Main *bmain, Scene *scene, bool time) { - DEG_editors_set_update_cb(id_func, scene_func); + DEG_editors_update_pre(bmain, scene, time); } /* Tag all relations for update. */ diff --git a/source/blender/blenkernel/intern/displist.c b/source/blender/blenkernel/intern/displist.c index 3213b59b92d..a2d555d0918 100644 --- a/source/blender/blenkernel/intern/displist.c +++ b/source/blender/blenkernel/intern/displist.c @@ -1521,7 +1521,7 @@ static void do_makeDispListCurveTypes(Scene *scene, Object *ob, ListBase *dispba BKE_curve_bevelList_free(&ob->curve_cache->bev); - /* We only re-evlauate path if evaluation is not happening for orco. + /* We only re-evaluate path if evaluation is not happening for orco. * If the calculation happens for orco, we should never free data which * was needed before and only not needed for orco calculation. */ @@ -1600,7 +1600,7 @@ static void do_makeDispListCurveTypes(Scene *scene, Object *ob, ListBase *dispba float bottom_no[3] = {0.0f}; float top_no[3] = {0.0f}; float firstblend = 0.0f, lastblend = 0.0f; - int i, start, steps; + int i, start, steps = 0; if (nu->flagu & CU_NURB_CYCLIC) { calc_bevfac_mapping_default(bl, diff --git a/source/blender/blenkernel/intern/dynamicpaint.c b/source/blender/blenkernel/intern/dynamicpaint.c index 7f1d2e877ed..f3ce988ee17 100644 --- a/source/blender/blenkernel/intern/dynamicpaint.c +++ b/source/blender/blenkernel/intern/dynamicpaint.c @@ -1773,8 +1773,8 @@ static DerivedMesh *dynamicPaint_Modifier_apply(DynamicPaintModifierData *pmd, } else { col[l_index].r = - col[l_index].g = - col[l_index].b = FTOCHAR(pPoint[v_index].wetness); + col[l_index].g = + col[l_index].b = FTOCHAR(pPoint[v_index].wetness); col[l_index].a = 255; } } @@ -2085,7 +2085,7 @@ static int dynamicPaint_findNeighbourPixel(PaintUVPoint *tempPoints, DerivedMesh int i, edge1_index, edge2_index, e1_index, e2_index, target_tri; float closest_point[2], lambda, dir_vec[2]; - int target_uv1, target_uv2, final_pixel[2], final_index; + int target_uv1 = 0, target_uv2 = 0, final_pixel[2], final_index; const float *s_uv1, *s_uv2, *t_uv1, *t_uv2; @@ -3416,7 +3416,7 @@ static int dynamicPaint_paintMesh(DynamicPaintSurface *surface, { float proxDist = -1.0f; float hitCo[3] = {0.0f, 0.0f, 0.0f}; - int tri; + int tri = 0; /* if inverse prox and no hit found, skip this sample */ if (inner_proximity && !hit_found) continue; diff --git a/source/blender/blenkernel/intern/editderivedmesh.c b/source/blender/blenkernel/intern/editderivedmesh.c index f463cab1a10..88ae279050c 100644 --- a/source/blender/blenkernel/intern/editderivedmesh.c +++ b/source/blender/blenkernel/intern/editderivedmesh.c @@ -397,7 +397,7 @@ static void emDM_calcLoopTangents(DerivedMesh *dm) mesh2tangent.precomputedLoopNormals = tlnors; mesh2tangent.looptris = em->looptris; mesh2tangent.cd_loop_uv_offset = cd_loop_uv_offset; - mesh2tangent.orco = orco; + mesh2tangent.orco = (const float (*)[3])orco; mesh2tangent.tangent = tangent; mesh2tangent.numTessFaces = totface; @@ -1248,7 +1248,7 @@ static void emdm_pass_attrib_vertex_glsl(const DMVertexAttribs *attribs, const B GLubyte col[4]; if (attribs->mcol[i].em_offset != -1) { const MLoopCol *cp = BM_ELEM_CD_GET_VOID_P(loop, attribs->mcol[i].em_offset); - copy_v4_v4_char((char *)col, &cp->r); + copy_v4_v4_uchar(col, &cp->r); } else { col[0] = 0; col[1] = 0; col[2] = 0; col[3] = 0; @@ -2170,8 +2170,8 @@ static void statvis_calc_overhang( rgb_float_to_uchar(r_face_colors[index], fcol); } else { - unsigned char *fallback = is_max ? col_fallback_max : col_fallback; - copy_v4_v4_char((char *)r_face_colors[index], (const char *)fallback); + const unsigned char *fallback = is_max ? col_fallback_max : col_fallback; + copy_v4_v4_uchar(r_face_colors[index], fallback); } } } @@ -2210,7 +2210,7 @@ static void statvis_calc_thickness( struct BMLoop *(*looptris)[3] = em->looptris; /* fallback */ - const char col_fallback[4] = {64, 64, 64, 255}; + const unsigned char col_fallback[4] = {64, 64, 64, 255}; struct BMBVHTree *bmtree; @@ -2305,7 +2305,7 @@ static void statvis_calc_thickness( rgb_float_to_uchar(r_face_colors[i], fcol); } else { - copy_v4_v4_char((char *)r_face_colors[i], (const char *)col_fallback); + copy_v4_v4_uchar(r_face_colors[i], col_fallback); } } } @@ -2357,7 +2357,7 @@ static void statvis_calc_intersect( index = BM_elem_index_get(f_hit); - copy_v3_v3_char((char *)r_face_colors[index], (const char *)col); + copy_v3_v3_uchar(r_face_colors[index], col); } } MEM_freeN(overlap); @@ -2382,7 +2382,7 @@ static void statvis_calc_distort( const float minmax_irange = 1.0f / (max - min); /* fallback */ - const char col_fallback[4] = {64, 64, 64, 255}; + const unsigned char col_fallback[4] = {64, 64, 64, 255}; /* now convert into global space */ BM_ITER_MESH_INDEX (f, &iter, bm, BM_FACES_OF_MESH, index) { @@ -2431,7 +2431,7 @@ static void statvis_calc_distort( rgb_float_to_uchar(r_face_colors[index], fcol); } else { - copy_v4_v4_char((char *)r_face_colors[index], (const char *)col_fallback); + copy_v4_v4_uchar(r_face_colors[index], col_fallback); } } } @@ -2453,7 +2453,7 @@ static void statvis_calc_sharp( int i; /* fallback */ - const char col_fallback[4] = {64, 64, 64, 255}; + const unsigned char col_fallback[4] = {64, 64, 64, 255}; (void)vertexCos; /* TODO */ @@ -2481,7 +2481,7 @@ static void statvis_calc_sharp( rgb_float_to_uchar(r_vert_colors[i], fcol); } else { - copy_v4_v4_char((char *)r_vert_colors[i], (const char *)col_fallback); + copy_v4_v4_uchar(r_vert_colors[i], col_fallback); } } } diff --git a/source/blender/blenkernel/intern/effect.c b/source/blender/blenkernel/intern/effect.c index bf53acc1d95..e66fa86c4b1 100644 --- a/source/blender/blenkernel/intern/effect.c +++ b/source/blender/blenkernel/intern/effect.c @@ -687,10 +687,10 @@ int get_effector_data(EffectorCache *eff, EffectorData *efd, EffectedPoint *poin } static void get_effector_tot(EffectorCache *eff, EffectorData *efd, EffectedPoint *point, int *tot, int *p, int *step) { - if (eff->pd->shape == PFIELD_SHAPE_POINTS) { - efd->index = p; + *p = 0; + efd->index = p; - *p = 0; + if (eff->pd->shape == PFIELD_SHAPE_POINTS) { *tot = eff->ob->derivedFinal ? eff->ob->derivedFinal->numVertData : 1; if (*tot && eff->pd->forcefield == PFIELD_HARMONIC && point->index >= 0) { @@ -699,9 +699,6 @@ static void get_effector_tot(EffectorCache *eff, EffectorData *efd, EffectedPoin } } else if (eff->psys) { - efd->index = p; - - *p = 0; *tot = eff->psys->totpart; if (eff->pd->forcefield == PFIELD_CHARGE) { @@ -727,7 +724,6 @@ static void get_effector_tot(EffectorCache *eff, EffectorData *efd, EffectedPoin } } else { - *p = 0; *tot = 1; } } diff --git a/source/blender/blenkernel/intern/fmodifier.c b/source/blender/blenkernel/intern/fmodifier.c index 2305ae89abd..2c301c04100 100644 --- a/source/blender/blenkernel/intern/fmodifier.c +++ b/source/blender/blenkernel/intern/fmodifier.c @@ -103,8 +103,8 @@ static FModifierTypeInfo FMI_MODNAME = { /* Generators available: * 1) simple polynomial generator: - * - Exanded form - (y = C[0]*(x^(n)) + C[1]*(x^(n-1)) + ... + C[n]) - * - Factorized form - (y = (C[0][0]*x + C[0][1]) * (C[1][0]*x + C[1][1]) * ... * (C[n][0]*x + C[n][1])) + * - Expanded form - (y = C[0]*(x^(n)) + C[1]*(x^(n-1)) + ... + C[n]) + * - Factorized form - (y = (C[0][0]*x + C[0][1]) * (C[1][0]*x + C[1][1]) * ... * (C[n][0]*x + C[n][1])) */ static void fcm_generator_free(FModifier *fcm) @@ -849,7 +849,7 @@ static FModifierTypeInfo FMI_FILTER = { NULL, /* copy data */ NULL, /* new data */ NULL /*fcm_filter_verify*/, /* verify */ - NULL, /* evlauate time */ + NULL, /* evaluate time */ fcm_filter_evaluate, /* evaluate */ NULL, /* evaluate time with storage */ NULL /* evaluate with storage */ diff --git a/source/blender/blenkernel/intern/font.c b/source/blender/blenkernel/intern/font.c index 2adf8ebc615..b12e16d9502 100644 --- a/source/blender/blenkernel/intern/font.c +++ b/source/blender/blenkernel/intern/font.c @@ -203,7 +203,27 @@ static VFontData *vfont_get_data(Main *bmain, VFont *vfont) return vfont->data; } -VFont *BKE_vfont_load(Main *bmain, const char *name) +/* Bad naming actually in this case... */ +void BKE_vfont_init(VFont *vfont) +{ + PackedFile *pf = get_builtin_packedfile(); + + if (pf) { + VFontData *vfd; + + vfd = BLI_vfontdata_from_freetypefont(pf); + if (vfd) { + vfont->data = vfd; + + BLI_strncpy(vfont->name, FO_BUILTIN_NAME, sizeof(vfont->name)); + } + + /* Free the packed file */ + freePackedFile(pf); + } +} + +VFont *BKE_vfont_load(Main *bmain, const char *filepath) { char filename[FILE_MAXFILE]; VFont *vfont = NULL; @@ -211,16 +231,16 @@ VFont *BKE_vfont_load(Main *bmain, const char *name) PackedFile *temp_pf = NULL; bool is_builtin; - if (STREQ(name, FO_BUILTIN_NAME)) { - BLI_strncpy(filename, name, sizeof(filename)); + if (STREQ(filepath, FO_BUILTIN_NAME)) { + BLI_strncpy(filename, filepath, sizeof(filename)); pf = get_builtin_packedfile(); is_builtin = true; } else { - BLI_split_file_part(name, filename, sizeof(filename)); - pf = newPackedFile(NULL, name, bmain->name); - temp_pf = newPackedFile(NULL, name, bmain->name); + BLI_split_file_part(filepath, filename, sizeof(filename)); + pf = newPackedFile(NULL, filepath, bmain->name); + temp_pf = newPackedFile(NULL, filepath, bmain->name); is_builtin = false; } @@ -237,7 +257,7 @@ VFont *BKE_vfont_load(Main *bmain, const char *name) if (vfd->name[0] != '\0') { BLI_strncpy(vfont->id.name + 2, vfd->name, sizeof(vfont->id.name) - 2); } - BLI_strncpy(vfont->name, name, sizeof(vfont->name)); + BLI_strncpy(vfont->name, filepath, sizeof(vfont->name)); /* if autopack is on store the packedfile in de font structure */ if (!is_builtin && (G.fileflags & G_AUTOPACK)) { @@ -259,6 +279,37 @@ VFont *BKE_vfont_load(Main *bmain, const char *name) return vfont; } +VFont *BKE_vfont_load_exists_ex(struct Main *bmain, const char *filepath, bool *r_exists) +{ + VFont *vfont; + char str[FILE_MAX], strtest[FILE_MAX]; + + BLI_strncpy(str, filepath, sizeof(str)); + BLI_path_abs(str, bmain->name); + + /* first search an identical filepath */ + for (vfont = bmain->vfont.first; vfont; vfont = vfont->id.next) { + BLI_strncpy(strtest, vfont->name, sizeof(vfont->name)); + BLI_path_abs(strtest, ID_BLEND_PATH(bmain, &vfont->id)); + + if (BLI_path_cmp(strtest, str) == 0) { + vfont->id.us++; /* officially should not, it doesn't link here! */ + if (r_exists) + *r_exists = true; + return vfont; + } + } + + if (r_exists) + *r_exists = false; + return BKE_vfont_load(bmain, filepath); +} + +VFont *BKE_vfont_load_exists(struct Main *bmain, const char *filepath) +{ + return BKE_vfont_load_exists_ex(bmain, filepath, NULL); +} + static VFont *which_vfont(Curve *cu, CharInfo *info) { switch (info->flag & (CU_CHINFO_BOLD | CU_CHINFO_ITALIC)) { @@ -777,7 +828,7 @@ makebreak: if ((tb_scale.h != 0.0f) && (cu->totbox > (curbox + 1)) && - ((-(yof - tb_scale.y)) > (tb_scale.h - (linedist * cu->fsize)) - yof_scale)) + ((-(yof - tb_scale.y)) > (tb_scale.h - linedist) - yof_scale)) { maxlen = 0; curbox++; diff --git a/source/blender/blenkernel/intern/idcode.c b/source/blender/blenkernel/intern/idcode.c index cf1eb8838e9..68a741bc3fc 100644 --- a/source/blender/blenkernel/intern/idcode.c +++ b/source/blender/blenkernel/intern/idcode.c @@ -103,12 +103,12 @@ static IDType *idtype_from_name(const char *str) return NULL; } -static IDType *idtype_from_code(int code) +static IDType *idtype_from_code(short idcode) { int i = ARRAY_SIZE(idtypes); while (i--) - if (code == idtypes[i].code) + if (idcode == idtypes[i].code) return &idtypes[i]; return NULL; @@ -120,9 +120,9 @@ static IDType *idtype_from_code(int code) * \param code The code to check. * \return Boolean, 0 when invalid. */ -bool BKE_idcode_is_valid(int code) +bool BKE_idcode_is_valid(short idcode) { - return idtype_from_code(code) ? true : false; + return idtype_from_code(idcode) ? true : false; } /** @@ -131,9 +131,9 @@ bool BKE_idcode_is_valid(int code) * \param code The code to check. * \return Boolean, 0 when non linkable. */ -bool BKE_idcode_is_linkable(int code) +bool BKE_idcode_is_linkable(short idcode) { - IDType *idt = idtype_from_code(code); + IDType *idt = idtype_from_code(idcode); BLI_assert(idt); return idt ? ((idt->flags & IDTYPE_FLAGS_ISLINKABLE) != 0) : false; } @@ -145,9 +145,9 @@ bool BKE_idcode_is_linkable(int code) * \return A static string representing the name of * the code. */ -const char *BKE_idcode_to_name(int code) +const char *BKE_idcode_to_name(short idcode) { - IDType *idt = idtype_from_code(code); + IDType *idt = idtype_from_code(idcode); BLI_assert(idt); return idt ? idt->name : NULL; } @@ -158,7 +158,7 @@ const char *BKE_idcode_to_name(int code) * \param name The name to convert. * \return The code for the name, or 0 if invalid. */ -int BKE_idcode_from_name(const char *name) +short BKE_idcode_from_name(const char *name) { IDType *idt = idtype_from_name(name); BLI_assert(idt); @@ -168,7 +168,7 @@ int BKE_idcode_from_name(const char *name) /** * Convert an idcode into an idfilter (e.g. ID_OB -> FILTER_ID_OB). */ -int BKE_idcode_to_idfilter(const int idcode) +int BKE_idcode_to_idfilter(const short idcode) { #define CASE_IDFILTER(_id) case ID_##_id: return FILTER_ID_##_id @@ -211,7 +211,7 @@ int BKE_idcode_to_idfilter(const int idcode) /** * Convert an idfilter into an idcode (e.g. FILTER_ID_OB -> ID_OB). */ -int BKE_idcode_from_idfilter(const int idfilter) +short BKE_idcode_from_idfilter(const int idfilter) { #define CASE_IDFILTER(_id) case FILTER_ID_##_id: return ID_##_id @@ -258,9 +258,9 @@ int BKE_idcode_from_idfilter(const int idfilter) * \return A static string representing the name of * the code. */ -const char *BKE_idcode_to_name_plural(int code) +const char *BKE_idcode_to_name_plural(short idcode) { - IDType *idt = idtype_from_code(code); + IDType *idt = idtype_from_code(idcode); BLI_assert(idt); return idt ? idt->plural : NULL; } @@ -271,9 +271,9 @@ const char *BKE_idcode_to_name_plural(int code) * \param code The code to convert. * \return A static string representing the i18n context of the code. */ -const char *BKE_idcode_to_translation_context(int code) +const char *BKE_idcode_to_translation_context(short idcode) { - IDType *idt = idtype_from_code(code); + IDType *idt = idtype_from_code(idcode); BLI_assert(idt); return idt ? idt->i18n_context : BLT_I18NCONTEXT_DEFAULT; } @@ -284,7 +284,7 @@ const char *BKE_idcode_to_translation_context(int code) * \param index start as 0. * \return the code, 0 when all codes have been returned. */ -int BKE_idcode_iter_step(int *index) +short BKE_idcode_iter_step(int *index) { return (*index < ARRAY_SIZE(idtypes)) ? idtypes[(*index)++].code : 0; } diff --git a/source/blender/blenkernel/intern/image.c b/source/blender/blenkernel/intern/image.c index ef760f2da26..3ffd03dc3be 100644 --- a/source/blender/blenkernel/intern/image.c +++ b/source/blender/blenkernel/intern/image.c @@ -280,14 +280,9 @@ void BKE_image_free_packedfiles(Image *ima) image_free_packedfiles(ima); } -static void image_free_views(Image *ima) -{ - BLI_freelistN(&ima->views); -} - void BKE_image_free_views(Image *image) { - image_free_views(image); + BLI_freelistN(&image->views); } static void image_free_anims(Image *ima) @@ -350,7 +345,7 @@ void BKE_image_free(Image *ima) } } - image_free_views(ima); + BKE_image_free_views(ima); MEM_freeN(ima->stereo3d_format); } @@ -704,8 +699,7 @@ void BKE_image_alpha_mode_from_extension(Image *image) Image *BKE_image_load(Main *bmain, const char *filepath) { Image *ima; - int file, len; - const char *libname; + int file; char str[FILE_MAX]; BLI_strncpy(str, filepath, sizeof(str)); @@ -717,13 +711,7 @@ Image *BKE_image_load(Main *bmain, const char *filepath) return NULL; close(file); - /* create a short library name */ - len = strlen(filepath); - - while (len > 0 && filepath[len - 1] != '/' && filepath[len - 1] != '\\') len--; - libname = filepath + len; - - ima = image_alloc(bmain, libname, IMA_SRC_FILE, IMA_TYPE_IMAGE); + ima = image_alloc(bmain, BLI_path_basename(filepath), IMA_SRC_FILE, IMA_TYPE_IMAGE); BLI_strncpy(ima->name, filepath, sizeof(ima->name)); if (BLI_testextensie_array(filepath, imb_ext_movie)) @@ -746,7 +734,7 @@ Image *BKE_image_load_exists_ex(const char *filepath, bool *r_exists) BLI_strncpy(str, filepath, sizeof(str)); BLI_path_abs(str, G.main->name); - /* first search an identical image */ + /* first search an identical filepath */ for (ima = G.main->image.first; ima; ima = ima->id.next) { if (ima->source != IMA_SRC_VIEWER && ima->source != IMA_SRC_GENERATED) { BLI_strncpy(strtest, ima->name, sizeof(ima->name)); @@ -873,8 +861,6 @@ Image *BKE_image_add_generated(Main *bmain, unsigned int width, unsigned int hei } ima->ok = IMA_OK_LOADED; - if (stereo3d) - ima->flag |= IMA_IS_STEREO | IMA_IS_MULTIVIEW; } return ima; @@ -964,7 +950,7 @@ void BKE_image_memorypack(Image *ima) { ImBuf *ibuf; - if ((ima->flag & IMA_IS_MULTIVIEW)) { + if (BKE_image_is_multiview(ima)) { image_memorypack_multiview(ima); return; } @@ -1872,12 +1858,23 @@ void BKE_image_stamp_buf( struct ColorManagedDisplay *display; const char *display_device; + /* vars for calculating wordwrap */ + struct { + struct ResultBLF info; + rctf rect; + } wrap; + /* this could be an argument if we want to operate on non linear float imbuf's * for now though this is only used for renders which use scene settings */ #define TEXT_SIZE_CHECK(str, w, h) \ ((str[0]) && ((void)(h = h_fixed), (w = BLF_width(mono, str, sizeof(str))))) + /* must enable BLF_WORD_WRAP before using */ +#define TEXT_SIZE_CHECK_WORD_WRAP(str, w, h) \ + ((str[0]) && (BLF_boundbox_ex(mono, str, sizeof(str), &wrap.rect, &wrap.info), \ + (void)(h = h_fixed * wrap.info.lines), (w = BLI_rctf_size_x(&wrap.rect)))) + #define BUFF_MARGIN_X 2 #define BUFF_MARGIN_Y 1 @@ -1895,6 +1892,7 @@ void BKE_image_stamp_buf( /* set before return */ BLF_size(mono, scene->r.stamp_font_id, 72); + BLF_wordwrap(mono, width - (BUFF_MARGIN_X * 2)); BLF_buffer(mono, rectf, rect, width, height, channels, display); BLF_buffer_col(mono, scene->r.fg_stamp[0], scene->r.fg_stamp[1], scene->r.fg_stamp[2], 1.0); @@ -1917,14 +1915,14 @@ void BKE_image_stamp_buf( /* and draw the text. */ BLF_position(mono, x, y + y_ofs, 0.0); - BLF_draw_buffer(mono, stamp_data.file); + BLF_draw_buffer(mono, stamp_data.file, BLF_DRAW_STR_DUMMY_MAX); /* the extra pixel for background. */ y -= BUFF_MARGIN_Y * 2; } /* Top left corner, below File */ - if (TEXT_SIZE_CHECK(stamp_data.note, w, h)) { + if (TEXT_SIZE_CHECK(stamp_data.date, w, h)) { y -= h; /* and space for background. */ @@ -1932,14 +1930,14 @@ void BKE_image_stamp_buf( 0, y - BUFF_MARGIN_Y, w + BUFF_MARGIN_X, y + h + BUFF_MARGIN_Y); BLF_position(mono, x, y + y_ofs, 0.0); - BLF_draw_buffer(mono, stamp_data.note); + BLF_draw_buffer(mono, stamp_data.date, BLF_DRAW_STR_DUMMY_MAX); /* the extra pixel for background. */ y -= BUFF_MARGIN_Y * 2; } - /* Top left corner, below File (or Note) */ - if (TEXT_SIZE_CHECK(stamp_data.date, w, h)) { + /* Top left corner, below File, Date */ + if (TEXT_SIZE_CHECK(stamp_data.rendertime, w, h)) { y -= h; /* and space for background. */ @@ -1947,23 +1945,25 @@ void BKE_image_stamp_buf( 0, y - BUFF_MARGIN_Y, w + BUFF_MARGIN_X, y + h + BUFF_MARGIN_Y); BLF_position(mono, x, y + y_ofs, 0.0); - BLF_draw_buffer(mono, stamp_data.date); + BLF_draw_buffer(mono, stamp_data.rendertime, BLF_DRAW_STR_DUMMY_MAX); /* the extra pixel for background. */ y -= BUFF_MARGIN_Y * 2; } - /* Top left corner, below File, Date or Note */ - if (TEXT_SIZE_CHECK(stamp_data.rendertime, w, h)) { + /* Top left corner, below File, Date, Rendertime */ + BLF_enable(mono, BLF_WORD_WRAP); + if (TEXT_SIZE_CHECK_WORD_WRAP(stamp_data.note, w, h)) { y -= h; /* and space for background. */ buf_rectfill_area(rect, rectf, width, height, scene->r.bg_stamp, display, 0, y - BUFF_MARGIN_Y, w + BUFF_MARGIN_X, y + h + BUFF_MARGIN_Y); - BLF_position(mono, x, y + y_ofs, 0.0); - BLF_draw_buffer(mono, stamp_data.rendertime); + BLF_position(mono, x, y + y_ofs + (h - h_fixed), 0.0); + BLF_draw_buffer(mono, stamp_data.note, BLF_DRAW_STR_DUMMY_MAX); } + BLF_disable(mono, BLF_WORD_WRAP); x = 0; y = 0; @@ -1977,7 +1977,7 @@ void BKE_image_stamp_buf( /* and pad the text. */ BLF_position(mono, x, y + y_ofs, 0.0); - BLF_draw_buffer(mono, stamp_data.marker); + BLF_draw_buffer(mono, stamp_data.marker, BLF_DRAW_STR_DUMMY_MAX); /* space width. */ x += w + pad; @@ -1992,7 +1992,7 @@ void BKE_image_stamp_buf( /* and pad the text. */ BLF_position(mono, x, y + y_ofs, 0.0); - BLF_draw_buffer(mono, stamp_data.time); + BLF_draw_buffer(mono, stamp_data.time, BLF_DRAW_STR_DUMMY_MAX); /* space width. */ x += w + pad; @@ -2006,7 +2006,7 @@ void BKE_image_stamp_buf( /* and pad the text. */ BLF_position(mono, x, y + y_ofs, 0.0); - BLF_draw_buffer(mono, stamp_data.frame); + BLF_draw_buffer(mono, stamp_data.frame, BLF_DRAW_STR_DUMMY_MAX); /* space width. */ x += w + pad; @@ -2018,7 +2018,7 @@ void BKE_image_stamp_buf( buf_rectfill_area(rect, rectf, width, height, scene->r.bg_stamp, display, x - BUFF_MARGIN_X, y - BUFF_MARGIN_Y, x + w + BUFF_MARGIN_X, y + h + BUFF_MARGIN_Y); BLF_position(mono, x, y + y_ofs, 0.0); - BLF_draw_buffer(mono, stamp_data.camera); + BLF_draw_buffer(mono, stamp_data.camera, BLF_DRAW_STR_DUMMY_MAX); /* space width. */ x += w + pad; @@ -2030,7 +2030,7 @@ void BKE_image_stamp_buf( buf_rectfill_area(rect, rectf, width, height, scene->r.bg_stamp, display, x - BUFF_MARGIN_X, y - BUFF_MARGIN_Y, x + w + BUFF_MARGIN_X, y + h + BUFF_MARGIN_Y); BLF_position(mono, x, y + y_ofs, 0.0); - BLF_draw_buffer(mono, stamp_data.cameralens); + BLF_draw_buffer(mono, stamp_data.cameralens, BLF_DRAW_STR_DUMMY_MAX); } if (TEXT_SIZE_CHECK(stamp_data.scene, w, h)) { @@ -2044,7 +2044,7 @@ void BKE_image_stamp_buf( /* and pad the text. */ BLF_position(mono, x, y + y_ofs, 0.0); - BLF_draw_buffer(mono, stamp_data.scene); + BLF_draw_buffer(mono, stamp_data.scene, BLF_DRAW_STR_DUMMY_MAX); } if (TEXT_SIZE_CHECK(stamp_data.strip, w, h)) { @@ -2058,13 +2058,15 @@ void BKE_image_stamp_buf( x - BUFF_MARGIN_X, y - BUFF_MARGIN_Y, x + w + BUFF_MARGIN_X, y + h + BUFF_MARGIN_Y); BLF_position(mono, x, y + y_ofs, 0.0); - BLF_draw_buffer(mono, stamp_data.strip); + BLF_draw_buffer(mono, stamp_data.strip, BLF_DRAW_STR_DUMMY_MAX); } /* cleanup the buffer. */ BLF_buffer(mono, NULL, NULL, 0, 0, 0, NULL); + BLF_wordwrap(mono, 0); #undef TEXT_SIZE_CHECK +#undef TEXT_SIZE_CHECK_WORD_WRAP #undef BUFF_MARGIN_X #undef BUFF_MARGIN_Y } @@ -2474,15 +2476,8 @@ void BKE_image_verify_viewer_views(const RenderData *rd, Image *ima, ImageUser * BLI_lock_thread(LOCK_DRAW_IMAGE); - if (BKE_scene_multiview_is_stereo3d(rd)) { - ima->flag |= IMA_IS_STEREO; - ima->flag |= IMA_IS_MULTIVIEW; - } - else { - ima->flag &= ~IMA_IS_STEREO; - ima->flag &= ~IMA_IS_MULTIVIEW; + if (!BKE_scene_multiview_is_stereo3d(rd)) iuser->flag &= ~IMA_SHOW_STEREO; - } /* see if all scene render views are in the image view list */ do_reset = (BKE_scene_multiview_num_views_get(rd) != BLI_listbase_count(&ima->views)); @@ -2528,6 +2523,17 @@ void BKE_image_walk_all_users(const Main *mainp, void *customdata, if (tex->type == TEX_IMAGE && tex->ima) { callback(tex->ima, &tex->iuser, customdata); } + + if (tex->nodetree) { + bNode *node; + for (node = tex->nodetree->nodes.first; node; node = node->next) { + if (node->id && node->type == TEX_NODE_IMAGE) { + Image *ima = (Image *)node->id; + ImageUser *iuser = node->storage; + callback(ima, iuser, customdata); + } + } + } } /* image window, compo node users */ @@ -2578,21 +2584,10 @@ static void image_init_imageuser(Image *ima, ImageUser *iuser) RenderResult *rr = ima->rr; iuser->multi_index = 0; - iuser->layer = iuser->view = 0; - iuser->passtype = SCE_PASS_COMBINED; - - if (rr) { - RenderLayer *rl = rr->layers.first; - - if (rl) { - RenderPass *rp = rl->passes.first; - - if (rp) - iuser->passtype = rp->passtype; - } + iuser->layer = iuser->pass = iuser->view = 0; + if (rr) BKE_image_multilayer_index(rr, iuser); - } } void BKE_image_init_imageuser(Image *ima, ImageUser *iuser) @@ -2740,6 +2735,52 @@ void BKE_image_signal(Image *ima, ImageUser *iuser, int signal) } } +#define PASSTYPE_UNSET -1 +/* return renderpass for a given pass index and active view */ +/* fallback to available if there are missing passes for active view */ +static RenderPass *image_render_pass_get(RenderLayer *rl, const int pass, const int view, int *r_passindex) +{ + RenderPass *rpass_ret = NULL; + RenderPass *rpass; + + int rp_index = 0; + int rp_passtype = PASSTYPE_UNSET; + + for (rpass = rl->passes.first; rpass; rpass = rpass->next, rp_index++) { + if (rp_index == pass) { + rpass_ret = rpass; + if (view == 0) { + /* no multiview or left eye */ + break; + } + else { + rp_passtype = rpass->passtype; + } + } + /* multiview */ + else if ((rp_passtype != PASSTYPE_UNSET) && + (rpass->passtype == rp_passtype) && + (rpass->view_id == view)) + { + rpass_ret = rpass; + break; + } + } + + /* fallback to the first pass in the layer */ + if (rpass_ret == NULL) { + rp_index = 0; + rpass_ret = rl->passes.first; + } + + if (r_passindex) { + *r_passindex = (rpass == rpass_ret ? rp_index : pass); + } + + return rpass_ret; +} +#undef PASSTYPE_UNSET + /* if layer or pass changes, we need an index for the imbufs list */ /* note it is called for rendered results, but it doesnt use the index! */ /* and because rendered results use fake layer/passes, don't correct for wrong indices here */ @@ -2759,27 +2800,16 @@ RenderPass *BKE_image_multilayer_index(RenderResult *rr, ImageUser *iuser) if (RE_HasFakeLayer(rr)) rl_index += 1; for (rl = rr->layers.first; rl; rl = rl->next, rl_index++) { - for (rpass = rl->passes.first; rpass; rpass = rpass->next, index++) { - if (iuser->layer == rl_index && - iuser->passtype == rpass->passtype && - rv_index == rpass->view_id) - { - break; - } - } - if (rpass) + if (iuser->layer == rl_index) { + int rp_index; + rpass = image_render_pass_get(rl, iuser->pass, rv_index, &rp_index); + iuser->multi_index = index + rp_index; break; + } + else { + index += BLI_listbase_count(&rl->passes); + } } - iuser->multi_index = (rpass ? index : 0); - } - - if (rpass == NULL) { - rl = rr->layers.first; - if (rl) - rpass = rl->passes.first; - - if (rpass && iuser) - iuser->passtype = rpass->passtype; } return rpass; @@ -2788,7 +2818,7 @@ RenderPass *BKE_image_multilayer_index(RenderResult *rr, ImageUser *iuser) void BKE_image_multiview_index(Image *ima, ImageUser *iuser) { if (iuser) { - bool is_stereo = (ima->flag & IMA_IS_STEREO) && (iuser->flag & IMA_SHOW_STEREO); + bool is_stereo = BKE_image_is_stereo(ima) && (iuser->flag & IMA_SHOW_STEREO); if (is_stereo) { iuser->multi_index = iuser->multiview_eye; } @@ -2821,27 +2851,27 @@ bool BKE_image_is_multilayer(Image *ima) return false; } -static void image_init_multilayer_multiview_flag(Image *ima, RenderResult *rr) +bool BKE_image_is_multiview(Image *ima) +{ + return (BLI_listbase_count_ex(&ima->views, 2) > 1); +} + +bool BKE_image_is_stereo(Image *ima) +{ + return BKE_image_is_multiview(ima) && + (BLI_findstring(&ima->views, STEREO_LEFT_NAME, offsetof(ImageView, name)) && + BLI_findstring(&ima->views, STEREO_RIGHT_NAME, offsetof(ImageView, name))); +} + +static void image_init_multilayer_multiview(Image *ima, RenderResult *rr) { + BKE_image_free_views(ima); if (rr) { - if (RE_RenderResult_is_stereo(rr)) { - ima->flag |= IMA_IS_STEREO; - ima->flag |= IMA_IS_MULTIVIEW; - } - else { - ima->flag &= ~IMA_IS_STEREO; - if (BLI_listbase_count_ex(&rr->views, 2) > 1) - ima->flag |= IMA_IS_MULTIVIEW; - else - ima->flag &= ~IMA_IS_MULTIVIEW; - } - } - else { - ima->flag &= ~IMA_IS_STEREO; - ima->flag &= ~IMA_IS_MULTIVIEW; + BLI_duplicatelist(&ima->views, &rr->views); } } + RenderResult *BKE_image_acquire_renderresult(Scene *scene, Image *ima) { RenderResult *rr = NULL; @@ -2854,8 +2884,8 @@ RenderResult *BKE_image_acquire_renderresult(Scene *scene, Image *ima) else rr = ima->renders[ima->render_slot]; - /* set proper multiview flag */ - image_init_multilayer_multiview_flag(ima, rr); + /* set proper views */ + image_init_multilayer_multiview(ima, rr); } return rr; @@ -3013,39 +3043,15 @@ static void image_add_buffer_cb(void *base, const char *str, ImBuf *ibuf, const } #endif /* WITH_OPENEXR */ -#ifdef WITH_OPENEXR -static void image_update_multiview_flags(Image *ima) -{ - if (BLI_listbase_count_ex(&ima->views, 2) > 1) { - ima->flag |= IMA_IS_MULTIVIEW; - - if (BLI_findstring(&ima->views, STEREO_LEFT_NAME, offsetof(ImageView, name)) && - BLI_findstring(&ima->views, STEREO_RIGHT_NAME, offsetof(ImageView, name))) - { - ima->flag |= IMA_IS_STEREO; - } - else { - ima->flag &= ~IMA_IS_STEREO; - } - } - else { - ima->flag &= ~IMA_IS_STEREO; - ima->flag &= ~IMA_IS_MULTIVIEW; - } -} -#endif /* WITH_OPENEXR */ - /* after imbuf load, openexr type can return with a exrhandle open */ /* in that case we have to build a render-result */ #ifdef WITH_OPENEXR static void image_create_multiview(Image *ima, ImBuf *ibuf, const int frame) { - image_free_views(ima); + BKE_image_free_views(ima); IMB_exr_multiview_convert(ibuf->userdata, ima, image_add_view_cb, image_add_buffer_cb, frame); - image_update_multiview_flags(ima); - IMB_exr_close(ibuf->userdata); } #endif /* WITH_OPENEXR */ @@ -3058,7 +3064,9 @@ static void image_create_multilayer(Image *ima, ImBuf *ibuf, int framenr) const char *colorspace = ima->colorspace_settings.name; bool predivide = (ima->alpha_mode == IMA_ALPHA_PREMUL); - ima->rr = RE_MultilayerConvert(ibuf->userdata, colorspace, predivide, ibuf->x, ibuf->y); + /* only load rr once for multiview */ + if (!ima->rr) + ima->rr = RE_MultilayerConvert(ibuf->userdata, colorspace, predivide, ibuf->x, ibuf->y); IMB_exr_close(ibuf->userdata); @@ -3066,8 +3074,8 @@ static void image_create_multilayer(Image *ima, ImBuf *ibuf, int framenr) if (ima->rr) ima->rr->framenr = framenr; - /* set proper multiview flag */ - image_init_multilayer_multiview_flag(ima, ima->rr); + /* set proper views */ + image_init_multilayer_multiview(ima, ima->rr); } #endif /* WITH_OPENEXR */ @@ -3105,7 +3113,7 @@ static int imbuf_alpha_flags_for_image(Image *ima) /* the number of files will vary according to the stereo format */ static size_t image_num_files(Image *ima) { - const bool is_multiview = (ima->flag & IMA_IS_MULTIVIEW) != 0; + const bool is_multiview = BKE_image_is_multiview(ima); if (!is_multiview) { return 1; @@ -3187,7 +3195,7 @@ static ImBuf *load_sequence_single(Image *ima, ImageUser *iuser, int frame, cons static ImBuf *image_load_sequence_file(Image *ima, ImageUser *iuser, int frame) { struct ImBuf *ibuf = NULL; - const bool is_multiview = (ima->flag & IMA_IS_MULTIVIEW) != 0; + const bool is_multiview = BKE_image_is_multiview(ima); const size_t totfiles = image_num_files(ima); bool assign = false; @@ -3207,7 +3215,7 @@ static ImBuf *image_load_sequence_file(Image *ima, ImageUser *iuser, int frame) for (i = 0; i < totfiles; i++) ibuf_arr[i] = load_sequence_single(ima, iuser, frame, i, &assign); - if ((ima->flag & IMA_IS_STEREO) && ima->views_format == R_IMF_VIEWS_STEREO_3D) + if (BKE_image_is_stereo(ima) && ima->views_format == R_IMF_VIEWS_STEREO_3D) IMB_ImBufFromStereo3d(ima->stereo3d_format, ibuf_arr[0], &ibuf_arr[0], &ibuf_arr[1]); /* return the original requested ImBuf */ @@ -3344,7 +3352,7 @@ static ImBuf *load_movie_single(Image *ima, ImageUser *iuser, int frame, const s static ImBuf *image_load_movie_file(Image *ima, ImageUser *iuser, int frame) { struct ImBuf *ibuf = NULL; - const bool is_multiview = (ima->flag & IMA_IS_MULTIVIEW) != 0; + const bool is_multiview = BKE_image_is_multiview(ima); const size_t totfiles = image_num_files(ima); size_t i; @@ -3372,7 +3380,7 @@ static ImBuf *image_load_movie_file(Image *ima, ImageUser *iuser, int frame) ibuf_arr[i] = load_movie_single(ima, iuser, frame, i); } - if ((ima->flag & IMA_IS_STEREO) && ima->views_format == R_IMF_VIEWS_STEREO_3D) + if (BKE_image_is_stereo(ima) && ima->views_format == R_IMF_VIEWS_STEREO_3D) IMB_ImBufFromStereo3d(ima->stereo3d_format, ibuf_arr[0], &ibuf_arr[0], &ibuf_arr[1]); for (i = 0; i < totviews; i++) { @@ -3500,7 +3508,7 @@ static ImBuf *image_load_image_file(Image *ima, ImageUser *iuser, int cfra) { struct ImBuf *ibuf = NULL; bool assign = false; - const bool is_multiview = (ima->flag & IMA_IS_MULTIVIEW) != 0; + const bool is_multiview = BKE_image_is_multiview(ima); const size_t totfiles = image_num_files(ima); bool has_packed = BKE_image_has_packedfile(ima); @@ -3533,7 +3541,7 @@ static ImBuf *image_load_image_file(Image *ima, ImageUser *iuser, int cfra) ibuf_arr[i] = load_image_single(ima, iuser, cfra, i, has_packed, &assign); /* multi-views/multi-layers OpenEXR files directly populate ima, and return NULL ibuf... */ - if ((ima->flag & IMA_IS_STEREO) && ima->views_format == R_IMF_VIEWS_STEREO_3D && + if (BKE_image_is_stereo(ima) && ima->views_format == R_IMF_VIEWS_STEREO_3D && ibuf_arr[0] && totfiles == 1 && totviews >= 2) { IMB_ImBufFromStereo3d(ima->stereo3d_format, ibuf_arr[0], &ibuf_arr[0], &ibuf_arr[1]); @@ -3613,7 +3621,7 @@ static ImBuf *image_get_render_result(Image *ima, ImageUser *iuser, void **r_loc float *rectf, *rectz; unsigned int *rect; float dither; - int channels, layer, passtype; + int channels, layer, pass; ImBuf *ibuf; int from_render = (ima->render_slot == ima->last_render_slot); int actview; @@ -3630,10 +3638,10 @@ static ImBuf *image_get_render_result(Image *ima, ImageUser *iuser, void **r_loc channels = 4; layer = iuser->layer; - passtype = iuser->passtype; + pass = iuser->pass; actview = iuser->view; - if ((ima->flag & IMA_IS_STEREO) && (iuser->flag & IMA_SHOW_STEREO)) + if (BKE_image_is_stereo(ima) && (iuser->flag & IMA_SHOW_STEREO)) actview = iuser->multiview_eye; if (from_render) { @@ -3693,19 +3701,10 @@ static ImBuf *image_get_render_result(Image *ima, ImageUser *iuser, void **r_loc else if (rres.layers.first) { RenderLayer *rl = BLI_findlink(&rres.layers, layer - (rres.have_combined ? 1 : 0)); if (rl) { - RenderPass *rpass; - - for (rpass = rl->passes.first; rpass; rpass = rpass->next) { - if (passtype == rpass->passtype && - actview == rpass->view_id) - { - break; - } - } - + RenderPass *rpass = image_render_pass_get(rl, pass, actview, NULL); if (rpass) { rectf = rpass->rect; - if (passtype == SCE_PASS_COMBINED) { + if (pass == 0) { if (rectf == NULL) { /* Happens when Save Buffers is enabled. * Use display buffer stored in the render layer. @@ -3816,12 +3815,12 @@ static size_t image_get_multiview_index(Image *ima, ImageUser *iuser) return iuser ? iuser->multi_index : index; } else if (is_backdrop) { - if ((ima->flag & IMA_IS_STEREO)) { + if (BKE_image_is_stereo(ima)) { /* backdrop hackaround (since there is no iuser */ return ima->eye; } } - else if ((ima->flag & IMA_IS_MULTIVIEW)) { + else if (BKE_image_is_multiview(ima)) { return iuser ? iuser->multi_index : index; } @@ -4310,9 +4309,12 @@ void BKE_image_update_frame(const Main *bmain, int cfra) void BKE_image_user_file_path(ImageUser *iuser, Image *ima, char *filepath) { - if ((ima->flag & IMA_IS_MULTIVIEW) && (ima->rr == NULL)) { + if (BKE_image_is_multiview(ima) && (ima->rr == NULL)) { ImageView *iv = BLI_findlink(&ima->views, iuser->view); - BLI_strncpy(filepath, iv->filepath, FILE_MAX); + if (iv->filepath[0]) + BLI_strncpy(filepath, iv->filepath, FILE_MAX); + else + BLI_strncpy(filepath, ima->name, FILE_MAX); } else { BLI_strncpy(filepath, ima->name, FILE_MAX); @@ -4442,14 +4444,7 @@ float *BKE_image_get_float_pixels_for_frame(struct Image *image, int frame) int BKE_image_sequence_guess_offset(Image *image) { - unsigned short numlen; - char head[FILE_MAX], tail[FILE_MAX]; - char num[FILE_MAX] = {0}; - - BLI_stringdec(image->name, head, tail, &numlen); - BLI_strncpy(num, image->name + strlen(head), numlen + 1); - - return atoi(num); + return BLI_stringdec(image->name, NULL, NULL, NULL); } bool BKE_image_has_anim(Image *ima) @@ -4607,15 +4602,12 @@ static void image_update_views_format(Image *ima, ImageUser *iuser) BKE_image_free_views(ima); if (!is_multiview) { - goto monoview; + /* nothing to do */ } else if (ima->views_format == R_IMF_VIEWS_STEREO_3D) { size_t i; const char *names[2] = {STEREO_LEFT_NAME, STEREO_RIGHT_NAME}; - ima->flag |= IMA_IS_MULTIVIEW; - ima->flag |= IMA_IS_STEREO; - for (i = 0; i < 2; i++) { image_add_view(ima, names[i], ima->name); } @@ -4630,7 +4622,8 @@ static void image_update_views_format(Image *ima, ImageUser *iuser) BKE_scene_multiview_view_prefix_get(scene, name, prefix, &ext); if (prefix[0] == '\0') { - goto monoview; + BKE_image_free_views(ima); + return; } /* create all the image views */ @@ -4666,15 +4659,7 @@ static void image_update_views_format(Image *ima, ImageUser *iuser) } /* all good */ - if (BLI_listbase_count_ex(&ima->views, 2) > 1) { - ima->flag |= IMA_IS_MULTIVIEW; - if (BKE_scene_multiview_is_stereo3d(&scene->r)) - ima->flag |= IMA_IS_STEREO; - } - else { -monoview: - ima->flag &= ~IMA_IS_STEREO; - ima->flag &= ~IMA_IS_MULTIVIEW; + if (!BKE_image_is_multiview(ima)) { BKE_image_free_views(ima); } } diff --git a/source/blender/blenkernel/intern/image_gen.c b/source/blender/blenkernel/intern/image_gen.c index 4f9ed5f258d..303d0c6adfc 100644 --- a/source/blender/blenkernel/intern/image_gen.c +++ b/source/blender/blenkernel/intern/image_gen.c @@ -309,26 +309,26 @@ static void checker_board_text(unsigned char *rect, float *rect_float, int width BLF_buffer_col(mono, 1.0, 1.0, 1.0, 1.0); BLF_position(mono, pen_x - outline, pen_y, 0.0); - BLF_draw_buffer(mono, text); + BLF_draw_buffer(mono, text, 2); BLF_position(mono, pen_x + outline, pen_y, 0.0); - BLF_draw_buffer(mono, text); + BLF_draw_buffer(mono, text, 2); BLF_position(mono, pen_x, pen_y - outline, 0.0); - BLF_draw_buffer(mono, text); + BLF_draw_buffer(mono, text, 2); BLF_position(mono, pen_x, pen_y + outline, 0.0); - BLF_draw_buffer(mono, text); + BLF_draw_buffer(mono, text, 2); BLF_position(mono, pen_x - outline, pen_y - outline, 0.0); - BLF_draw_buffer(mono, text); + BLF_draw_buffer(mono, text, 2); BLF_position(mono, pen_x + outline, pen_y + outline, 0.0); - BLF_draw_buffer(mono, text); + BLF_draw_buffer(mono, text, 2); BLF_position(mono, pen_x - outline, pen_y + outline, 0.0); - BLF_draw_buffer(mono, text); + BLF_draw_buffer(mono, text, 2); BLF_position(mono, pen_x + outline, pen_y - outline, 0.0); - BLF_draw_buffer(mono, text); + BLF_draw_buffer(mono, text, 2); BLF_buffer_col(mono, 0.0, 0.0, 0.0, 1.0); BLF_position(mono, pen_x, pen_y, 0.0); - BLF_draw_buffer(mono, text); + BLF_draw_buffer(mono, text, 2); text[1]++; } diff --git a/source/blender/blenkernel/intern/key.c b/source/blender/blenkernel/intern/key.c index b591dc19685..362f41335d2 100644 --- a/source/blender/blenkernel/intern/key.c +++ b/source/blender/blenkernel/intern/key.c @@ -58,6 +58,7 @@ #include "BKE_key.h" #include "BKE_lattice.h" #include "BKE_library.h" +#include "BKE_mesh.h" #include "BKE_editmesh.h" #include "BKE_scene.h" @@ -1392,26 +1393,51 @@ float *BKE_key_evaluate_object(Object *ob, int *r_totelem) return BKE_key_evaluate_object_ex(ob, r_totelem, NULL, 0); } -Key **BKE_key_from_object_p(Object *ob) +Key **BKE_key_from_id_p(ID *id) { - if (ob == NULL) - return NULL; - - if (ob->type == OB_MESH) { - Mesh *me = ob->data; - return &me->key; - } - else if (ELEM(ob->type, OB_CURVE, OB_SURF)) { - Curve *cu = ob->data; - return &cu->key; + switch (GS(id->name)) { + case ID_ME: + { + Mesh *me = (Mesh *)id; + return &me->key; + } + case ID_CU: + { + Curve *cu = (Curve *)id; + if (cu->vfont == NULL) { + return &cu->key; + } + break; + } + case ID_LT: + { + Lattice *lt = (Lattice *)id; + return <->key; + } } - else if (ob->type == OB_LATTICE) { - Lattice *lt = ob->data; - return <->key; + + return NULL; +} + +Key *BKE_key_from_id(ID *id) +{ + Key **key_p; + key_p = BKE_key_from_id_p(id); + if (key_p) { + return *key_p; } + return NULL; } +Key **BKE_key_from_object_p(Object *ob) +{ + if (ob == NULL || ob->data == NULL) + return NULL; + + return BKE_key_from_id_p(ob->data); +} + Key *BKE_key_from_object(Object *ob) { Key **key_p; @@ -1774,6 +1800,66 @@ void BKE_keyblock_convert_to_mesh(KeyBlock *kb, Mesh *me) } } +/** + * Computes normals (vertices, polygons and/or loops ones) of given mesh for given shape key. + * + * \param kb the KeyBlock to use to compute normals. + * \param mesh the Mesh to apply keyblock to. + * \param r_vertnors if non-NULL, an array of vectors, same length as number of vertices. + * \param r_polynors if non-NULL, an array of vectors, same length as number of polygons. + * \param r_loopnors if non-NULL, an array of vectors, same length as number of loops. + */ +void BKE_keyblock_mesh_calc_normals( + struct KeyBlock *kb, struct Mesh *mesh, + float (*r_vertnors)[3], float (*r_polynors)[3], float (*r_loopnors)[3]) +{ + /* We use a temp, shallow copy of mesh to work. */ + Mesh me; + bool free_polynors = false; + + if (r_vertnors == NULL && r_polynors == NULL && r_loopnors == NULL) { + return; + } + + me = *mesh; + me.mvert = MEM_dupallocN(mesh->mvert); + CustomData_reset(&me.vdata); + CustomData_reset(&me.edata); + CustomData_reset(&me.pdata); + CustomData_reset(&me.ldata); + CustomData_reset(&me.fdata); + + BKE_keyblock_convert_to_mesh(kb, &me); + + if (r_polynors == NULL && r_loopnors != NULL) { + r_polynors = MEM_mallocN(sizeof(float[3]) * me.totpoly, __func__); + free_polynors = true; + } + BKE_mesh_calc_normals_poly( + me.mvert, r_vertnors, me.totvert, me.mloop, me.mpoly, me.totloop, me.totpoly, r_polynors, false); + + if (r_loopnors) { + short (*clnors)[2] = CustomData_get_layer(&mesh->ldata, CD_CUSTOMLOOPNORMAL); /* May be NULL. */ + + BKE_mesh_normals_loop_split( + me.mvert, me.totvert, me.medge, me.totedge, + me.mloop, r_loopnors, me.totloop, me.mpoly, r_polynors, me.totpoly, + (me.flag & ME_AUTOSMOOTH) != 0, me.smoothresh, NULL, clnors, NULL); + } + + CustomData_free(&me.vdata, me.totvert); + CustomData_free(&me.edata, me.totedge); + CustomData_free(&me.pdata, me.totpoly); + CustomData_free(&me.ldata, me.totloop); + CustomData_free(&me.fdata, me.totface); + MEM_freeN(me.mvert); + + if (free_polynors) { + MEM_freeN(r_polynors); + } +} + + /************************* raw coords ************************/ void BKE_keyblock_update_from_vertcos(Object *ob, KeyBlock *kb, float (*vertCos)[3]) { diff --git a/source/blender/blenkernel/intern/lamp.c b/source/blender/blenkernel/intern/lamp.c index 44e35c645de..8e350896eb8 100644 --- a/source/blender/blenkernel/intern/lamp.c +++ b/source/blender/blenkernel/intern/lamp.c @@ -53,12 +53,10 @@ #include "BKE_main.h" #include "BKE_node.h" -Lamp *BKE_lamp_add(Main *bmain, const char *name) +void BKE_lamp_init(Lamp *la) { - Lamp *la; - - la = BKE_libblock_alloc(bmain, ID_LA, name); - + BLI_assert(MEMCMP_STRUCT_OFS_IS_ZERO(la, id)); + la->r = la->g = la->b = la->k = 1.0f; la->haint = la->energy = 1.0f; la->dist = 25.0f; @@ -100,6 +98,16 @@ Lamp *BKE_lamp_add(Main *bmain, const char *name) la->shadow_frustum_size = 10.0f; curvemapping_initialize(la->curfalloff); +} + +Lamp *BKE_lamp_add(Main *bmain, const char *name) +{ + Lamp *la; + + la = BKE_libblock_alloc(bmain, ID_LA, name); + + BKE_lamp_init(la); + return la; } diff --git a/source/blender/blenkernel/intern/lattice.c b/source/blender/blenkernel/intern/lattice.c index 009e1d20328..0e5228a6db4 100644 --- a/source/blender/blenkernel/intern/lattice.c +++ b/source/blender/blenkernel/intern/lattice.c @@ -251,12 +251,10 @@ void BKE_lattice_resize(Lattice *lt, int uNew, int vNew, int wNew, Object *ltOb) MEM_freeN(vertexCos); } -Lattice *BKE_lattice_add(Main *bmain, const char *name) +void BKE_lattice_init(Lattice *lt) { - Lattice *lt; - - lt = BKE_libblock_alloc(bmain, ID_LT, name); - + BLI_assert(MEMCMP_STRUCT_OFS_IS_ZERO(lt, id)); + lt->flag = LT_GRID; lt->typeu = lt->typev = lt->typew = KEY_BSPLINE; @@ -264,7 +262,16 @@ Lattice *BKE_lattice_add(Main *bmain, const char *name) lt->def = MEM_callocN(sizeof(BPoint), "lattvert"); /* temporary */ BKE_lattice_resize(lt, 2, 2, 2, NULL); /* creates a uniform lattice */ lt->actbp = LT_ACTBP_NONE; - +} + +Lattice *BKE_lattice_add(Main *bmain, const char *name) +{ + Lattice *lt; + + lt = BKE_libblock_alloc(bmain, ID_LT, name); + + BKE_lattice_init(lt); + return lt; } diff --git a/source/blender/blenkernel/intern/library.c b/source/blender/blenkernel/intern/library.c index 8bb2864a604..f8f92825479 100644 --- a/source/blender/blenkernel/intern/library.c +++ b/source/blender/blenkernel/intern/library.c @@ -59,6 +59,7 @@ #include "DNA_movieclip_types.h" #include "DNA_mask_types.h" #include "DNA_node_types.h" +#include "DNA_object_types.h" #include "DNA_scene_types.h" #include "DNA_screen_types.h" #include "DNA_speaker_types.h" @@ -95,6 +96,7 @@ #include "BKE_lamp.h" #include "BKE_lattice.h" #include "BKE_library.h" +#include "BKE_library_query.h" #include "BKE_linestyle.h" #include "BKE_mesh.h" #include "BKE_material.h" @@ -119,6 +121,9 @@ #include "RNA_access.h" +#include "IMB_imbuf.h" +#include "IMB_imbuf_types.h" + #ifdef WITH_PYTHON #include "BPY_extern.h" #endif @@ -644,7 +649,7 @@ int set_listbasepointers(Main *main, ListBase **lb) * Allocates and returns memory of the right size for the specified block type, * initialized to zero. */ -static ID *alloc_libblock_notest(short type) +void *BKE_libblock_alloc_notest(short type) { ID *id = NULL; @@ -766,7 +771,7 @@ void *BKE_libblock_alloc(Main *bmain, short type, const char *name) ID *id = NULL; ListBase *lb = which_libbase(bmain, type); - id = alloc_libblock_notest(type); + id = BKE_libblock_alloc_notest(type); if (id) { BKE_main_lock(bmain); BLI_addtail(lb, id); @@ -781,6 +786,121 @@ void *BKE_libblock_alloc(Main *bmain, short type, const char *name) return id; } +/** + * Initialize an ID of given type, such that it has valid 'empty' data. + * ID is assumed to be just calloc'ed. + */ +void BKE_libblock_init_empty(ID *id) +{ + /* Note that only ID types that are not valid when filled of zero should have a callback here. */ + switch (GS(id->name)) { + case ID_SCE: + BKE_scene_init((Scene *)id); + break; + case ID_LI: + /* Nothing to do. */ + break; + case ID_OB: + { + Object *ob = (Object *)id; + ob->type = OB_EMPTY; + BKE_object_init(ob); + break; + } + case ID_ME: + BKE_mesh_init((Mesh *)id); + break; + case ID_CU: + BKE_curve_init((Curve *)id); + break; + case ID_MB: + BKE_mball_init((MetaBall *)id); + break; + case ID_MA: + BKE_material_init((Material *)id); + break; + case ID_TE: + BKE_texture_default((Tex *)id); + break; + case ID_IM: + /* Image is a bit complicated, for now assume NULLified im is OK. */ + break; + case ID_LT: + BKE_lattice_init((Lattice *)id); + break; + case ID_LA: + BKE_lamp_init((Lamp *)id); + break; + case ID_SPK: + BKE_speaker_init((Speaker *)id); + break; + case ID_CA: + BKE_camera_init((Camera *)id); + break; + case ID_IP: + /* Should not be needed - animation from lib pre-2.5 is broken anyway. */ + BLI_assert(0); + break; + case ID_KE: + /* Shapekeys are a complex topic too - they depend on their 'user' data type... + * They are not linkable, though, so it should never reach here anyway. */ + BLI_assert(0); + break; + case ID_WO: + BKE_world_init((World *)id); + break; + case ID_SCR: + /* Nothing to do. */ + break; + case ID_VF: + BKE_vfont_init((VFont *)id); + break; + case ID_TXT: + BKE_text_init((Text *)id); + break; + case ID_SCRIPT: + BLI_assert(0); + break; + case ID_SO: + /* Another fuzzy case, think NULLified content is OK here... */ + break; + case ID_GR: + /* Nothing to do. */ + break; + case ID_AR: + /* Nothing to do. */ + break; + case ID_AC: + /* Nothing to do. */ + break; + case ID_NT: + ntreeInitDefault((bNodeTree *)id); + break; + case ID_BR: + BKE_brush_init((Brush *)id); + break; + case ID_PA: + /* Nothing to do. */ + break; + case ID_PC: + /* Nothing to do. */ + break; + case ID_WM: + /* We should never reach this. */ + BLI_assert(0); + break; + case ID_GD: + /* Nothing to do. */ + break; + case ID_MSK: + /* Nothing to do. */ + break; + case ID_LS: + BKE_linestyle_init((FreestyleLineStyle *)id); + break; + } +} + /* by spec, animdata is first item after ID */ /* and, trust that BKE_animdata_from_id() will only find AnimData for valid ID-types */ static void id_copy_animdata(ID *id, const bool do_action) @@ -834,7 +954,7 @@ void *BKE_libblock_copy_nolib(ID *id, const bool do_action) ID *idn; size_t idn_len; - idn = alloc_libblock_notest(GS(id->name)); + idn = BKE_libblock_alloc_notest(GS(id->name)); assert(idn != NULL); BLI_strncpy(idn->name, id->name, sizeof(idn->name)); @@ -861,6 +981,31 @@ void *BKE_libblock_copy(ID *id) return BKE_libblock_copy_ex(G.main, id); } +static bool id_relink_looper(void *UNUSED(user_data), ID **id_pointer, const int cd_flag) +{ + ID *id = *id_pointer; + if (id) { + /* See: NEW_ID macro */ + if (id->newid) { + BKE_library_update_ID_link_user(id->newid, id, cd_flag); + *id_pointer = id->newid; + } + else if (id->flag & LIB_NEW) { + id->flag &= ~LIB_NEW; + BKE_libblock_relink(id); + } + } + return true; +} + +void BKE_libblock_relink(ID *id) +{ + if (id->lib) + return; + + BKE_library_foreach_ID_link(id, id_relink_looper, NULL, 0); +} + static void BKE_library_free(Library *lib) { if (lib->packedfile) @@ -1097,6 +1242,8 @@ void BKE_main_free(Main *mainvar) ListBase *lbarray[MAX_LIBARRAY]; int a; + MEM_SAFE_FREE(mainvar->blen_thumb); + a = set_listbasepointers(mainvar, lbarray); while (a--) { ListBase *lb = lbarray[a]; @@ -1142,6 +1289,7 @@ void BKE_main_free(Main *mainvar) 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; default: BLI_assert(0); break; @@ -1166,6 +1314,74 @@ void BKE_main_unlock(struct Main *bmain) BLI_spin_unlock((SpinLock *) bmain->lock); } +/** + * Generates a raw .blend file thumbnail data from given image. + * + * \param bmain If not NULL, also store generated data in this Main. + * \param img ImBuf image to generate thumbnail data from. + * \return The generated .blend file raw thumbnail data. + */ +BlendThumbnail *BKE_main_thumbnail_from_imbuf(Main *bmain, ImBuf *img) +{ + BlendThumbnail *data = NULL; + + if (bmain) { + MEM_SAFE_FREE(bmain->blen_thumb); + } + + if (img) { + const size_t sz = BLEN_THUMB_MEMSIZE(img->x, img->y); + data = MEM_mallocN(sz, __func__); + + IMB_rect_from_float(img); /* Just in case... */ + data->width = img->x; + data->height = img->y; + memcpy(data->rect, img->rect, sz - sizeof(*data)); + } + + if (bmain) { + bmain->blen_thumb = data; + } + return data; +} + +/** + * Generates an image from raw .blend file thumbnail \a data. + * + * \param bmain Use this bmain->blen_thumb data if given \a data is NULL. + * \param data Raw .blend file thumbnail data. + * \return An ImBuf from given data, or NULL if invalid. + */ +ImBuf *BKE_main_thumbnail_to_imbuf(Main *bmain, BlendThumbnail *data) +{ + ImBuf *img = NULL; + + if (!data && bmain) { + data = bmain->blen_thumb; + } + + if (data) { + /* Note: we cannot use IMB_allocFromBuffer(), since it tries to dupalloc passed buffer, which will fail + * here (we do not want to pass the first two ints!). */ + img = IMB_allocImBuf((unsigned int)data->width, (unsigned int)data->height, 32, IB_rect | IB_metadata); + memcpy(img->rect, data->rect, BLEN_THUMB_MEMSIZE(data->width, data->height) - sizeof(*data)); + } + + return img; +} + +/** + * Generates an empty (black) thumbnail for given Main. + */ +void BKE_main_thumbnail_create(struct Main *bmain) +{ + MEM_SAFE_FREE(bmain->blen_thumb); + + bmain->blen_thumb = MEM_callocN(BLEN_THUMB_MEMSIZE(BLEN_THUMB_SIZE, BLEN_THUMB_SIZE), __func__); + bmain->blen_thumb->width = BLEN_THUMB_SIZE; + bmain->blen_thumb->height = BLEN_THUMB_SIZE; +} + /* ***************** ID ************************ */ ID *BKE_libblock_find_name_ex(struct Main *bmain, const short type, const char *name) { @@ -1620,7 +1836,7 @@ void rename_id(ID *id, const char *name) */ void name_uiprefix_id(char *name, const ID *id) { - name[0] = id->lib ? 'L' : ' '; + name[0] = id->lib ? (ID_MISSING(id) ? 'M' : 'L') : ' '; name[1] = (id->flag & LIB_FAKEUSER) ? 'F' : ((id->us == 0) ? '0' : ' '); name[2] = ' '; diff --git a/source/blender/blenkernel/intern/library_query.c b/source/blender/blenkernel/intern/library_query.c index 6d2e2f1ecd4..a800b3d8834 100644 --- a/source/blender/blenkernel/intern/library_query.c +++ b/source/blender/blenkernel/intern/library_query.c @@ -30,10 +30,12 @@ #include <stdlib.h> +#include "DNA_actuator_types.h" #include "DNA_anim_types.h" #include "DNA_brush_types.h" #include "DNA_camera_types.h" #include "DNA_constraint_types.h" +#include "DNA_controller_types.h" #include "DNA_group_types.h" #include "DNA_gpencil_types.h" #include "DNA_key_types.h" @@ -47,7 +49,9 @@ #include "DNA_mask_types.h" #include "DNA_node_types.h" #include "DNA_object_force.h" +#include "DNA_rigidbody_types.h" #include "DNA_scene_types.h" +#include "DNA_sensor_types.h" #include "DNA_sequence_types.h" #include "DNA_screen_types.h" #include "DNA_speaker_types.h" @@ -61,9 +65,12 @@ #include "BKE_animsys.h" #include "BKE_constraint.h" #include "BKE_fcurve.h" +#include "BKE_library.h" #include "BKE_library_query.h" #include "BKE_modifier.h" #include "BKE_particle.h" +#include "BKE_rigidbody.h" +#include "BKE_sca.h" #include "BKE_sequencer.h" #include "BKE_tracking.h" @@ -80,16 +87,19 @@ /* TODO(sergey): Make it less creepy without too much duplicated code.. */ \ return; \ } \ - } (void) 0 + } ((void)0) #define FOREACH_CALLBACK_INVOKE_ID(self_id, id, flag, callback, user_data, cb_flag) \ - FOREACH_CALLBACK_INVOKE_ID_PP(self_id, &(id), flag, callback, user_data, cb_flag) \ + { \ + CHECK_TYPE_ANY(id, ID *, void *); \ + FOREACH_CALLBACK_INVOKE_ID_PP(self_id, (ID **)&(id), flag, callback, user_data, cb_flag); \ + } ((void)0) #define FOREACH_CALLBACK_INVOKE(self_id, id_super, flag, callback, user_data, cb_flag) \ { \ CHECK_TYPE(&((id_super)->id), ID *); \ FOREACH_CALLBACK_INVOKE_ID_PP(self_id, (ID **)&id_super, flag, callback, user_data, cb_flag); \ - } (void) 0 + } ((void)0) typedef struct LibraryForeachIDData { ID *self_id; @@ -98,11 +108,18 @@ typedef struct LibraryForeachIDData { void *user_data; } LibraryForeachIDData; -static void library_foreach_modifiersForeachIDLink(void *user_data, Object *UNUSED(object), - ID **id_pointer) +static void library_foreach_rigidbodyworldSceneLooper( + struct RigidBodyWorld *UNUSED(rbw), ID **id_pointer, void *user_data, int cd_flag) { LibraryForeachIDData *data = (LibraryForeachIDData *) user_data; - FOREACH_CALLBACK_INVOKE_ID_PP(data->self_id, id_pointer, data->flag, data->callback, data->user_data, IDWALK_NOP); + FOREACH_CALLBACK_INVOKE_ID_PP(data->self_id, id_pointer, data->flag, data->callback, data->user_data, cd_flag); +} + +static void library_foreach_modifiersForeachIDLink( + void *user_data, Object *UNUSED(object), ID **id_pointer, int cd_flag) +{ + LibraryForeachIDData *data = (LibraryForeachIDData *) user_data; + FOREACH_CALLBACK_INVOKE_ID_PP(data->self_id, id_pointer, data->flag, data->callback, data->user_data, cd_flag); } static void library_foreach_constraintObjectLooper(bConstraint *UNUSED(con), ID **id_pointer, @@ -112,6 +129,34 @@ static void library_foreach_constraintObjectLooper(bConstraint *UNUSED(con), ID FOREACH_CALLBACK_INVOKE_ID_PP(data->self_id, id_pointer, data->flag, data->callback, data->user_data, IDWALK_NOP); } +static void library_foreach_particlesystemsObjectLooper( + ParticleSystem *UNUSED(psys), ID **id_pointer, void *user_data, int cd_flag) +{ + LibraryForeachIDData *data = (LibraryForeachIDData *) user_data; + FOREACH_CALLBACK_INVOKE_ID_PP(data->self_id, id_pointer, data->flag, data->callback, data->user_data, cd_flag); +} + +static void library_foreach_sensorsObjectLooper( + bSensor *UNUSED(sensor), ID **id_pointer, void *user_data, int cd_flag) +{ + LibraryForeachIDData *data = (LibraryForeachIDData *) user_data; + FOREACH_CALLBACK_INVOKE_ID_PP(data->self_id, id_pointer, data->flag, data->callback, data->user_data, cd_flag); +} + +static void library_foreach_controllersObjectLooper( + bController *UNUSED(controller), ID **id_pointer, void *user_data, int cd_flag) +{ + LibraryForeachIDData *data = (LibraryForeachIDData *) user_data; + FOREACH_CALLBACK_INVOKE_ID_PP(data->self_id, id_pointer, data->flag, data->callback, data->user_data, cd_flag); +} + +static void library_foreach_actuatorsObjectLooper( + bActuator *UNUSED(actuator), ID **id_pointer, void *user_data, int cd_flag) +{ + LibraryForeachIDData *data = (LibraryForeachIDData *) user_data; + FOREACH_CALLBACK_INVOKE_ID_PP(data->self_id, id_pointer, data->flag, data->callback, data->user_data, cd_flag); +} + static void library_foreach_animationData(LibraryForeachIDData *data, AnimData *adt) { FCurve *fcu; @@ -131,11 +176,10 @@ static void library_foreach_animationData(LibraryForeachIDData *data, AnimData * } } - static void library_foreach_mtex(LibraryForeachIDData *data, MTex *mtex) { FOREACH_CALLBACK_INVOKE(data->self_id, mtex->object, data->flag, data->callback, data->user_data, IDWALK_NOP); - FOREACH_CALLBACK_INVOKE(data->self_id, mtex->tex, data->flag, data->callback, data->user_data, IDWALK_NOP); + FOREACH_CALLBACK_INVOKE(data->self_id, mtex->tex, data->flag, data->callback, data->user_data, IDWALK_USER); } @@ -170,12 +214,15 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u case ID_SCE: { Scene *scene = (Scene *) id; + ToolSettings *toolsett = scene->toolsettings; SceneRenderLayer *srl; Base *base; CALLBACK_INVOKE(scene->camera, IDWALK_NOP); - CALLBACK_INVOKE(scene->world, IDWALK_NOP); + CALLBACK_INVOKE(scene->world, IDWALK_USER); CALLBACK_INVOKE(scene->set, IDWALK_NOP); + CALLBACK_INVOKE(scene->clip, IDWALK_NOP); + CALLBACK_INVOKE(scene->nodetree, IDWALK_NOP); if (scene->basact) { CALLBACK_INVOKE(scene->basact->object, IDWALK_NOP); } @@ -186,10 +233,10 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u FreestyleLineSet *fls; if (srl->mat_override) { - CALLBACK_INVOKE(srl->mat_override, IDWALK_NOP); + CALLBACK_INVOKE(srl->mat_override, IDWALK_USER); } if (srl->light_override) { - CALLBACK_INVOKE(srl->light_override, IDWALK_NOP); + CALLBACK_INVOKE(srl->light_override, IDWALK_USER); } for (fmc = srl->freestyleConfig.modules.first; fmc; fmc = fmc->next) { if (fmc->script) { @@ -198,10 +245,10 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u } for (fls = srl->freestyleConfig.linesets.first; fls; fls = fls->next) { if (fls->group) { - CALLBACK_INVOKE(fls->group, IDWALK_NOP); + CALLBACK_INVOKE(fls->group, IDWALK_USER); } if (fls->linestyle) { - CALLBACK_INVOKE(fls->linestyle, IDWALK_NOP); + CALLBACK_INVOKE(fls->linestyle, IDWALK_USER); } } } @@ -212,74 +259,136 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u { CALLBACK_INVOKE(seq->scene, IDWALK_NOP); CALLBACK_INVOKE(seq->scene_camera, IDWALK_NOP); - CALLBACK_INVOKE(seq->clip, IDWALK_NOP); - CALLBACK_INVOKE(seq->mask, IDWALK_NOP); + CALLBACK_INVOKE(seq->clip, IDWALK_USER); + CALLBACK_INVOKE(seq->mask, IDWALK_USER); + CALLBACK_INVOKE(seq->sound, IDWALK_USER); } SEQ_END } - CALLBACK_INVOKE(scene->gpd, IDWALK_NOP); + CALLBACK_INVOKE(scene->gpd, IDWALK_USER); for (base = scene->base.first; base; base = base->next) { - CALLBACK_INVOKE(base->object, IDWALK_NOP); + CALLBACK_INVOKE(base->object, IDWALK_USER); + } + + if (toolsett) { + CALLBACK_INVOKE(toolsett->skgen_template, IDWALK_NOP); + CALLBACK_INVOKE(toolsett->particle.scene, IDWALK_NOP); + CALLBACK_INVOKE(toolsett->particle.object, IDWALK_NOP); + CALLBACK_INVOKE(toolsett->particle.shape_object, IDWALK_NOP); + CALLBACK_INVOKE(toolsett->imapaint.stencil, IDWALK_NOP); + CALLBACK_INVOKE(toolsett->imapaint.clone, IDWALK_NOP); + CALLBACK_INVOKE(toolsett->imapaint.canvas, IDWALK_NOP); + if (toolsett->vpaint) { + CALLBACK_INVOKE(toolsett->vpaint->paint.brush, IDWALK_NOP); + CALLBACK_INVOKE(toolsett->vpaint->paint.palette, IDWALK_NOP); + } + if (toolsett->wpaint) { + CALLBACK_INVOKE(toolsett->wpaint->paint.brush, IDWALK_NOP); + CALLBACK_INVOKE(toolsett->wpaint->paint.palette, IDWALK_NOP); + } + if (toolsett->sculpt) { + CALLBACK_INVOKE(toolsett->sculpt->paint.brush, IDWALK_NOP); + CALLBACK_INVOKE(toolsett->sculpt->paint.palette, IDWALK_NOP); + CALLBACK_INVOKE(toolsett->sculpt->gravity_object, IDWALK_NOP); + } + if (toolsett->uvsculpt) { + CALLBACK_INVOKE(toolsett->uvsculpt->paint.brush, IDWALK_NOP); + CALLBACK_INVOKE(toolsett->uvsculpt->paint.palette, IDWALK_NOP); + } } + + if (scene->rigidbody_world) { + BKE_rigidbody_world_id_loop(scene->rigidbody_world, library_foreach_rigidbodyworldSceneLooper, &data); + } + break; } case ID_OB: { Object *object = (Object *) id; + ParticleSystem *psys; + + /* object data special case */ + if (object->type == OB_EMPTY) { + /* empty can have NULL or Image */ + CALLBACK_INVOKE_ID(object->data, IDWALK_USER); + } + else { + /* when set, this can't be NULL */ + if (object->data) { + CALLBACK_INVOKE_ID(object->data, IDWALK_USER | IDWALK_NEVER_NULL); + } + } + CALLBACK_INVOKE(object->parent, IDWALK_NOP); CALLBACK_INVOKE(object->track, IDWALK_NOP); - CALLBACK_INVOKE(object->proxy, IDWALK_NOP); + /* object->proxy is refcounted, but not object->proxy_group... *sigh* */ + CALLBACK_INVOKE(object->proxy, IDWALK_USER); CALLBACK_INVOKE(object->proxy_group, IDWALK_NOP); CALLBACK_INVOKE(object->proxy_from, IDWALK_NOP); - CALLBACK_INVOKE(object->poselib, IDWALK_NOP); + CALLBACK_INVOKE(object->poselib, IDWALK_USER); for (i = 0; i < object->totcol; i++) { - CALLBACK_INVOKE(object->mat[i], IDWALK_NOP); + CALLBACK_INVOKE(object->mat[i], IDWALK_USER); } - CALLBACK_INVOKE(object->gpd, IDWALK_NOP); - CALLBACK_INVOKE(object->dup_group, IDWALK_NOP); + CALLBACK_INVOKE(object->gpd, IDWALK_USER); + CALLBACK_INVOKE(object->dup_group, IDWALK_USER); + if (object->particlesystem.first) { - ParticleSystem *particle_system; - for (particle_system = object->particlesystem.first; - particle_system; - particle_system = particle_system->next) - { - CALLBACK_INVOKE(particle_system->target_ob, IDWALK_NOP); - CALLBACK_INVOKE(particle_system->parent, IDWALK_NOP); + ParticleSystem *psys; + for (psys = object->particlesystem.first; psys; psys = psys->next) { + CALLBACK_INVOKE(psys->target_ob, IDWALK_NOP); + CALLBACK_INVOKE(psys->parent, IDWALK_NOP); } } + if (object->pd) { + CALLBACK_INVOKE(object->pd->tex, IDWALK_USER); + CALLBACK_INVOKE(object->pd->f_source, IDWALK_NOP); + } + if (object->pose) { - bPoseChannel *pose_channel; - for (pose_channel = object->pose->chanbase.first; - pose_channel; - pose_channel = pose_channel->next) - { - CALLBACK_INVOKE(pose_channel->custom, IDWALK_NOP); - BKE_constraints_id_loop(&pose_channel->constraints, - library_foreach_constraintObjectLooper, - &data); + bPoseChannel *pchan; + for (pchan = object->pose->chanbase.first; pchan; pchan = pchan->next) { + CALLBACK_INVOKE(pchan->custom, IDWALK_USER); + BKE_constraints_id_loop(&pchan->constraints, library_foreach_constraintObjectLooper, &data); + } + } + + if (object->rigidbody_constraint) { + CALLBACK_INVOKE(object->rigidbody_constraint->ob1, IDWALK_NOP); + CALLBACK_INVOKE(object->rigidbody_constraint->ob2, IDWALK_NOP); + } + + if (object->lodlevels.first) { + LodLevel *level; + for (level = object->lodlevels.first; level; level = level->next) { + CALLBACK_INVOKE(level->source, IDWALK_NOP); } } - modifiers_foreachIDLink(object, - library_foreach_modifiersForeachIDLink, - &data); - BKE_constraints_id_loop(&object->constraints, - library_foreach_constraintObjectLooper, - &data); + modifiers_foreachIDLink(object, library_foreach_modifiersForeachIDLink, &data); + BKE_constraints_id_loop(&object->constraints, library_foreach_constraintObjectLooper, &data); + + for (psys = object->particlesystem.first; psys; psys = psys->next) { + BKE_particlesystem_id_loop(psys, library_foreach_particlesystemsObjectLooper, &data); + } + + BKE_sca_sensors_id_loop(&object->sensors, library_foreach_sensorsObjectLooper, &data); + BKE_sca_controllers_id_loop(&object->controllers, library_foreach_controllersObjectLooper, &data); + BKE_sca_actuators_id_loop(&object->actuators, library_foreach_actuatorsObjectLooper, &data); break; } case ID_ME: { Mesh *mesh = (Mesh *) id; - CALLBACK_INVOKE(mesh->texcomesh, IDWALK_NOP); - CALLBACK_INVOKE(mesh->key, IDWALK_NOP); + CALLBACK_INVOKE(mesh->texcomesh, IDWALK_USER); + CALLBACK_INVOKE(mesh->key, IDWALK_USER); for (i = 0; i < mesh->totcol; i++) { - CALLBACK_INVOKE(mesh->mat[i], IDWALK_NOP); + CALLBACK_INVOKE(mesh->mat[i], IDWALK_USER); } break; } @@ -290,14 +399,14 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u CALLBACK_INVOKE(curve->bevobj, IDWALK_NOP); CALLBACK_INVOKE(curve->taperobj, IDWALK_NOP); CALLBACK_INVOKE(curve->textoncurve, IDWALK_NOP); - CALLBACK_INVOKE(curve->key, IDWALK_NOP); + CALLBACK_INVOKE(curve->key, IDWALK_USER); for (i = 0; i < curve->totcol; i++) { - CALLBACK_INVOKE(curve->mat[i], IDWALK_NOP); + CALLBACK_INVOKE(curve->mat[i], IDWALK_USER); } - CALLBACK_INVOKE(curve->vfont, IDWALK_NOP); - CALLBACK_INVOKE(curve->vfontb, IDWALK_NOP); - CALLBACK_INVOKE(curve->vfonti, IDWALK_NOP); - CALLBACK_INVOKE(curve->vfontbi, IDWALK_NOP); + CALLBACK_INVOKE(curve->vfont, IDWALK_USER); + CALLBACK_INVOKE(curve->vfontb, IDWALK_USER); + CALLBACK_INVOKE(curve->vfonti, IDWALK_USER); + CALLBACK_INVOKE(curve->vfontbi, IDWALK_USER); break; } @@ -305,7 +414,7 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u { MetaBall *metaball = (MetaBall *) id; for (i = 0; i < metaball->totcol; i++) { - CALLBACK_INVOKE(metaball->mat[i], IDWALK_NOP); + CALLBACK_INVOKE(metaball->mat[i], IDWALK_USER); } break; } @@ -319,7 +428,7 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u } } CALLBACK_INVOKE(material->nodetree, IDWALK_NOP); - CALLBACK_INVOKE(material->group, IDWALK_NOP); + CALLBACK_INVOKE(material->group, IDWALK_USER); break; } @@ -327,14 +436,24 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u { Tex *texture = (Tex *) id; CALLBACK_INVOKE(texture->nodetree, IDWALK_NOP); - CALLBACK_INVOKE(texture->ima, IDWALK_NOP); + CALLBACK_INVOKE(texture->ima, IDWALK_USER); + if (texture->env) { + CALLBACK_INVOKE(texture->env->object, IDWALK_NOP); + CALLBACK_INVOKE(texture->env->ima, IDWALK_USER); + } + if (texture->pd) + CALLBACK_INVOKE(texture->pd->object, IDWALK_NOP); + if (texture->vd) + CALLBACK_INVOKE(texture->vd->object, IDWALK_NOP); + if (texture->ot) + CALLBACK_INVOKE(texture->ot->object, IDWALK_NOP); break; } case ID_LT: { Lattice *lattice = (Lattice *) id; - CALLBACK_INVOKE(lattice->key, IDWALK_NOP); + CALLBACK_INVOKE(lattice->key, IDWALK_USER); break; } @@ -367,7 +486,7 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u case ID_SCR: { bScreen *screen = (bScreen *) id; - CALLBACK_INVOKE(screen->scene, IDWALK_NOP); + CALLBACK_INVOKE(screen->scene, IDWALK_USER_ONE); break; } @@ -386,19 +505,16 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u case ID_SPK: { Speaker *speaker = (Speaker *) id; - CALLBACK_INVOKE(speaker->sound, IDWALK_NOP); + CALLBACK_INVOKE(speaker->sound, IDWALK_USER); break; } case ID_GR: { Group *group = (Group *) id; - GroupObject *group_object; - for (group_object = group->gobject.first; - group_object; - group_object = group_object->next) - { - CALLBACK_INVOKE(group_object->ob, IDWALK_NOP); + GroupObject *gob; + for (gob = group->gobject.first; gob; gob = gob->next) { + CALLBACK_INVOKE(gob->ob, IDWALK_NOP); } break; } @@ -407,8 +523,9 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u { bNodeTree *ntree = (bNodeTree *) id; bNode *node; + CALLBACK_INVOKE(ntree->gpd, IDWALK_USER); for (node = ntree->nodes.first; node; node = node->next) { - CALLBACK_INVOKE_ID(node->id, IDWALK_NOP); + CALLBACK_INVOKE_ID(node->id, IDWALK_USER); } break; } @@ -417,6 +534,8 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u { Brush *brush = (Brush *) id; CALLBACK_INVOKE(brush->toggle_brush, IDWALK_NOP); + CALLBACK_INVOKE(brush->clone.image, IDWALK_NOP); + CALLBACK_INVOKE(brush->paint_curve, IDWALK_USER); library_foreach_mtex(&data, &brush->mtex); library_foreach_mtex(&data, &brush->mask_mtex); break; @@ -424,13 +543,39 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u case ID_PA: { - ParticleSettings *particle_settings = (ParticleSettings *) id; - CALLBACK_INVOKE(particle_settings->dup_group, IDWALK_NOP); - CALLBACK_INVOKE(particle_settings->dup_ob, IDWALK_NOP); - CALLBACK_INVOKE(particle_settings->bb_ob, IDWALK_NOP); - if (particle_settings->effector_weights) { - CALLBACK_INVOKE(particle_settings->effector_weights->group, IDWALK_NOP); + ParticleSettings *psett = (ParticleSettings *) id; + CALLBACK_INVOKE(psett->dup_group, IDWALK_NOP); + CALLBACK_INVOKE(psett->dup_ob, IDWALK_NOP); + CALLBACK_INVOKE(psett->bb_ob, IDWALK_NOP); + + for (i = 0; i < MAX_MTEX; i++) { + if (psett->mtex[i]) { + library_foreach_mtex(&data, psett->mtex[i]); + } + } + + if (psett->effector_weights) { + CALLBACK_INVOKE(psett->effector_weights->group, IDWALK_NOP); + } + + if (psett->boids) { + BoidState *state; + BoidRule *rule; + + for (state = psett->boids->states.first; state; state = state->next) { + for (rule = state->rules.first; rule; rule = rule->next) { + if (rule->type == eBoidRuleType_Avoid) { + BoidRuleGoalAvoid *gabr = (BoidRuleGoalAvoid *)rule; + CALLBACK_INVOKE(gabr->ob, IDWALK_NOP); + } + else if (rule->type == eBoidRuleType_FollowLeader) { + BoidRuleFollowLeader *flbr = (BoidRuleFollowLeader *)rule; + CALLBACK_INVOKE(flbr->ob, IDWALK_NOP); + } + } + } } + break; } @@ -439,18 +584,14 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u MovieClip *clip = (MovieClip *) id; MovieTracking *tracking = &clip->tracking; MovieTrackingObject *object; - CALLBACK_INVOKE(clip->gpd, IDWALK_NOP); - for (object = tracking->objects.first; - object; - object = object->next) - { + + CALLBACK_INVOKE(clip->gpd, IDWALK_USER); + for (object = tracking->objects.first; object; object = object->next) { ListBase *tracksbase = BKE_tracking_object_get_tracks(tracking, object); MovieTrackingTrack *track; - for (track = tracksbase->first; - track; - track = track->next) - { - CALLBACK_INVOKE(track->gpd, IDWALK_NOP); + + for (track = tracksbase->first; track; track = track->next) { + CALLBACK_INVOKE(track->gpd, IDWALK_USER); } } break; @@ -460,20 +601,13 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u { Mask *mask = (Mask *) id; MaskLayer *mask_layer; - for (mask_layer = mask->masklayers.first; - mask_layer; - mask_layer = mask_layer->next) - { + for (mask_layer = mask->masklayers.first; mask_layer; mask_layer = mask_layer->next) { MaskSpline *mask_spline; - for (mask_spline = mask_layer->splines.first; - mask_spline; - mask_spline = mask_spline->next) - { - int i; + for (mask_spline = mask_layer->splines.first; mask_spline; mask_spline = mask_spline->next) { for (i = 0; i < mask_spline->tot_point; i++) { MaskSplinePoint *point = &mask_spline->points[i]; - CALLBACK_INVOKE_ID(point->parent.id, IDWALK_NOP); + CALLBACK_INVOKE_ID(point->parent.id, IDWALK_USER); } } } @@ -483,7 +617,7 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u case ID_LS: { FreestyleLineStyle *linestyle = (FreestyleLineStyle *) id; - LineStyleModifier *m; + LineStyleModifier *lsm; for (i = 0; i < MAX_MTEX; i++) { if (linestyle->mtex[i]) { library_foreach_mtex(&data, linestyle->mtex[i]); @@ -491,25 +625,25 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u } CALLBACK_INVOKE(linestyle->nodetree, IDWALK_NOP); - for (m = (LineStyleModifier *)linestyle->color_modifiers.first; m; m = m->next) { - if (m->type == LS_MODIFIER_DISTANCE_FROM_OBJECT) { - LineStyleColorModifier_DistanceFromObject *p = (LineStyleColorModifier_DistanceFromObject *)m; + for (lsm = linestyle->color_modifiers.first; lsm; lsm = lsm->next) { + if (lsm->type == LS_MODIFIER_DISTANCE_FROM_OBJECT) { + LineStyleColorModifier_DistanceFromObject *p = (LineStyleColorModifier_DistanceFromObject *)lsm; if (p->target) { CALLBACK_INVOKE(p->target, IDWALK_NOP); } } } - for (m = (LineStyleModifier *)linestyle->alpha_modifiers.first; m; m = m->next) { - if (m->type == LS_MODIFIER_DISTANCE_FROM_OBJECT) { - LineStyleAlphaModifier_DistanceFromObject *p = (LineStyleAlphaModifier_DistanceFromObject *)m; + for (lsm = linestyle->alpha_modifiers.first; lsm; lsm = lsm->next) { + if (lsm->type == LS_MODIFIER_DISTANCE_FROM_OBJECT) { + LineStyleAlphaModifier_DistanceFromObject *p = (LineStyleAlphaModifier_DistanceFromObject *)lsm; if (p->target) { CALLBACK_INVOKE(p->target, IDWALK_NOP); } } } - for (m = (LineStyleModifier *)linestyle->thickness_modifiers.first; m; m = m->next) { - if (m->type == LS_MODIFIER_DISTANCE_FROM_OBJECT) { - LineStyleThicknessModifier_DistanceFromObject *p = (LineStyleThicknessModifier_DistanceFromObject *)m; + for (lsm = linestyle->thickness_modifiers.first; lsm; lsm = lsm->next) { + if (lsm->type == LS_MODIFIER_DISTANCE_FROM_OBJECT) { + LineStyleThicknessModifier_DistanceFromObject *p = (LineStyleThicknessModifier_DistanceFromObject *)lsm; if (p->target) { CALLBACK_INVOKE(p->target, IDWALK_NOP); } @@ -517,7 +651,6 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u } break; } - } #undef CALLBACK_INVOKE_ID @@ -526,3 +659,19 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u #undef FOREACH_CALLBACK_INVOKE_ID #undef FOREACH_CALLBACK_INVOKE + +/** + * re-usable function, use when replacing ID's + */ +void BKE_library_update_ID_link_user(ID *id_dst, ID *id_src, const int cd_flag) +{ + if (cd_flag & IDWALK_USER) { + id_us_min(id_src); + id_us_plus(id_dst); + } + else if (cd_flag & IDWALK_USER_ONE) { + if (id_dst->us == 0) { + id_us_plus(id_dst); + } + } +} diff --git a/source/blender/blenkernel/intern/linestyle.c b/source/blender/blenkernel/intern/linestyle.c index ac2c4e35dce..93d2b549fee 100644 --- a/source/blender/blenkernel/intern/linestyle.c +++ b/source/blender/blenkernel/intern/linestyle.c @@ -80,8 +80,10 @@ static const char *modifier_name[LS_MODIFIER_NUM] = { "3D Curvature", }; -static void default_linestyle_settings(FreestyleLineStyle *linestyle) +void BKE_linestyle_init(FreestyleLineStyle *linestyle) { + BLI_assert(MEMCMP_STRUCT_OFS_IS_ZERO(linestyle, id)); + linestyle->panel = LS_PANEL_STROKES; linestyle->r = linestyle->g = linestyle->b = 0.0f; linestyle->alpha = 1.0f; @@ -118,7 +120,7 @@ FreestyleLineStyle *BKE_linestyle_new(struct Main *bmain, const char *name) linestyle = (FreestyleLineStyle *)BKE_libblock_alloc(bmain, ID_LS, name); - default_linestyle_settings(linestyle); + BKE_linestyle_init(linestyle); return linestyle; } diff --git a/source/blender/blenkernel/intern/material.c b/source/blender/blenkernel/intern/material.c index fa0d34b8db6..a69b5fd87b5 100644 --- a/source/blender/blenkernel/intern/material.c +++ b/source/blender/blenkernel/intern/material.c @@ -78,7 +78,7 @@ Material defmaterial; /* called on startup, creator.c */ void init_def_material(void) { - init_material(&defmaterial); + BKE_material_init(&defmaterial); } /* not material itself */ @@ -122,8 +122,10 @@ void BKE_material_free_ex(Material *ma, bool do_id_user) GPU_material_free(&ma->gpumaterial); } -void init_material(Material *ma) +void BKE_material_init(Material *ma) { + BLI_assert(MEMCMP_STRUCT_OFS_IS_ZERO(ma, id)); + ma->r = ma->g = ma->b = ma->ref = 0.8; ma->specr = ma->specg = ma->specb = 1.0; ma->mirr = ma->mirg = ma->mirb = 1.0; @@ -221,7 +223,7 @@ Material *BKE_material_add(Main *bmain, const char *name) ma = BKE_libblock_alloc(bmain, ID_MA, name); - init_material(ma); + BKE_material_init(ma); return ma; } @@ -1078,7 +1080,10 @@ static void do_init_render_material(Material *ma, int r_mode, float *amb) static void init_render_nodetree(bNodeTree *ntree, Material *basemat, int r_mode, float *amb) { bNode *node; - + + /* parses the geom+tex nodes */ + ntreeShaderGetTexcoMode(ntree, r_mode, &basemat->texco, &basemat->mode_l); + for (node = ntree->nodes.first; node; node = node->next) { if (node->id) { if (GS(node->id->name) == ID_MA) { @@ -1115,9 +1120,6 @@ void init_render_material(Material *mat, int r_mode, float *amb) mat->mode_l = (mat->mode & MA_MODE_PIPELINE) | MA_SHLESS; mat->mode2_l = mat->mode2 & MA_MODE2_PIPELINE; - /* parses the geom+tex nodes */ - ntreeShaderGetTexcoMode(mat->nodetree, r_mode, &mat->texco, &mat->mode_l); - init_render_nodetree(mat->nodetree, mat, r_mode, amb); if (!mat->nodetree->execdata) diff --git a/source/blender/blenkernel/intern/mball.c b/source/blender/blenkernel/intern/mball.c index c09cd1aabdc..bd9fd331584 100644 --- a/source/blender/blenkernel/intern/mball.c +++ b/source/blender/blenkernel/intern/mball.c @@ -91,19 +91,26 @@ void BKE_mball_free(MetaBall *mb) if (mb->disp.first) BKE_displist_free(&mb->disp); } -MetaBall *BKE_mball_add(Main *bmain, const char *name) +void BKE_mball_init(MetaBall *mb) { - MetaBall *mb; - - mb = BKE_libblock_alloc(bmain, ID_MB, name); - + BLI_assert(MEMCMP_STRUCT_OFS_IS_ZERO(mb, id)); + mb->size[0] = mb->size[1] = mb->size[2] = 1.0; mb->texflag = MB_AUTOSPACE; mb->wiresize = 0.4f; mb->rendersize = 0.2f; mb->thresh = 0.6f; - +} + +MetaBall *BKE_mball_add(Main *bmain, const char *name) +{ + MetaBall *mb; + + mb = BKE_libblock_alloc(bmain, ID_MB, name); + + BKE_mball_init(mb); + return mb; } diff --git a/source/blender/blenkernel/intern/mesh.c b/source/blender/blenkernel/intern/mesh.c index f85e54a8362..318040db2be 100644 --- a/source/blender/blenkernel/intern/mesh.c +++ b/source/blender/blenkernel/intern/mesh.c @@ -490,12 +490,10 @@ static void mesh_tessface_clear_intern(Mesh *mesh, int free_customdata) mesh->totface = 0; } -Mesh *BKE_mesh_add(Main *bmain, const char *name) +void BKE_mesh_init(Mesh *me) { - Mesh *me; - - me = BKE_libblock_alloc(bmain, ID_ME, name); - + BLI_assert(MEMCMP_STRUCT_OFS_IS_ZERO(me, id)); + me->size[0] = me->size[1] = me->size[2] = 1.0; me->smoothresh = 30; me->texflag = ME_AUTOSPACE; @@ -511,6 +509,15 @@ Mesh *BKE_mesh_add(Main *bmain, const char *name) CustomData_reset(&me->fdata); CustomData_reset(&me->pdata); CustomData_reset(&me->ldata); +} + +Mesh *BKE_mesh_add(Main *bmain, const char *name) +{ + Mesh *me; + + me = BKE_libblock_alloc(bmain, ID_ME, name); + + BKE_mesh_init(me); return me; } @@ -2199,8 +2206,9 @@ void BKE_mesh_calc_normals_split(Mesh *mesh) } else { polynors = MEM_mallocN(sizeof(float[3]) * mesh->totpoly, __func__); - BKE_mesh_calc_normals_poly(mesh->mvert, mesh->totvert, mesh->mloop, mesh->mpoly, mesh->totloop, mesh->totpoly, - polynors, false); + BKE_mesh_calc_normals_poly( + mesh->mvert, NULL, mesh->totvert, + mesh->mloop, mesh->mpoly, mesh->totloop, mesh->totpoly, polynors, false); free_polynors = true; } @@ -2340,6 +2348,19 @@ Mesh *BKE_mesh_new_from_object( tmpcu = (Curve *)tmpobj->data; tmpcu->id.us--; + /* Copy cached display list, it might be needed by the stack evaluation. + * Ideally stack should be able to use render-time display list, but doing + * so is quite tricky and not safe so close to the release. + * + * TODO(sergey): Look into more proper solution. + */ + if (ob->curve_cache != NULL) { + if (tmpobj->curve_cache == NULL) { + tmpobj->curve_cache = MEM_callocN(sizeof(CurveCache), "CurveCache for curve types"); + } + BKE_displist_copy(&tmpobj->curve_cache->disp, &ob->curve_cache->disp); + } + /* if getting the original caged mesh, delete object modifiers */ if (cage) BKE_object_free_modifiers(tmpobj); diff --git a/source/blender/blenkernel/intern/mesh_evaluate.c b/source/blender/blenkernel/intern/mesh_evaluate.c index d4787bd250c..a65ac5151a8 100644 --- a/source/blender/blenkernel/intern/mesh_evaluate.c +++ b/source/blender/blenkernel/intern/mesh_evaluate.c @@ -51,6 +51,7 @@ #include "BLI_task.h" #include "BKE_customdata.h" +#include "BKE_global.h" #include "BKE_mesh.h" #include "BKE_multires.h" #include "BKE_report.h" @@ -132,7 +133,7 @@ void BKE_mesh_calc_normals_mapping_ex( if (only_face_normals == false) { /* vertex normals are optional, they require some extra calculations, * so make them optional */ - BKE_mesh_calc_normals_poly(mverts, numVerts, mloop, mpolys, numLoops, numPolys, pnors, false); + BKE_mesh_calc_normals_poly(mverts, NULL, numVerts, mloop, mpolys, numLoops, numPolys, pnors, false); } else { /* only calc poly normals */ @@ -221,18 +222,20 @@ static void mesh_calc_normals_poly_accum( } void BKE_mesh_calc_normals_poly( - MVert *mverts, int numVerts, + MVert *mverts, float (*r_vertnors)[3], int numVerts, const MLoop *mloop, const MPoly *mpolys, int UNUSED(numLoops), int numPolys, float (*r_polynors)[3], const bool only_face_normals) { float (*pnors)[3] = r_polynors; - float (*tnorms)[3]; + float (*vnors)[3] = r_vertnors; + bool free_vnors = false; int i; const MPoly *mp; if (only_face_normals) { BLI_assert((pnors != NULL) || (numPolys == 0)); + BLI_assert(r_vertnors == NULL); #pragma omp parallel for if (numPolys > BKE_MESH_OMP_LIMIT) for (i = 0; i < numPolys; i++) { @@ -242,25 +245,30 @@ void BKE_mesh_calc_normals_poly( } /* first go through and calculate normals for all the polys */ - tnorms = MEM_callocN(sizeof(*tnorms) * (size_t)numVerts, __func__); + if (vnors == NULL) { + vnors = MEM_callocN(sizeof(*vnors) * (size_t)numVerts, __func__); + free_vnors = true; + } + else { + memset(vnors, 0, sizeof(*vnors) * (size_t)numVerts); + } + mp = mpolys; if (pnors) { - mp = mpolys; for (i = 0; i < numPolys; i++, mp++) { - mesh_calc_normals_poly_accum(mp, mloop + mp->loopstart, mverts, pnors[i], tnorms); + mesh_calc_normals_poly_accum(mp, mloop + mp->loopstart, mverts, pnors[i], vnors); } } else { float tpnor[3]; /* temp poly normal */ - mp = mpolys; for (i = 0; i < numPolys; i++, mp++) { - mesh_calc_normals_poly_accum(mp, mloop + mp->loopstart, mverts, tpnor, tnorms); + mesh_calc_normals_poly_accum(mp, mloop + mp->loopstart, mverts, tpnor, vnors); } } for (i = 0; i < numVerts; i++) { MVert *mv = &mverts[i]; - float *no = tnorms[i]; + float *no = vnors[i]; if (UNLIKELY(normalize_v3(no) == 0.0f)) { /* following Mesh convention; we use vertex coordinate itself for normal in this case */ @@ -270,7 +278,9 @@ void BKE_mesh_calc_normals_poly( normal_float_to_short_v3(mv->no, no); } - MEM_freeN(tnorms); + if (free_vnors) { + MEM_freeN(vnors); + } } void BKE_mesh_calc_normals(Mesh *mesh) @@ -278,7 +288,7 @@ void BKE_mesh_calc_normals(Mesh *mesh) #ifdef DEBUG_TIME TIMEIT_START(BKE_mesh_calc_normals); #endif - BKE_mesh_calc_normals_poly(mesh->mvert, mesh->totvert, + BKE_mesh_calc_normals_poly(mesh->mvert, NULL, mesh->totvert, mesh->mloop, mesh->mpoly, mesh->totloop, mesh->totpoly, NULL, false); #ifdef DEBUG_TIME @@ -883,7 +893,9 @@ static void split_loop_nor_fan_do(LoopSplitTaskDataCommon *common_data, LoopSpli clnors_avg[0] /= clnors_nbr; clnors_avg[1] /= clnors_nbr; /* Fix/update all clnors of this fan with computed average value. */ - printf("Invalid clnors in this fan!\n"); + if (G.debug & G_DEBUG) { + printf("Invalid clnors in this fan!\n"); + } while ((clnor = BLI_SMALLSTACK_POP(clnors))) { //print_v2("org clnor", clnor); clnor[0] = (short)clnors_avg[0]; @@ -1338,12 +1350,14 @@ void BKE_mesh_normals_loop_split( * Compute internal representation of given custom normals (as an array of float[2]). * It also makes sure the mesh matches those custom normals, by setting sharp edges flag as needed to get a * same custom lnor for all loops sharing a same smooth fan. - * If use_vertices if true, custom_loopnors is assumed to be per-vertex, not per-loop + * If use_vertices if true, r_custom_loopnors is assumed to be per-vertex, not per-loop * (this allows to set whole vert's normals at once, useful in some cases). + * r_custom_loopnors is expected to have normalized normals, or zero ones, in which case they will be replaced + * by default loop/vertex normal. */ static void mesh_normals_loop_custom_set( const MVert *mverts, const int numVerts, MEdge *medges, const int numEdges, - MLoop *mloops, float (*custom_loopnors)[3], const int numLoops, + MLoop *mloops, float (*r_custom_loopnors)[3], const int numLoops, MPoly *mpolys, const float (*polynors)[3], const int numPolys, short (*r_clnors_data)[2], const bool use_vertices) { @@ -1369,6 +1383,22 @@ static void mesh_normals_loop_custom_set( mpolys, polynors, numPolys, use_split_normals, split_angle, &lnors_spacearr, NULL, loop_to_poly); + /* Set all given zero vectors to their default value. */ + if (use_vertices) { + for (i = 0; i < numVerts; i++) { + if (is_zero_v3(r_custom_loopnors[i])) { + normal_short_to_float_v3(r_custom_loopnors[i], mverts[i].no); + } + } + } + else { + for (i = 0; i < numLoops; i++) { + if (is_zero_v3(r_custom_loopnors[i])) { + copy_v3_v3(r_custom_loopnors[i], lnors[i]); + } + } + } + /* Now, check each current smooth fan (one lnor space per smooth fan!), and if all its matching custom lnors * are not (enough) equal, add sharp edges as needed. * This way, next time we run BKE_mesh_normals_loop_split(), we'll get lnor spacearr/smooth fans matching @@ -1384,7 +1414,9 @@ static void mesh_normals_loop_custom_set( * Maybe we should set those loops' edges as sharp? */ BLI_BITMAP_ENABLE(done_loops, i); - printf("WARNING! Getting invalid NULL loop space for loop %d!\n", i); + if (G.debug & G_DEBUG) { + printf("WARNING! Getting invalid NULL loop space for loop %d!\n", i); + } continue; } @@ -1406,11 +1438,7 @@ static void mesh_normals_loop_custom_set( const int lidx = GET_INT_FROM_POINTER(loops->link); MLoop *ml = &mloops[lidx]; const int nidx = lidx; - float *nor = custom_loopnors[nidx]; - - if (is_zero_v3(nor)) { - nor = lnors[nidx]; - } + float *nor = r_custom_loopnors[nidx]; if (!org_nor) { org_nor = nor; @@ -1432,7 +1460,26 @@ static void mesh_normals_loop_custom_set( loops = loops->next; BLI_BITMAP_ENABLE(done_loops, lidx); } - BLI_BITMAP_ENABLE(done_loops, i); /* For single loops, where lnors_spacearr.lspacearr[i]->loops is NULL. */ + + /* We also have to check between last and first loops, otherwise we may miss some sharp edges here! + * This is just a simplified version of above while loop. + * See T45984. */ + loops = lnors_spacearr.lspacearr[i]->loops; + if (loops && org_nor) { + const int lidx = GET_INT_FROM_POINTER(loops->link); + MLoop *ml = &mloops[lidx]; + const int nidx = lidx; + float *nor = r_custom_loopnors[nidx]; + + if (dot_v3v3(org_nor, nor) < LNOR_SPACE_TRIGO_THRESHOLD) { + const MPoly *mp = &mpolys[loop_to_poly[lidx]]; + const MLoop *mlp = &mloops[(lidx == mp->loopstart) ? mp->loopstart + mp->totloop - 1 : lidx - 1]; + medges[(prev_ml->e == mlp->e) ? prev_ml->e : ml->e].flag |= ME_SHARP; + } + } + + /* For single loops, where lnors_spacearr.lspacearr[i]->loops is NULL. */ + BLI_BITMAP_ENABLE(done_loops, i); } } @@ -1450,7 +1497,9 @@ static void mesh_normals_loop_custom_set( for (i = 0; i < numLoops; i++) { if (!lnors_spacearr.lspacearr[i]) { BLI_BITMAP_DISABLE(done_loops, i); - printf("WARNING! Still getting invalid NULL loop space in second loop for loop %d!\n", i); + if (G.debug & G_DEBUG) { + printf("WARNING! Still getting invalid NULL loop space in second loop for loop %d!\n", i); + } continue; } @@ -1469,11 +1518,7 @@ static void mesh_normals_loop_custom_set( while (loops) { const int lidx = GET_INT_FROM_POINTER(loops->link); const int nidx = use_vertices ? (int)mloops[lidx].v : lidx; - float *nor = custom_loopnors[nidx]; - - if (is_zero_v3(nor)) { - nor = lnors[nidx]; - } + float *nor = r_custom_loopnors[nidx]; nbr_nors++; add_v3_v3(avg_nor, nor); @@ -1493,7 +1538,7 @@ static void mesh_normals_loop_custom_set( } else { const int nidx = use_vertices ? (int)mloops[i].v : i; - float *nor = custom_loopnors[nidx]; + float *nor = r_custom_loopnors[nidx]; BKE_lnor_space_custom_normal_to_data(lnors_spacearr.lspacearr[i], nor, r_clnors_data[i]); BLI_BITMAP_DISABLE(done_loops, i); @@ -1509,21 +1554,21 @@ static void mesh_normals_loop_custom_set( void BKE_mesh_normals_loop_custom_set( const MVert *mverts, const int numVerts, MEdge *medges, const int numEdges, - MLoop *mloops, float (*custom_loopnors)[3], const int numLoops, + MLoop *mloops, float (*r_custom_loopnors)[3], const int numLoops, MPoly *mpolys, const float (*polynors)[3], const int numPolys, short (*r_clnors_data)[2]) { - mesh_normals_loop_custom_set(mverts, numVerts, medges, numEdges, mloops, custom_loopnors, numLoops, + mesh_normals_loop_custom_set(mverts, numVerts, medges, numEdges, mloops, r_custom_loopnors, numLoops, mpolys, polynors, numPolys, r_clnors_data, false); } void BKE_mesh_normals_loop_custom_from_vertices_set( - const MVert *mverts, float (*custom_vertnors)[3], const int numVerts, + const MVert *mverts, float (*r_custom_vertnors)[3], const int numVerts, MEdge *medges, const int numEdges, MLoop *mloops, const int numLoops, MPoly *mpolys, const float (*polynors)[3], const int numPolys, short (*r_clnors_data)[2]) { - mesh_normals_loop_custom_set(mverts, numVerts, medges, numEdges, mloops, custom_vertnors, numLoops, + mesh_normals_loop_custom_set(mverts, numVerts, medges, numEdges, mloops, r_custom_vertnors, numLoops, mpolys, polynors, numPolys, r_clnors_data, true); } @@ -1531,7 +1576,7 @@ void BKE_mesh_normals_loop_custom_from_vertices_set( * Computes average per-vertex normals from given custom loop normals. * * @param clnors The computed custom loop normals. - * @param r_vert_clnors The (already allocated) array wher to store averaged per-vertex normals. + * @param r_vert_clnors The (already allocated) array where to store averaged per-vertex normals. */ void BKE_mesh_normals_loop_to_vertex( const int numVerts, const MLoop *mloops, const int numLoops, @@ -3211,7 +3256,7 @@ void BKE_mesh_flush_hidden_from_polys_ex(MVert *mvert, j = mp->totloop; for (ml = &mloop[mp->loopstart]; j--; ml++) { mvert[ml->v].flag &= (char)~ME_HIDE; - medge[ml->e].flag &= (char)~ME_HIDE; + medge[ml->e].flag &= (short)~ME_HIDE; } } } diff --git a/source/blender/blenkernel/intern/mesh_mapping.c b/source/blender/blenkernel/intern/mesh_mapping.c index ef9136397fa..8dce3c372f6 100644 --- a/source/blender/blenkernel/intern/mesh_mapping.c +++ b/source/blender/blenkernel/intern/mesh_mapping.c @@ -65,7 +65,7 @@ UvVertMap *BKE_mesh_uv_vert_map_create( unsigned int a; int i, totuv, nverts; - bool *winding; + bool *winding = NULL; BLI_buffer_declare_static(vec2f, tf_uv_buf, BLI_BUFFER_NOP, 32); totuv = 0; @@ -94,10 +94,10 @@ UvVertMap *BKE_mesh_uv_vert_map_create( mp = mpoly; for (a = 0; a < totpoly; a++, mp++) { if (!selected || (!(mp->flag & ME_HIDE) && (mp->flag & ME_FACE_SEL))) { - float (*tf_uv)[2]; + float (*tf_uv)[2] = NULL; if (use_winding) { - tf_uv = (float (*)[2])BLI_buffer_resize_data(&tf_uv_buf, vec2f, mp->totloop); + tf_uv = (float (*)[2])BLI_buffer_reinit_data(&tf_uv_buf, vec2f, (size_t)mp->totloop); } nverts = mp->totloop; diff --git a/source/blender/blenkernel/intern/mesh_remap.c b/source/blender/blenkernel/intern/mesh_remap.c index 993921c22e0..258131f46ed 100644 --- a/source/blender/blenkernel/intern/mesh_remap.c +++ b/source/blender/blenkernel/intern/mesh_remap.c @@ -237,7 +237,7 @@ static void mesh_calc_eigen_matrix( /* Protect against 1D/2D degenerated cases! */ /* Note: not sure why we need square root of eigen values here (which are equivalent to singular values, - * as far as I have understood), but it seems to heavily reduce (if not completly nullify) + * as far as I have understood), but it seems to heavily reduce (if not completely nullify) * the error due to non-uniform scalings... */ evi = (evi < 1e-6f && evi > -1e-6f) ? ((evi < 0.0f) ? -1e-3f : 1e-3f) : sqrtf_signed(evi); mul_v3_fl(eigen_vec[i], evi); @@ -455,14 +455,13 @@ void BKE_mesh_remap_calc_verts_from_dm( BVHTreeNearest nearest = {0}; BVHTreeRayHit rayhit = {0}; float hit_dist; + float tmp_co[3], tmp_no[3]; if (mode == MREMAP_MODE_VERT_NEAREST) { bvhtree_from_mesh_verts(&treedata, dm_src, 0.0f, 2, 6); nearest.index = -1; for (i = 0; i < numverts_dst; i++) { - float tmp_co[3]; - copy_v3_v3(tmp_co, verts_dst[i].co); /* Convert the vertex to tree coordinates, if needed. */ @@ -488,8 +487,6 @@ void BKE_mesh_remap_calc_verts_from_dm( nearest.index = -1; for (i = 0; i < numverts_dst; i++) { - float tmp_co[3]; - copy_v3_v3(tmp_co, verts_dst[i].co); /* Convert the vertex to tree coordinates, if needed. */ @@ -548,8 +545,6 @@ void BKE_mesh_remap_calc_verts_from_dm( if (mode == MREMAP_MODE_VERT_POLYINTERP_VNORPROJ) { for (i = 0; i < numverts_dst; i++) { - float tmp_co[3], tmp_no[3]; - copy_v3_v3(tmp_co, verts_dst[i].co); normal_short_to_float_v3(tmp_no, verts_dst[i].no); @@ -580,8 +575,6 @@ void BKE_mesh_remap_calc_verts_from_dm( nearest.index = -1; for (i = 0; i < numverts_dst; i++) { - float tmp_co[3]; - copy_v3_v3(tmp_co, verts_dst[i].co); /* Convert the vertex to tree coordinates, if needed. */ @@ -656,6 +649,7 @@ void BKE_mesh_remap_calc_edges_from_dm( BVHTreeNearest nearest = {0}; BVHTreeRayHit rayhit = {0}; float hit_dist; + float tmp_co[3], tmp_no[3]; if (mode == MREMAP_MODE_EDGE_VERT_NEAREST) { const int num_verts_src = dm_src->getNumVerts(dm_src); @@ -694,8 +688,6 @@ void BKE_mesh_remap_calc_edges_from_dm( /* Compute closest verts only once! */ if (v_dst_to_src_map[vidx_dst].hit_dist == -1.0f) { - float tmp_co[3]; - copy_v3_v3(tmp_co, verts_dst[vidx_dst].co); /* Convert the vertex to tree coordinates, if needed. */ @@ -786,8 +778,6 @@ void BKE_mesh_remap_calc_edges_from_dm( nearest.index = -1; for (i = 0; i < numedges_dst; i++) { - float tmp_co[3]; - interp_v3_v3v3(tmp_co, verts_dst[edges_dst[i].v1].co, verts_dst[edges_dst[i].v2].co, 0.5f); /* Convert the vertex to tree coordinates, if needed. */ @@ -814,8 +804,6 @@ void BKE_mesh_remap_calc_edges_from_dm( bvhtree_from_mesh_looptri(&treedata, dm_src, 0.0f, 2, 6); for (i = 0; i < numedges_dst; i++) { - float tmp_co[3]; - interp_v3_v3v3(tmp_co, verts_dst[edges_dst[i].v1].co, verts_dst[edges_dst[i].v2].co, 0.5f); /* Convert the vertex to tree coordinates, if needed. */ @@ -872,8 +860,8 @@ void BKE_mesh_remap_calc_edges_from_dm( /* For each dst edge, we sample some rays from it (interpolated from its vertices) * and use their hits to interpolate from source edges. */ const MEdge *me = &edges_dst[i]; - float tmp_co[3], v1_co[3], v2_co[3]; - float tmp_no[3], v1_no[3], v2_no[3]; + float v1_co[3], v2_co[3]; + float v1_no[3], v2_no[3]; int grid_size; float edge_dst_len; @@ -1150,6 +1138,7 @@ void BKE_mesh_remap_calc_loops_from_dm( BVHTreeRayHit rayhit = {0}; int num_trees = 0; float hit_dist; + float tmp_co[3], tmp_no[3]; const bool use_from_vert = (mode & MREMAP_USE_VERT); @@ -1234,7 +1223,7 @@ void BKE_mesh_remap_calc_loops_from_dm( CustomData_set_layer_flag(pdata_dst, CD_NORMAL, CD_FLAG_TEMPORARY); } if (dirty_nors_dst) { - BKE_mesh_calc_normals_poly(verts_dst, numverts_dst, loops_dst, polys_dst, + BKE_mesh_calc_normals_poly(verts_dst, NULL, numverts_dst, loops_dst, polys_dst, numloops_dst, numpolys_dst, poly_nors_dst, true); } } @@ -1440,13 +1429,18 @@ void BKE_mesh_remap_calc_loops_from_dm( } for (pidx_dst = 0, mp_dst = polys_dst; pidx_dst < numpolys_dst; pidx_dst++, mp_dst++) { - float (*pnor_dst)[3] = &poly_nors_dst[pidx_dst]; + float pnor_dst[3]; /* Only in use_from_vert case, we may need polys' centers as fallback in case we cannot decide which * corner to use from normals only. */ float pcent_dst[3]; bool pcent_dst_valid = false; + if (mode == MREMAP_MODE_LOOP_NEAREST_POLYNOR) { + copy_v3_v3(pnor_dst, poly_nors_dst[pidx_dst]); + BLI_space_transform_apply_normal(space_transform, pnor_dst); + } + if ((size_t)mp_dst->totloop > islands_res_buff_size) { islands_res_buff_size = (size_t)mp_dst->totloop + MREMAP_DEFAULT_BUFSIZE; for (tindex = 0; tindex < num_trees; tindex++) { @@ -1460,7 +1454,6 @@ void BKE_mesh_remap_calc_loops_from_dm( ml_dst = &loops_dst[mp_dst->loopstart]; for (plidx_dst = 0; plidx_dst < mp_dst->totloop; plidx_dst++, ml_dst++) { if (use_from_vert) { - float tmp_co[3]; MeshElemMap *vert_to_refelem_map_src = NULL; copy_v3_v3(tmp_co, verts_dst[ml_dst->v].co); @@ -1479,12 +1472,14 @@ void BKE_mesh_remap_calc_loops_from_dm( int best_index_src = -1; if (mode == MREMAP_MODE_LOOP_NEAREST_LOOPNOR) { - nor_dst = &loop_nors_dst[plidx_dst + mp_dst->loopstart]; + copy_v3_v3(tmp_no, loop_nors_dst[plidx_dst + mp_dst->loopstart]); + BLI_space_transform_apply_normal(space_transform, tmp_no); + nor_dst = &tmp_no; nors_src = loop_nors_src; vert_to_refelem_map_src = vert_to_loop_map_src; } else { /* if (mode == MREMAP_MODE_LOOP_NEAREST_POLYNOR) { */ - nor_dst = pnor_dst; + nor_dst = &pnor_dst; nors_src = poly_nors_src; vert_to_refelem_map_src = vert_to_poly_map_src; } @@ -1556,8 +1551,6 @@ void BKE_mesh_remap_calc_loops_from_dm( } } else if (mode & MREMAP_USE_NORPROJ) { - float tmp_co[3], tmp_no[3]; - int n = (ray_radius > 0.0f) ? MREMAP_RAYCAST_APPROXIMATE_NR : 1; float w = 1.0f; @@ -1615,8 +1608,6 @@ void BKE_mesh_remap_calc_loops_from_dm( } } else { /* Nearest poly either to use all its loops/verts or just closest one. */ - float tmp_co[3]; - copy_v3_v3(tmp_co, verts_dst[ml_dst->v].co); nearest.index = -1; @@ -1739,7 +1730,6 @@ void BKE_mesh_remap_calc_loops_from_dm( * Note we could be much more subtle here, again that's for later... */ int j; float best_dist_sq = FLT_MAX; - float tmp_co[3]; ml_dst = &loops_dst[lidx_dst]; copy_v3_v3(tmp_co, verts_dst[ml_dst->v].co); @@ -1824,7 +1814,6 @@ void BKE_mesh_remap_calc_loops_from_dm( /* Find a new valid loop in that new poly (nearest point on poly for now). * Note we could be much more subtle here, again that's for later... */ float best_dist_sq = FLT_MAX; - float tmp_co[3]; int j; ml_dst = &loops_dst[lidx_dst]; @@ -1987,6 +1976,7 @@ void BKE_mesh_remap_calc_polys_from_dm( const float full_weight = 1.0f; const float max_dist_sq = max_dist * max_dist; float (*poly_nors_dst)[3] = NULL; + float tmp_co[3], tmp_no[3]; int i; BLI_assert(mode & MREMAP_MODE_POLY); @@ -1999,7 +1989,7 @@ void BKE_mesh_remap_calc_polys_from_dm( CustomData_set_layer_flag(pdata_dst, CD_NORMAL, CD_FLAG_TEMPORARY); } if (dirty_nors_dst) { - BKE_mesh_calc_normals_poly(verts_dst, numverts_dst, loops_dst, polys_dst, numloops_dst, numpolys_dst, + BKE_mesh_calc_normals_poly(verts_dst, NULL, numverts_dst, loops_dst, polys_dst, numloops_dst, numpolys_dst, poly_nors_dst, true); } } @@ -2028,7 +2018,6 @@ void BKE_mesh_remap_calc_polys_from_dm( for (i = 0; i < numpolys_dst; i++) { MPoly *mp = &polys_dst[i]; - float tmp_co[3]; BKE_mesh_calc_poly_center(mp, &loops_dst[mp->loopstart], verts_dst, tmp_co); @@ -2055,7 +2044,6 @@ void BKE_mesh_remap_calc_polys_from_dm( for (i = 0; i < numpolys_dst; i++) { MPoly *mp = &polys_dst[i]; - float tmp_co[3], tmp_no[3]; BKE_mesh_calc_poly_center(mp, &loops_dst[mp->loopstart], verts_dst, tmp_co); copy_v3_v3(tmp_no, poly_nors_dst[i]); @@ -2104,7 +2092,6 @@ void BKE_mesh_remap_calc_polys_from_dm( * and use their hits to interpolate from source polys. */ /* Note: dst poly is early-converted into src space! */ MPoly *mp = &polys_dst[i]; - float tmp_co[3], tmp_no[3]; int tot_rays, done_rays = 0; float poly_area_2d_inv, done_area = 0.0f; diff --git a/source/blender/blenkernel/intern/mesh_validate.c b/source/blender/blenkernel/intern/mesh_validate.c index e21dde9c726..ab469ac3996 100644 --- a/source/blender/blenkernel/intern/mesh_validate.c +++ b/source/blender/blenkernel/intern/mesh_validate.c @@ -241,6 +241,7 @@ bool BKE_mesh_validate_arrays(Mesh *mesh, struct { int verts : 1; int verts_weight : 1; + int loops_edge : 1; }; int as_flag; } fix_flag; @@ -564,6 +565,7 @@ bool BKE_mesh_validate_arrays(Mesh *mesh, if (do_fixes) { int prev_e = ml->e; ml->e = GET_INT_FROM_POINTER(BLI_edgehash_lookup(edge_hash, v1, v2)); + fix_flag.loops_edge = true; PRINT_ERR("\tLoop %u has invalid edge reference (%d), fixed using edge %u\n", sp->loopstart + j, prev_e, ml->e); } @@ -580,6 +582,7 @@ bool BKE_mesh_validate_arrays(Mesh *mesh, if (do_fixes) { int prev_e = ml->e; ml->e = GET_INT_FROM_POINTER(BLI_edgehash_lookup(edge_hash, v1, v2)); + fix_flag.loops_edge = true; PRINT_ERR("\tPoly %u has invalid edge reference (%d), fixed using edge %u\n", sp->index, prev_e, ml->e); } diff --git a/source/blender/blenkernel/intern/modifier.c b/source/blender/blenkernel/intern/modifier.c index b2c0c6d6d0a..716da14cae6 100644 --- a/source/blender/blenkernel/intern/modifier.c +++ b/source/blender/blenkernel/intern/modifier.c @@ -215,8 +215,7 @@ void modifiers_clearErrors(Object *ob) } } -void modifiers_foreachObjectLink(Object *ob, ObjectWalkFunc walk, - void *userData) +void modifiers_foreachObjectLink(Object *ob, ObjectWalkFunc walk, void *userData) { ModifierData *md = ob->modifiers.first; diff --git a/source/blender/blenkernel/intern/movieclip.c b/source/blender/blenkernel/intern/movieclip.c index 7a8c4ad4564..432ae32f02b 100644 --- a/source/blender/blenkernel/intern/movieclip.c +++ b/source/blender/blenkernel/intern/movieclip.c @@ -603,9 +603,8 @@ static void detect_clip_source(MovieClip *clip) MovieClip *BKE_movieclip_file_add(Main *bmain, const char *name) { MovieClip *clip; - int file, len; - const char *libname; - char str[FILE_MAX], strtest[FILE_MAX]; + int file; + char str[FILE_MAX]; BLI_strncpy(str, name, sizeof(str)); BLI_path_abs(str, bmain->name); @@ -616,29 +615,10 @@ MovieClip *BKE_movieclip_file_add(Main *bmain, const char *name) return NULL; close(file); - /* ** first search an identical clip ** */ - for (clip = bmain->movieclip.first; clip; clip = clip->id.next) { - BLI_strncpy(strtest, clip->name, sizeof(clip->name)); - BLI_path_abs(strtest, G.main->name); - - if (STREQ(strtest, str)) { - BLI_strncpy(clip->name, name, sizeof(clip->name)); /* for stringcode */ - clip->id.us++; /* officially should not, it doesn't link here! */ - - return clip; - } - } - /* ** add new movieclip ** */ /* create a short library name */ - len = strlen(name); - - while (len > 0 && name[len - 1] != '/' && name[len - 1] != '\\') - len--; - libname = name + len; - - clip = movieclip_alloc(bmain, libname); + clip = movieclip_alloc(bmain, BLI_path_basename(name)); BLI_strncpy(clip->name, name, sizeof(clip->name)); detect_clip_source(clip); @@ -655,6 +635,37 @@ MovieClip *BKE_movieclip_file_add(Main *bmain, const char *name) return clip; } +MovieClip *BKE_movieclip_file_add_exists_ex(Main *bmain, const char *filepath, bool *r_exists) +{ + MovieClip *clip; + char str[FILE_MAX], strtest[FILE_MAX]; + + BLI_strncpy(str, filepath, sizeof(str)); + BLI_path_abs(str, bmain->name); + + /* first search an identical filepath */ + for (clip = bmain->movieclip.first; clip; clip = clip->id.next) { + BLI_strncpy(strtest, clip->name, sizeof(clip->name)); + BLI_path_abs(strtest, ID_BLEND_PATH(bmain, &clip->id)); + + if (BLI_path_cmp(strtest, str) == 0) { + clip->id.us++; /* officially should not, it doesn't link here! */ + if (r_exists) + *r_exists = true; + return clip; + } + } + + if (r_exists) + *r_exists = false; + return BKE_movieclip_file_add(bmain, filepath); +} + +MovieClip *BKE_movieclip_file_add_exists(Main *bmain, const char *filepath) +{ + return BKE_movieclip_file_add_exists_ex(bmain, filepath, NULL); +} + static void real_ibuf_size(MovieClip *clip, MovieClipUser *user, ImBuf *ibuf, int *width, int *height) { *width = ibuf->x; @@ -847,7 +858,7 @@ static ImBuf *movieclip_get_postprocessed_ibuf(MovieClip *clip, MovieClipUser *u bool need_postprocess = false; /* cache isn't threadsafe itself and also loading of movies - * can't happen from concurent threads that's why we use lock here */ + * can't happen from concurrent threads that's why we use lock here */ BLI_lock_thread(LOCK_MOVIECLIP); /* try to obtain cached postprocessed frame first */ diff --git a/source/blender/blenkernel/intern/multires.c b/source/blender/blenkernel/intern/multires.c index 9ef5b697079..fbba6249b73 100644 --- a/source/blender/blenkernel/intern/multires.c +++ b/source/blender/blenkernel/intern/multires.c @@ -1464,10 +1464,10 @@ DerivedMesh *multires_make_derived_from_derived(DerivedMesh *dm, gridData = result->getGridData(result); result->getGridKey(result, &key); - subGridData = MEM_callocN(sizeof(CCGElem *) * numGrids, "subGridData*"); + subGridData = MEM_mallocN(sizeof(CCGElem *) * numGrids, "subGridData*"); for (i = 0; i < numGrids; i++) { - subGridData[i] = MEM_callocN(key.elem_size * gridSize * gridSize, "subGridData"); + subGridData[i] = MEM_mallocN(key.elem_size * gridSize * gridSize, "subGridData"); memcpy(subGridData[i], gridData[i], key.elem_size * gridSize * gridSize); } diff --git a/source/blender/blenkernel/intern/nla.c b/source/blender/blenkernel/intern/nla.c index a04eb9bd611..65245477c7f 100644 --- a/source/blender/blenkernel/intern/nla.c +++ b/source/blender/blenkernel/intern/nla.c @@ -1178,7 +1178,34 @@ static void nlastrip_fix_resize_overlaps(NlaStrip *strip) NlaStrip *nls = strip->next; float offset = 0.0f; - if (strip->end > nls->start) { + if (nls->type == NLASTRIP_TYPE_TRANSITION) { + /* transition strips should grow/shrink to accomodate the resized strip, + * but if the strip's bounds now exceed the transition, we're forced to + * offset everything to maintain the balance + */ + if (strip->end <= nls->start) { + /* grow the transition to fill the void */ + nls->start = strip->end; + } + else if (strip->end < nls->end) { + /* shrink the transition to give the strip room */ + nls->start = strip->end; + } + else { + /* shrink transition down to 1 frame long (so that it can still be found), + * then offset everything else by the remaining defict to give the strip room + */ + nls->start = nls->end - 1.0f; + offset = ceilf(strip->end - nls->start); /* XXX: review whether preventing fractionals is good here... */ + + /* apply necessary offset to ensure that the strip has enough space */ + for (; nls; nls = nls->next) { + nls->start += offset; + nls->end += offset; + } + } + } + else if (strip->end > nls->start) { /* NOTE: need to ensure we don't have a fractional frame offset, even if that leaves a gap, * otherwise it will be very hard to get rid of later */ @@ -1198,7 +1225,34 @@ static void nlastrip_fix_resize_overlaps(NlaStrip *strip) NlaStrip *nls = strip->prev; float offset = 0.0f; - if (strip->start < nls->end) { + if (nls->type == NLASTRIP_TYPE_TRANSITION) { + /* transition strips should grow/shrink to accomodate the resized strip, + * but if the strip's bounds now exceed the transition, we're forced to + * offset everything to maintain the balance + */ + if (strip->start >= nls->end) { + /* grow the transition to fill the void */ + nls->end = strip->start; + } + else if (strip->start > nls->start) { + /* shrink the transition to give the strip room */ + nls->end = strip->start; + } + else { + /* shrink transition down to 1 frame long (so that it can still be found), + * then offset everything else by the remaining defict to give the strip room + */ + nls->end = nls->start + 1.0f; + offset = ceilf(nls->end - strip->start); /* XXX: review whether preventing fractionals is good here... */ + + /* apply necessary offset to ensure that the strip has enough space */ + for (; nls; nls = nls->next) { + nls->start -= offset; + nls->end -= offset; + } + } + } + else if (strip->start < nls->end) { /* NOTE: need to ensure we don't have a fractional frame offset, even if that leaves a gap, * otherwise it will be very hard to get rid of later */ @@ -1778,7 +1832,7 @@ bool BKE_nla_tweakmode_enter(AnimData *adt) } return false; } - + /* go over all the tracks up to the active one, tagging each strip that uses the same * action as the active strip, but leaving everything else alone */ @@ -1791,6 +1845,13 @@ bool BKE_nla_tweakmode_enter(AnimData *adt) } } + /* tag all other strips in active track that uses the same action as the active strip */ + for (strip = activeTrack->strips.first; strip; strip = strip->next) { + if ((strip->act == activeStrip->act) && (strip != activeStrip)) + strip->flag |= NLASTRIP_FLAG_TWEAKUSER; + else + strip->flag &= ~NLASTRIP_FLAG_TWEAKUSER; + } /* go over all the tracks after AND INCLUDING the active one, tagging them as being disabled * - the active track needs to also be tagged, otherwise, it'll overlap with the tweaks going on @@ -1852,8 +1913,19 @@ void BKE_nla_tweakmode_exit(AnimData *adt) for (nlt = adt->nla_tracks.first; nlt; nlt = nlt->next) { nlt->flag &= ~NLATRACK_DISABLED; - for (strip = nlt->strips.first; strip; strip = strip->next) + for (strip = nlt->strips.first; strip; strip = strip->next) { + /* sync strip extents if this strip uses the same action */ + if ((adt->actstrip) && (adt->actstrip->act == strip->act) && (strip->flag & NLASTRIP_FLAG_SYNC_LENGTH)) { + /* recalculate the length of the action */ + calc_action_range(strip->act, &strip->actstart, &strip->actend, 0); + + /* adjust the strip extents in response to this */ + BKE_nlastrip_recalculate_bounds(strip); + } + + /* clear tweakuser flag */ strip->flag &= ~NLASTRIP_FLAG_TWEAKUSER; + } } /* handle AnimData level changes: diff --git a/source/blender/blenkernel/intern/node.c b/source/blender/blenkernel/intern/node.c index 3bcdb93729f..d3460dcb481 100644 --- a/source/blender/blenkernel/intern/node.c +++ b/source/blender/blenkernel/intern/node.c @@ -818,6 +818,10 @@ void nodeChainIter( bNodeLink *link; for (link = ntree->links.first; link; link = link->next) { + if ((link->flag & NODE_LINK_VALID) == 0) { + /* Skip links marked as cyclic. */ + continue; + } if (link->tonode && link->fromnode) { /* is the link part of the chain meaning node_start == fromnode (or tonode for reversed case)? */ if ((reversed && (link->tonode == node_start)) || @@ -1147,6 +1151,11 @@ void nodeDetachNode(struct bNode *node) } } +void ntreeInitDefault(bNodeTree *ntree) +{ + ntree_set_typeinfo(ntree, NULL); +} + bNodeTree *ntreeAddTree(Main *bmain, const char *name, const char *idname) { bNodeTree *ntree; diff --git a/source/blender/blenkernel/intern/object.c b/source/blender/blenkernel/intern/object.c index 4ddda70e2e7..e56887b0a1c 100644 --- a/source/blender/blenkernel/intern/object.c +++ b/source/blender/blenkernel/intern/object.c @@ -471,7 +471,7 @@ void BKE_object_free(Object *ob) BKE_object_free_ex(ob, true); } -static void unlink_object__unlinkModifierLinks(void *userData, Object *ob, Object **obpoin) +static void unlink_object__unlinkModifierLinks(void *userData, Object *ob, Object **obpoin, int UNUSED(cd_flag)) { Object *unlinkOb = userData; @@ -976,19 +976,10 @@ void *BKE_object_obdata_add_from_type(Main *bmain, int type, const char *name) } } -/* more general add: creates minimum required data, but without vertices etc. */ -Object *BKE_object_add_only_object(Main *bmain, int type, const char *name) +void BKE_object_init(Object *ob) { - Object *ob; + /* BLI_assert(MEMCMP_STRUCT_OFS_IS_ZERO(ob, id)); */ /* ob->type is already initialized... */ - if (!name) - name = get_obdata_defname(type); - - ob = BKE_libblock_alloc(bmain, ID_OB, name); - - /* default object vars */ - ob->type = type; - ob->col[0] = ob->col[1] = ob->col[2] = 1.0; ob->col[3] = 1.0; @@ -1016,7 +1007,7 @@ Object *BKE_object_add_only_object(Main *bmain, int type, const char *name) ob->empty_drawtype = OB_PLAINAXES; ob->empty_drawsize = 1.0; - if (ELEM(type, OB_LAMP, OB_CAMERA, OB_SPEAKER)) { + if (ELEM(ob->type, OB_LAMP, OB_CAMERA, OB_SPEAKER)) { ob->trackflag = OB_NEGZ; ob->upflag = OB_POSY; } @@ -1045,6 +1036,7 @@ Object *BKE_object_add_only_object(Main *bmain, int type, const char *name) ob->step_height = 0.15f; ob->jump_speed = 10.0f; ob->fall_speed = 55.0f; + ob->max_jumps = 1; ob->col_group = 0x01; ob->col_mask = 0xffff; ob->preview = NULL; @@ -1056,6 +1048,22 @@ Object *BKE_object_add_only_object(Main *bmain, int type, const char *name) /* Animation Visualization defaults */ animviz_settings_init(&ob->avs); +} + +/* more general add: creates minimum required data, but without vertices etc. */ +Object *BKE_object_add_only_object(Main *bmain, int type, const char *name) +{ + Object *ob; + + if (!name) + name = get_obdata_defname(type); + + ob = BKE_libblock_alloc(bmain, ID_OB, name); + + /* default object vars */ + ob->type = type; + + BKE_object_init(ob); return ob; } @@ -1579,8 +1587,7 @@ Object *BKE_object_copy(Object *ob) } static void extern_local_object__modifiersForeachIDLink( - void *UNUSED(userData), Object *UNUSED(ob), - ID **idpoin) + void *UNUSED(userData), Object *UNUSED(ob), ID **idpoin, int UNUSED(cd_flag)) { if (*idpoin) { /* intentionally omit ID_OB */ @@ -1955,9 +1962,15 @@ void BKE_object_mat3_to_rot(Object *ob, float mat[3][3], bool use_compat) } case ROT_MODE_AXISANGLE: { - mat3_to_axis_angle(ob->rotAxis, &ob->rotAngle, mat); - sub_v3_v3(ob->rotAxis, ob->drotAxis); - ob->rotAngle -= ob->drotAngle; + float quat[4]; + float dquat[4]; + + /* without drot we could apply 'mat' directly */ + mat3_to_quat(quat, mat); + axis_angle_to_quat(dquat, ob->drotAxis, ob->drotAngle); + invert_qt(dquat); + mul_qt_qtqt(quat, dquat, quat); + quat_to_axis_angle(ob->rotAxis, &ob->rotAngle, quat); break; } default: /* euler */ @@ -2660,6 +2673,76 @@ void BKE_boundbox_calc_size_aabb(const BoundBox *bb, float r_size[3]) r_size[2] = 0.5f * fabsf(bb->vec[0][2] - bb->vec[1][2]); } +void BKE_boundbox_minmax(const BoundBox *bb, float obmat[4][4], float r_min[3], float r_max[3]) +{ + int i; + for (i = 0; i < 8; i++) { + float vec[3]; + mul_v3_m4v3(vec, obmat, bb->vec[i]); + minmax_v3v3_v3(r_min, r_max, vec); + } +} + +/** + * Returns a BBox which each dimensions are at least epsilon. + * \note In case a given dimension needs to be enlarged, its final value will be in [epsilon, 3 * epsilon] range. + * + * \param bb the input bbox to check. + * \param bb_temp the temp bbox to modify (\a bb content is never changed). + * \param epsilon the minimum dimension to ensure. + * \return either bb (if nothing needed to be changed) or bb_temp. + */ +BoundBox *BKE_boundbox_ensure_minimum_dimensions(BoundBox *bb, BoundBox *bb_temp, const float epsilon) +{ + if (fabsf(bb->vec[0][0] - bb->vec[4][0]) < epsilon) { + /* Flat along X axis... */ + *bb_temp = *bb; + bb = bb_temp; + bb->vec[0][0] -= epsilon; + bb->vec[1][0] -= epsilon; + bb->vec[2][0] -= epsilon; + bb->vec[3][0] -= epsilon; + bb->vec[4][0] += epsilon; + bb->vec[5][0] += epsilon; + bb->vec[6][0] += epsilon; + bb->vec[7][0] += epsilon; + } + + if (fabsf(bb->vec[0][1] - bb->vec[3][1]) < epsilon) { + /* Flat along Y axis... */ + if (bb != bb_temp) { + *bb_temp = *bb; + bb = bb_temp; + } + bb->vec[0][1] -= epsilon; + bb->vec[1][1] -= epsilon; + bb->vec[4][1] -= epsilon; + bb->vec[5][1] -= epsilon; + bb->vec[2][1] += epsilon; + bb->vec[3][1] += epsilon; + bb->vec[6][1] += epsilon; + bb->vec[7][1] += epsilon; + } + + if (fabsf(bb->vec[0][2] - bb->vec[1][2]) < epsilon) { + /* Flat along Z axis... */ + if (bb != bb_temp) { + *bb_temp = *bb; + bb = bb_temp; + } + bb->vec[0][2] -= epsilon; + bb->vec[3][2] -= epsilon; + bb->vec[4][2] -= epsilon; + bb->vec[7][2] -= epsilon; + bb->vec[1][2] += epsilon; + bb->vec[2][2] += epsilon; + bb->vec[5][2] += epsilon; + bb->vec[6][2] += epsilon; + } + + return bb; +} + BoundBox *BKE_object_boundbox_get(Object *ob) { BoundBox *bb = NULL; @@ -2735,7 +2818,6 @@ void BKE_object_minmax(Object *ob, float min_r[3], float max_r[3], const bool us { BoundBox bb; float vec[3]; - int a; bool changed = false; switch (ob->type) { @@ -2744,11 +2826,7 @@ void BKE_object_minmax(Object *ob, float min_r[3], float max_r[3], const bool us case OB_SURF: { bb = *BKE_curve_boundbox_get(ob); - - for (a = 0; a < 8; a++) { - mul_m4_v3(ob->obmat, bb.vec[a]); - minmax_v3v3_v3(min_r, max_r, bb.vec[a]); - } + BKE_boundbox_minmax(&bb, ob->obmat, min_r, max_r); changed = true; break; } @@ -2771,23 +2849,7 @@ void BKE_object_minmax(Object *ob, float min_r[3], float max_r[3], const bool us } case OB_ARMATURE: { - if (ob->pose) { - bArmature *arm = ob->data; - bPoseChannel *pchan; - - for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) { - /* XXX pchan->bone may be NULL for duplicated bones, see duplicateEditBoneObjects() comment - * (editarmature.c:2592)... Skip in this case too! */ - if (pchan->bone && !((use_hidden == false) && (PBONE_VISIBLE(arm, pchan->bone) == false))) { - mul_v3_m4v3(vec, ob->obmat, pchan->pose_head); - minmax_v3v3_v3(min_r, max_r, vec); - mul_v3_m4v3(vec, ob->obmat, pchan->pose_tail); - minmax_v3v3_v3(min_r, max_r, vec); - - changed = true; - } - } - } + changed = BKE_pose_minmax(ob, min_r, max_r, use_hidden, false); break; } case OB_MESH: @@ -2796,11 +2858,7 @@ void BKE_object_minmax(Object *ob, float min_r[3], float max_r[3], const bool us if (me) { bb = *BKE_mesh_boundbox_get(ob); - - for (a = 0; a < 8; a++) { - mul_m4_v3(ob->obmat, bb.vec[a]); - minmax_v3v3_v3(min_r, max_r, bb.vec[a]); - } + BKE_boundbox_minmax(&bb, ob->obmat, min_r, max_r); changed = true; } break; @@ -3676,38 +3734,6 @@ bool BKE_object_is_animated(Scene *scene, Object *ob) return false; } -static void copy_object__forwardModifierLinks(void *UNUSED(userData), Object *UNUSED(ob), ID **idpoin) -{ - /* this is copied from ID_NEW; it might be better to have a macro */ - if (*idpoin && (*idpoin)->newid) *idpoin = (*idpoin)->newid; -} - -void BKE_object_relink(Object *ob) -{ - if (ob->id.lib) - return; - - BKE_constraints_relink(&ob->constraints); - if (ob->pose) { - bPoseChannel *chan; - for (chan = ob->pose->chanbase.first; chan; chan = chan->next) { - BKE_constraints_relink(&chan->constraints); - } - } - modifiers_foreachIDLink(ob, copy_object__forwardModifierLinks, NULL); - - if (ob->adt) - BKE_animdata_relink(ob->adt); - - if (ob->rigidbody_constraint) - BKE_rigidbody_relink_constraint(ob->rigidbody_constraint); - - ID_NEW(ob->parent); - - ID_NEW(ob->proxy); - ID_NEW(ob->proxy_group); -} - MovieClip *BKE_object_movieclip_get(Scene *scene, Object *ob, bool use_default) { MovieClip *clip = use_default ? scene->clip : NULL; diff --git a/source/blender/blenkernel/intern/packedFile.c b/source/blender/blenkernel/intern/packedFile.c index 151889b10a1..a1669c745e6 100644 --- a/source/blender/blenkernel/intern/packedFile.c +++ b/source/blender/blenkernel/intern/packedFile.c @@ -582,7 +582,7 @@ int unpackImage(ReportList *reports, Image *ima, int how) { int ret_value = RET_ERROR; - if (ima != NULL && ima->name[0]) { + if (ima != NULL) { while (ima->packedfiles.last) { char localname[FILE_MAX], absname[FILE_MAX]; char *newname; @@ -605,7 +605,9 @@ int unpackImage(ReportList *reports, Image *ima, int how) } /* keep the new name in the image for non-pack specific reasons */ - BLI_strncpy(ima->name, newname, sizeof(imapf->filepath)); + if (how != PF_REMOVE) { + BLI_strncpy(ima->name, newname, sizeof(imapf->filepath)); + } MEM_freeN(newname); } else { diff --git a/source/blender/blenkernel/intern/paint.c b/source/blender/blenkernel/intern/paint.c index 328731a11a9..06844b09a9b 100644 --- a/source/blender/blenkernel/intern/paint.c +++ b/source/blender/blenkernel/intern/paint.c @@ -128,6 +128,32 @@ void BKE_paint_reset_overlay_invalid(OverlayControlFlags flag) overlay_flags &= ~(flag); } +Paint *BKE_paint_get_active_from_paintmode(Scene *sce, PaintMode mode) +{ + if (sce) { + ToolSettings *ts = sce->toolsettings; + + switch (mode) { + case ePaintSculpt: + return &ts->sculpt->paint; + case ePaintVertex: + return &ts->vpaint->paint; + case ePaintWeight: + return &ts->wpaint->paint; + case ePaintTexture2D: + case ePaintTextureProjective: + return &ts->imapaint.paint; + case ePaintSculptUV: + return &ts->uvsculpt->paint; + case ePaintInvalid: + return NULL; + default: + return &ts->imapaint.paint; + } + } + + return NULL; +} Paint *BKE_paint_get_active(Scene *sce) { @@ -223,39 +249,39 @@ PaintMode BKE_paintmode_get_active_from_context(const bContext *C) if ((sima = CTX_wm_space_image(C)) != NULL) { if (obact && obact->mode == OB_MODE_EDIT) { if (sima->mode == SI_MODE_PAINT) - return PAINT_TEXTURE_2D; + return ePaintTexture2D; else if (ts->use_uv_sculpt) - return PAINT_SCULPT_UV; + return ePaintSculptUV; } else { - return PAINT_TEXTURE_2D; + return ePaintTexture2D; } } else if (obact) { switch (obact->mode) { case OB_MODE_SCULPT: - return PAINT_SCULPT; + return ePaintSculpt; case OB_MODE_VERTEX_PAINT: - return PAINT_VERTEX; + return ePaintVertex; case OB_MODE_WEIGHT_PAINT: - return PAINT_WEIGHT; + return ePaintWeight; case OB_MODE_TEXTURE_PAINT: - return PAINT_TEXTURE_PROJECTIVE; + return ePaintTextureProjective; case OB_MODE_EDIT: if (ts->use_uv_sculpt) - return PAINT_SCULPT_UV; - return PAINT_TEXTURE_2D; + return ePaintSculptUV; + return ePaintTexture2D; default: - return PAINT_TEXTURE_2D; + return ePaintTexture2D; } } else { /* default to image paint */ - return PAINT_TEXTURE_2D; + return ePaintTexture2D; } } - return PAINT_INVALID; + return ePaintInvalid; } Brush *BKE_paint_brush(Paint *p) @@ -418,23 +444,51 @@ void BKE_paint_cavity_curve_preset(Paint *p, int preset) curvemapping_changed(p->cavity_curve, false); } -void BKE_paint_init(UnifiedPaintSettings *ups, Paint *p, const char col[3]) +short BKE_paint_object_mode_from_paint_mode(PaintMode mode) { + switch (mode) { + case ePaintSculpt: + return OB_MODE_SCULPT; + case ePaintVertex: + return OB_MODE_VERTEX_PAINT; + case ePaintWeight: + return OB_MODE_WEIGHT_PAINT; + case ePaintTextureProjective: + return OB_MODE_TEXTURE_PAINT; + case ePaintTexture2D: + return OB_MODE_TEXTURE_PAINT; + case ePaintSculptUV: + return OB_MODE_EDIT; + case ePaintInvalid: + default: + return 0; + } +} + +void BKE_paint_init(Scene *sce, PaintMode mode, const char col[3]) +{ + UnifiedPaintSettings *ups = &sce->toolsettings->unified_paint_settings; Brush *brush; + Paint *paint = BKE_paint_get_active_from_paintmode(sce, mode); /* If there's no brush, create one */ - brush = BKE_paint_brush(p); - if (brush == NULL) - brush = BKE_brush_add(G.main, "Brush"); - BKE_paint_brush_set(p, brush); + brush = BKE_paint_brush(paint); + if (brush == NULL) { + short ob_mode = BKE_paint_object_mode_from_paint_mode(mode); + brush = BKE_brush_first_search(G.main, ob_mode); + + if (!brush) + brush = BKE_brush_add(G.main, "Brush", ob_mode); + BKE_paint_brush_set(paint, brush); + } - memcpy(p->paint_cursor_col, col, 3); - p->paint_cursor_col[3] = 128; + memcpy(paint->paint_cursor_col, col, 3); + paint->paint_cursor_col[3] = 128; ups->last_stroke_valid = false; zero_v3(ups->average_stroke_accum); ups->average_stroke_counter = 0; - if (!p->cavity_curve) - BKE_paint_cavity_curve_preset(p, CURVE_PRESET_LINE); + if (!paint->cavity_curve) + BKE_paint_cavity_curve_preset(paint, CURVE_PRESET_LINE); } void BKE_paint_free(Paint *paint) diff --git a/source/blender/blenkernel/intern/particle_system.c b/source/blender/blenkernel/intern/particle_system.c index dd43e63b9c3..a59a0b73b69 100644 --- a/source/blender/blenkernel/intern/particle_system.c +++ b/source/blender/blenkernel/intern/particle_system.c @@ -77,6 +77,7 @@ #include "BKE_cdderivedmesh.h" #include "BKE_collision.h" #include "BKE_effect.h" +#include "BKE_library_query.h" #include "BKE_particle.h" #include "BKE_global.h" @@ -4209,13 +4210,39 @@ void particle_system_update(Scene *scene, Object *ob, ParticleSystem *psys) invert_m4_m4(psys->imat, ob->obmat); } +/* ID looper */ + +void BKE_particlesystem_id_loop(ParticleSystem *psys, ParticleSystemIDFunc func, void *userdata) +{ + ParticleTarget *pt; + + func(psys, (ID **)&psys->part, userdata, IDWALK_NOP); + func(psys, (ID **)&psys->target_ob, userdata, IDWALK_NOP); + func(psys, (ID **)&psys->parent, userdata, IDWALK_NOP); + + for (pt = psys->targets.first; pt; pt = pt->next) { + func(psys, (ID **)&pt->ob, userdata, IDWALK_NOP); + } + + if (psys->part->phystype == PART_PHYS_BOIDS) { + ParticleData *pa; + int p; + + for (p = 0, pa = psys->particles; p < psys->totpart; p++, pa++) { + func(psys, (ID **)&pa->boid->ground, userdata, IDWALK_NOP); + } + } +} + /* **** Depsgraph evaluation **** */ void BKE_particle_system_eval(EvaluationContext *UNUSED(eval_ctx), + Scene *scene, Object *ob, ParticleSystem *psys) { if (G.debug & G_DEBUG_DEPSGRAPH) { printf("%s on %s:%s\n", __func__, ob->id.name, psys->name); } + BKE_ptcache_object_reset(scene, ob, PTCACHE_RESET_DEPSGRAPH); } diff --git a/source/blender/blenkernel/intern/pbvh_bmesh.c b/source/blender/blenkernel/intern/pbvh_bmesh.c index 3e236079a66..ff4cae09437 100644 --- a/source/blender/blenkernel/intern/pbvh_bmesh.c +++ b/source/blender/blenkernel/intern/pbvh_bmesh.c @@ -575,7 +575,7 @@ static void pbvh_bmesh_edge_loops(BLI_Buffer *buf, BMEdge *e) buf->count = 2; } else { - BLI_buffer_resize(buf, BM_edge_face_count(e)); + BLI_buffer_reinit(buf, BM_edge_face_count(e)); BM_iter_as_array(NULL, BM_LOOPS_OF_EDGE, e, buf->data, buf->count); } } diff --git a/source/blender/blenkernel/intern/property.c b/source/blender/blenkernel/intern/property.c index 100df5fd121..dc4063b42ed 100644 --- a/source/blender/blenkernel/intern/property.c +++ b/source/blender/blenkernel/intern/property.c @@ -142,8 +142,8 @@ void BKE_bproperty_object_set(Object *ob, bProperty *propc) bProperty *prop; prop = BKE_bproperty_object_get(ob, propc->name); if (prop) { - BKE_bproperty_free(prop); BLI_remlink(&ob->prop, prop); + BKE_bproperty_free(prop); } BLI_addtail(&ob->prop, BKE_bproperty_copy(propc)); } diff --git a/source/blender/blenkernel/intern/rigidbody.c b/source/blender/blenkernel/intern/rigidbody.c index 476b9a22238..0f1f9b4bdf7 100644 --- a/source/blender/blenkernel/intern/rigidbody.c +++ b/source/blender/blenkernel/intern/rigidbody.c @@ -58,6 +58,7 @@ #include "BKE_effect.h" #include "BKE_global.h" #include "BKE_library.h" +#include "BKE_library_query.h" #include "BKE_mesh.h" #include "BKE_object.h" #include "BKE_pointcache.h" @@ -957,6 +958,20 @@ void BKE_rigidbody_world_groups_relink(RigidBodyWorld *rbw) rbw->effector_weights->group = (Group *)rbw->effector_weights->group->id.newid; } +void BKE_rigidbody_world_id_loop(RigidBodyWorld *rbw, RigidbodyWorldIDFunc func, void *userdata) +{ + func(rbw, (ID **)&rbw->group, userdata, IDWALK_NOP); + func(rbw, (ID **)&rbw->constraints, userdata, IDWALK_NOP); + func(rbw, (ID **)&rbw->effector_weights->group, userdata, IDWALK_NOP); + + if (rbw->objects) { + int i; + for (i = 0; i < rbw->numbodies; i++) { + func(rbw, (ID **)&rbw->objects[i], userdata, IDWALK_NOP); + } + } +} + /* Add rigid body settings to the specified object */ RigidBodyOb *BKE_rigidbody_create_object(Scene *scene, Object *ob, short type) { @@ -1597,6 +1612,7 @@ void BKE_rigidbody_calc_center_of_mass(Object *ob, float r_center[3]) { zero_v3( struct RigidBodyWorld *BKE_rigidbody_create_world(Scene *scene) { return NULL; } struct RigidBodyWorld *BKE_rigidbody_world_copy(RigidBodyWorld *rbw) { return NULL; } void BKE_rigidbody_world_groups_relink(struct RigidBodyWorld *rbw) {} +void BKE_rigidbody_world_id_loop(struct RigidBodyWorld *rbw, RigidbodyWorldIDFunc func, void *userdata) {} struct RigidBodyOb *BKE_rigidbody_create_object(Scene *scene, Object *ob, short type) { return NULL; } struct RigidBodyCon *BKE_rigidbody_create_constraint(Scene *scene, Object *ob, short type) { return NULL; } struct RigidBodyWorld *BKE_rigidbody_get_world(Scene *scene) { return NULL; } diff --git a/source/blender/blenkernel/intern/sca.c b/source/blender/blenkernel/intern/sca.c index c902659c039..88a28228639 100644 --- a/source/blender/blenkernel/intern/sca.c +++ b/source/blender/blenkernel/intern/sca.c @@ -48,6 +48,7 @@ #include "BKE_global.h" #include "BKE_main.h" #include "BKE_library.h" +#include "BKE_library_query.h" #include "BKE_sca.h" /* ******************* SENSORS ************************ */ @@ -903,6 +904,179 @@ void unlink_logicbricks(void **poin, void ***ppoin, short *tot) } } +void BKE_sca_sensors_id_loop(ListBase *senslist, SCASensorIDFunc func, void *userdata) +{ + bSensor *sensor; + + for (sensor = senslist->first; sensor; sensor = sensor->next) { + func(sensor, (ID **)&sensor->ob, userdata, IDWALK_NOP); + + switch (sensor->type) { + case SENS_TOUCH: /* DEPRECATED */ + { + bTouchSensor *ts = sensor->data; + func(sensor, (ID **)&ts->ma, userdata, IDWALK_NOP); + break; + } + case SENS_MESSAGE: + { + bMessageSensor *ms = sensor->data; + func(sensor, (ID **)&ms->fromObject, userdata, IDWALK_NOP); + break; + } + case SENS_ALWAYS: + case SENS_NEAR: + case SENS_KEYBOARD: + case SENS_PROPERTY: + case SENS_MOUSE: + case SENS_COLLISION: + case SENS_RADAR: + case SENS_RANDOM: + case SENS_RAY: + case SENS_JOYSTICK: + case SENS_ACTUATOR: + case SENS_DELAY: + case SENS_ARMATURE: + default: + break; + } + } +} + +void BKE_sca_controllers_id_loop(ListBase *contlist, SCAControllerIDFunc func, void *userdata) +{ + bController *controller; + + for (controller = contlist->first; controller; controller = controller->next) { + switch (controller->type) { + case CONT_PYTHON: + { + bPythonCont *pc = controller->data; + func(controller, (ID **)&pc->text, userdata, IDWALK_NOP); + break; + } + case CONT_LOGIC_AND: + case CONT_LOGIC_OR: + case CONT_EXPRESSION: + case CONT_LOGIC_NAND: + case CONT_LOGIC_NOR: + case CONT_LOGIC_XOR: + case CONT_LOGIC_XNOR: + default: + break; + } + } +} + +void BKE_sca_actuators_id_loop(ListBase *actlist, SCAActuatorIDFunc func, void *userdata) +{ + bActuator *actuator; + + for (actuator = actlist->first; actuator; actuator = actuator->next) { + func(actuator, (ID **)&actuator->ob, userdata, IDWALK_NOP); + + switch (actuator->type) { + case ACT_ADD_OBJECT: /* DEPRECATED */ + { + bAddObjectActuator *aoa = actuator->data; + func(actuator, (ID **)&aoa->ob, userdata, IDWALK_NOP); + break; + } + case ACT_ACTION: + { + bActionActuator *aa = actuator->data; + func(actuator, (ID **)&aa->act, userdata, IDWALK_NOP); + break; + } + case ACT_SOUND: + { + bSoundActuator *sa = actuator->data; + func(actuator, (ID **)&sa->sound, userdata, IDWALK_NOP); + break; + } + case ACT_EDIT_OBJECT: + { + bEditObjectActuator *eoa = actuator->data; + func(actuator, (ID **)&eoa->ob, userdata, IDWALK_NOP); + func(actuator, (ID **)&eoa->me, userdata, IDWALK_NOP); + break; + } + case ACT_SCENE: + { + bSceneActuator *sa = actuator->data; + func(actuator, (ID **)&sa->scene, userdata, IDWALK_NOP); + func(actuator, (ID **)&sa->camera, userdata, IDWALK_NOP); + break; + } + case ACT_PROPERTY: + { + bPropertyActuator *pa = actuator->data; + func(actuator, (ID **)&pa->ob, userdata, IDWALK_NOP); + break; + } + case ACT_OBJECT: + { + bObjectActuator *oa = actuator->data; + func(actuator, (ID **)&oa->reference, userdata, IDWALK_NOP); + break; + } + case ACT_CAMERA: + { + bCameraActuator *ca = actuator->data; + func(actuator, (ID **)&ca->ob, userdata, IDWALK_NOP); + break; + } + case ACT_MESSAGE: + { + bMessageActuator *ma = actuator->data; + func(actuator, (ID **)&ma->toObject, userdata, IDWALK_NOP); + break; + } + case ACT_2DFILTER: + { + bTwoDFilterActuator *tdfa = actuator->data; + func(actuator, (ID **)&tdfa->text, userdata, IDWALK_NOP); + break; + } + case ACT_PARENT: + { + bParentActuator *pa = actuator->data; + func(actuator, (ID **)&pa->ob, userdata, IDWALK_NOP); + break; + } + case ACT_ARMATURE: + { + bArmatureActuator *aa = actuator->data; + func(actuator, (ID **)&aa->target, userdata, IDWALK_NOP); + func(actuator, (ID **)&aa->subtarget, userdata, IDWALK_NOP); + break; + } + case ACT_STEERING: + { + bSteeringActuator *sa = actuator->data; + func(actuator, (ID **)&sa->target, userdata, IDWALK_NOP); + func(actuator, (ID **)&sa->navmesh, userdata, IDWALK_NOP); + break; + } + /* Note: some types seems to be non-implemented? ACT_LAMP, ACT_MATERIAL... */ + case ACT_IPO: /* DEPRECATED */ + case ACT_LAMP: + case ACT_MATERIAL: + case ACT_END_OBJECT: /* DEPRECATED */ + case ACT_CONSTRAINT: + case ACT_GROUP: + case ACT_RANDOM: + case ACT_GAME: + case ACT_VISIBILITY: + case ACT_SHAPEACTION: + case ACT_STATE: + case ACT_MOUSE: + default: + break; + } + } +} + const char *sca_state_name_get(Object *ob, short bit) { bController *cont; diff --git a/source/blender/blenkernel/intern/scene.c b/source/blender/blenkernel/intern/scene.c index 701483af43f..cc656775c14 100644 --- a/source/blender/blenkernel/intern/scene.c +++ b/source/blender/blenkernel/intern/scene.c @@ -464,15 +464,15 @@ void BKE_scene_free(Scene *sce) BKE_previewimg_free(&sce->preview); } -Scene *BKE_scene_add(Main *bmain, const char *name) +void BKE_scene_init(Scene *sce) { - Scene *sce; ParticleEditSettings *pset; int a; const char *colorspace_name; SceneRenderView *srv; - sce = BKE_libblock_alloc(bmain, ID_SCE, name); + BLI_assert(MEMCMP_STRUCT_OFS_IS_ZERO(sce, id)); + sce->lay = sce->layact = 1; sce->r.mode = R_GAMMA | R_OSA | R_SHADOW | R_SSS | R_ENVMAP | R_RAYTRACE; @@ -743,6 +743,15 @@ Scene *BKE_scene_add(Main *bmain, const char *name) copy_v2_fl2(sce->safe_areas.action_center, 15.0f / 100.0f, 5.0f / 100.0f); sce->preview = NULL; +} + +Scene *BKE_scene_add(Main *bmain, const char *name) +{ + Scene *sce; + + sce = BKE_libblock_alloc(bmain, ID_SCE, name); + + BKE_scene_init(sce); return sce; } @@ -1360,7 +1369,7 @@ static void scene_do_rb_simulation_recursive(Scene *scene, float ctime) * * 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 ingle thread. + * let's keep it simple and update mballs in a single thread. */ #define MBALL_SINGLETHREAD_HACK @@ -1587,7 +1596,9 @@ static void scene_free_unused_opensubdiv_cache(Scene *scene) if (md != NULL && md->type == eModifierType_Subsurf) { SubsurfModifierData *smd = (SubsurfModifierData *) md; bool object_in_editmode = object->mode == OB_MODE_EDIT; - if (!smd->use_opensubdiv) { + if (!smd->use_opensubdiv || + DAG_get_eval_flags_for_object(scene, object) & DAG_EVAL_NEED_CPU) + { if (smd->mCache != NULL) { ccgSubSurf_free_osd_mesh(smd->mCache); } @@ -1804,6 +1815,11 @@ void BKE_scene_update_tagged(EvaluationContext *eval_ctx, Main *bmain, Scene *sc else #endif { +#ifdef OPENSUBDIV_GL_WORKAROUND + if (DEG_needs_eval(scene->depsgraph)) { + scene_free_unused_opensubdiv_cache(scene); + } +#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); @@ -1885,6 +1901,8 @@ void BKE_scene_update_for_newframe_ex(EvaluationContext *eval_ctx, Main *bmain, (void) do_invisible_flush; #endif + DAG_editors_update_pre(bmain, sce, true); + /* keep this first */ BLI_callback_exec(bmain, &sce->id, BLI_CB_EVT_FRAME_CHANGE_PRE); BLI_callback_exec(bmain, &sce->id, BLI_CB_EVT_SCENE_UPDATE_PRE); @@ -2165,8 +2183,8 @@ bool BKE_scene_use_new_shading_nodes(const Scene *scene) bool BKE_scene_use_shading_nodes_custom(Scene *scene) { - RenderEngineType *type = RE_engines_find(scene->r.engine); - return (type && type->flag & RE_USE_SHADING_NODES_CUSTOM); + RenderEngineType *type = RE_engines_find(scene->r.engine); + return (type && type->flag & RE_USE_SHADING_NODES_CUSTOM); } bool BKE_scene_uses_blender_internal(const Scene *scene) diff --git a/source/blender/blenkernel/intern/screen.c b/source/blender/blenkernel/intern/screen.c index 83aac79ae0b..6742a1fe80d 100644 --- a/source/blender/blenkernel/intern/screen.c +++ b/source/blender/blenkernel/intern/screen.c @@ -313,7 +313,16 @@ void BKE_area_region_free(SpaceType *st, ARegion *ar) ar->v2d.tab_offset = NULL; } - BLI_freelistN(&ar->panels); + if (!BLI_listbase_is_empty(&ar->panels)) { + Panel *pa, *pa_next; + for (pa = ar->panels.first; pa; pa = pa_next) { + pa_next = pa->next; + if (pa->activedata) { + MEM_freeN(pa->activedata); + } + MEM_freeN(pa); + } + } for (uilst = ar->ui_lists.first; uilst; uilst = uilst->next) { if (uilst->dyn_data) { diff --git a/source/blender/blenkernel/intern/seqeffects.c b/source/blender/blenkernel/intern/seqeffects.c index 3e6edbe01e8..f375c2b1e4f 100644 --- a/source/blender/blenkernel/intern/seqeffects.c +++ b/source/blender/blenkernel/intern/seqeffects.c @@ -38,11 +38,13 @@ #include "BLI_math.h" /* windows needs for M_PI */ #include "BLI_utildefines.h" +#include "BLI_rect.h" #include "BLI_string.h" #include "DNA_scene_types.h" #include "DNA_sequence_types.h" #include "DNA_anim_types.h" +#include "DNA_space_types.h" #include "BKE_fcurve.h" #include "BKE_sequencer.h" @@ -2480,7 +2482,7 @@ void BKE_sequence_effect_speed_rebuild_map(Scene *scene, Sequence *seq, bool for if ((seq->seq1->enddisp != seq->seq1->start) && (seq->seq1->len != 0)) { - fallback_fac = 1.0f; + fallback_fac = (float) seq->seq1->len / (float) (seq->seq1->enddisp - seq->seq1->start); flags = SEQ_SPEED_INTEGRATE; fcu = NULL; } @@ -2892,7 +2894,8 @@ static void init_text_effect(Sequence *seq) BLI_strncpy(data->text, "Text", sizeof(data->text)); data->loc[0] = 0.5f; - data->align = SEQ_TEXT_ALIGN_CENTER; + data->align = SEQ_TEXT_ALIGN_X_CENTER; + data->align_y = SEQ_TEXT_ALIGN_Y_BOTTOM; } static int num_inputs_text(void) @@ -2919,32 +2922,70 @@ static ImBuf *do_text_effect(const SeqRenderData *context, Sequence *seq, float struct ColorManagedDisplay *display; const char *display_device; const int mono = blf_mono_font_render; // XXX + int line_height; int y_ofs, x, y; + float proxy_size_comp; display_device = context->scene->display_settings.display_device; display = IMB_colormanagement_display_get_named(display_device); + /* Compensate text size for preview render size. */ + if (ELEM(context->preview_render_size, SEQ_PROXY_RENDER_SIZE_SCENE, SEQ_PROXY_RENDER_SIZE_FULL)) { + proxy_size_comp = context->scene->r.size / 100.0f; + } + else if (context->preview_render_size == SEQ_PROXY_RENDER_SIZE_100) { + proxy_size_comp = 1.0f; + } + else { + proxy_size_comp = context->preview_render_size / 100.0f; + } + /* set before return */ - BLF_size(mono, (context->scene->r.size / 100.0f) * data->text_size, 72); + BLF_size(mono, proxy_size_comp * data->text_size, 72); + + BLF_enable(mono, BLF_WORD_WRAP); + + /* use max width to enable newlines only */ + BLF_wordwrap(mono, (data->wrap_width != 0.0f) ? data->wrap_width * width : -1); BLF_buffer(mono, out->rect_float, (unsigned char *)out->rect, width, height, out->channels, display); + line_height = BLF_height_max(mono); + y_ofs = -BLF_descender(mono); x = (data->loc[0] * width); y = (data->loc[1] * height) + y_ofs; - if (data->align == SEQ_TEXT_ALIGN_LEFT) { - /* pass */ + if ((data->align == SEQ_TEXT_ALIGN_X_LEFT) && + (data->align_y == SEQ_TEXT_ALIGN_Y_TOP)) + { + y -= line_height; } else { - const int w = BLF_width(mono, data->text, sizeof(data->text)); + /* vars for calculating wordwrap */ + struct { + struct ResultBLF info; + rctf rect; + } wrap; + + BLF_boundbox_ex(mono, data->text, sizeof(data->text), &wrap.rect, &wrap.info); - if (data->align == SEQ_TEXT_ALIGN_RIGHT) { - x -= w; + if (data->align == SEQ_TEXT_ALIGN_X_RIGHT) { + x -= BLI_rctf_size_x(&wrap.rect); } - else { /* SEQ_TEXT_ALIGN_CENTER */ - x -= w / 2; + else if (data->align == SEQ_TEXT_ALIGN_X_CENTER) { + x -= BLI_rctf_size_x(&wrap.rect) / 2; + } + + if (data->align_y == SEQ_TEXT_ALIGN_Y_TOP) { + y -= line_height; + } + else if (data->align_y == SEQ_TEXT_ALIGN_Y_BOTTOM) { + y += (wrap.info.lines - 1) * line_height; + } + else if (data->align_y == SEQ_TEXT_ALIGN_Y_CENTER) { + y += (((wrap.info.lines - 1) / 2) * line_height) - (line_height / 2); } } @@ -2952,17 +2993,19 @@ static ImBuf *do_text_effect(const SeqRenderData *context, Sequence *seq, float if (data->flag & SEQ_TEXT_SHADOW) { int fontx, fonty; fontx = BLF_width_max(mono); - fonty = BLF_height_max(mono); - BLF_position(mono, x + max_ii(fontx / 25, 1), y + max_ii(fonty / 25, 1), 0.0); - BLF_buffer_col(mono, 0.0f, 0.0f, 0.0f, 1.0); - BLF_draw_buffer(mono, data->text); + fonty = line_height; + BLF_position(mono, x + max_ii(fontx / 25, 1), y + max_ii(fonty / 25, 1), 0.0f); + BLF_buffer_col(mono, 0.0f, 0.0f, 0.0f, 1.0f); + BLF_draw_buffer(mono, data->text, BLF_DRAW_STR_DUMMY_MAX); } - BLF_position(mono, x, y, 0.0); - BLF_buffer_col(mono, 1.0f, 1.0f, 1.0f, 1.0); - BLF_draw_buffer(mono, data->text); + BLF_position(mono, x, y, 0.0f); + BLF_buffer_col(mono, 1.0f, 1.0f, 1.0f, 1.0f); + BLF_draw_buffer(mono, data->text, BLF_DRAW_STR_DUMMY_MAX); BLF_buffer(mono, NULL, NULL, 0, 0, 0, NULL); + BLF_disable(mono, BLF_WORD_WRAP); + return out; } diff --git a/source/blender/blenkernel/intern/sequencer.c b/source/blender/blenkernel/intern/sequencer.c index aa0e13124b8..c070ad73156 100644 --- a/source/blender/blenkernel/intern/sequencer.c +++ b/source/blender/blenkernel/intern/sequencer.c @@ -563,6 +563,8 @@ void BKE_sequencer_new_render_data( r_context->skip_cache = false; r_context->is_proxy_render = false; r_context->view_id = 0; + r_context->gpu_offscreen = NULL; + r_context->gpu_samples = (scene->r.mode & R_OSA) ? scene->r.osa : 0; } /* ************************* iterator ************************** */ @@ -1013,6 +1015,15 @@ void BKE_sequencer_sort(Scene *scene) *(ed->seqbasep) = seqbase; } +/** Comparision function suitable to be used with BLI_listbase_sort()... */ +int BKE_sequencer_cmp_time_startdisp(const void *a, const void *b) +{ + const Sequence *seq_a = a; + const Sequence *seq_b = b; + + return (seq_a->startdisp > seq_b->startdisp); +} + static int clear_scene_in_allseqs_cb(Sequence *seq, void *arg_pt) { if (seq->scene == (Scene *)arg_pt) @@ -3009,6 +3020,7 @@ static ImBuf *seq_render_mask(const SeqRenderData *context, Mask *mask, float nr return NULL; } else { + AnimData *adt; Mask *mask_temp; MaskRasterHandle *mr_handle; @@ -3016,6 +3028,10 @@ static ImBuf *seq_render_mask(const SeqRenderData *context, Mask *mask, float nr BKE_mask_evaluate(mask_temp, mask->sfra + nr, true); + /* anim-data */ + adt = BKE_animdata_from_id(&mask->id); + BKE_animsys_evaluate_animdata(context->scene, &mask_temp->id, adt, nr, ADT_RECALC_ANIM); + maskbuf = MEM_mallocN(sizeof(float) * context->rectx * context->recty, __func__); mr_handle = BKE_maskrasterize_handle_new(); @@ -3083,10 +3099,17 @@ static ImBuf *seq_render_mask_strip(const SeqRenderData *context, Sequence *seq, static ImBuf *seq_render_scene_strip(const SeqRenderData *context, Sequence *seq, float nr, float cfra) { ImBuf *ibuf = NULL; - float frame; - float oldcfra; + double frame; Object *camera; - ListBase oldmarkers; + + struct { + int scemode; + int cfra; + float subframe; +#ifdef DURIAN_CAMERA_SWITCH + ListBase markers; +#endif + } orig_data; /* Old info: * Hack! This function can be called from do_render_seq(), in that case @@ -3124,10 +3147,11 @@ static ImBuf *seq_render_scene_strip(const SeqRenderData *context, Sequence *seq const bool do_seq_gl = is_rendering ? 0 /* (context->scene->r.seq_flag & R_SEQ_GL_REND) */ : (context->scene->r.seq_flag & R_SEQ_GL_PREV) != 0; - int do_seq; // bool have_seq = false; /* UNUSED */ bool have_comp = false; bool use_gpencil = true; + /* do we need to re-evaluate the frame after rendering? */ + bool is_frame_update = false; Scene *scene; int is_thread_main = BLI_thread_is_main(); @@ -3137,13 +3161,19 @@ static ImBuf *seq_render_scene_strip(const SeqRenderData *context, Sequence *seq } scene = seq->scene; - frame = scene->r.sfra + nr + seq->anim_startofs; + frame = (double)scene->r.sfra + (double)nr + (double)seq->anim_startofs; // have_seq = (scene->r.scemode & R_DOSEQ) && scene->ed && scene->ed->seqbase.first); /* UNUSED */ have_comp = (scene->r.scemode & R_DOCOMP) && scene->use_nodes && scene->nodetree; - oldcfra = scene->r.cfra; - scene->r.cfra = frame; + orig_data.scemode = scene->r.scemode; + orig_data.cfra = scene->r.cfra; + orig_data.subframe = scene->r.subframe; +#ifdef DURIAN_CAMERA_SWITCH + orig_data.markers = scene->markers; +#endif + + BKE_scene_frame_set(scene, frame); if (seq->scene_camera) { camera = seq->scene_camera; @@ -3153,27 +3183,24 @@ static ImBuf *seq_render_scene_strip(const SeqRenderData *context, Sequence *seq camera = scene->camera; } - if (seq->flag & SEQ_SCENE_NO_GPENCIL) { - use_gpencil = false; + if (have_comp == false && camera == NULL) { + goto finally; } - if (have_comp == false && camera == NULL) { - scene->r.cfra = oldcfra; - return NULL; + if (seq->flag & SEQ_SCENE_NO_GPENCIL) { + use_gpencil = false; } /* prevent eternal loop */ - do_seq = scene->r.scemode & R_DOSEQ; scene->r.scemode &= ~R_DOSEQ; #ifdef DURIAN_CAMERA_SWITCH /* stooping to new low's in hackyness :( */ - oldmarkers = scene->markers; BLI_listbase_clear(&scene->markers); -#else - (void)oldmarkers; #endif + is_frame_update = (orig_data.cfra != scene->r.cfra) || (orig_data.subframe != scene->r.subframe); + if ((sequencer_view3d_cb && do_seq_gl && camera) && is_thread_main) { char err_out[256] = "unknown"; int width = (scene->r.xsch * scene->r.size) / 100; @@ -3187,10 +3214,14 @@ static ImBuf *seq_render_scene_strip(const SeqRenderData *context, Sequence *seq /* opengl offscreen render */ BKE_scene_update_for_newframe(context->eval_ctx, context->bmain, scene, scene->lay); - ibuf = sequencer_view3d_cb(scene, camera, width, height, IB_rect, - context->scene->r.seq_prev_type, - (context->scene->r.seq_flag & R_SEQ_SOLID_TEX) != 0, - use_gpencil, true, scene->r.alphamode, viewname, err_out); + ibuf = sequencer_view3d_cb( + /* set for OpenGL render (NULL when scrubbing) */ + scene, camera, width, height, IB_rect, + context->scene->r.seq_prev_type, + (context->scene->r.seq_flag & R_SEQ_SOLID_TEX) != 0, + use_gpencil, true, scene->r.alphamode, + context->gpu_samples, viewname, + context->gpu_offscreen, err_out); if (ibuf == NULL) { fprintf(stderr, "seq_render_scene_strip failed to get opengl buffer: %s\n", err_out); } @@ -3268,19 +3299,21 @@ static ImBuf *seq_render_scene_strip(const SeqRenderData *context, Sequence *seq // BIF_end_render_callbacks(); } - + + +finally: /* restore */ - scene->r.scemode |= do_seq; - - scene->r.cfra = oldcfra; + scene->r.scemode = orig_data.scemode; + scene->r.cfra = orig_data.cfra; + scene->r.subframe = orig_data.subframe; - if (frame != oldcfra) { + if (is_frame_update) { BKE_scene_update_for_newframe(context->eval_ctx, context->bmain, scene, scene->lay); } - + #ifdef DURIAN_CAMERA_SWITCH /* stooping to new low's in hackyness :( */ - scene->markers = oldmarkers; + scene->markers = orig_data.markers; #endif return ibuf; @@ -3395,7 +3428,7 @@ static ImBuf *do_render_strip_uncached(const SeqRenderData *context, Sequence *s case SEQ_TYPE_MASK: { - /* ibuf is alwats new */ + /* ibuf is always new */ ibuf = seq_render_mask_strip(context, seq, nr); copy_to_ibuf_still(context, seq, nr, ibuf); @@ -3417,7 +3450,7 @@ static ImBuf *seq_render_strip(const SeqRenderData *context, Sequence *seq, floa float nr = give_stripelem_index(seq, cfra); /* all effects are handled similarly with the exception of speed effect */ int type = (seq->type & SEQ_TYPE_EFFECT && seq->type != SEQ_TYPE_SPEED) ? SEQ_TYPE_EFFECT : seq->type; - bool is_preprocessed = !ELEM(type, SEQ_TYPE_IMAGE, SEQ_TYPE_MOVIE, SEQ_TYPE_SCENE); + bool is_preprocessed = !ELEM(type, SEQ_TYPE_IMAGE, SEQ_TYPE_MOVIE, SEQ_TYPE_SCENE, SEQ_TYPE_MOVIECLIP); ibuf = BKE_sequencer_cache_get(context, seq, cfra, SEQ_STRIPELEM_IBUF); diff --git a/source/blender/blenkernel/intern/shrinkwrap.c b/source/blender/blenkernel/intern/shrinkwrap.c index 5ecd2fc74e8..40c58cea3d9 100644 --- a/source/blender/blenkernel/intern/shrinkwrap.c +++ b/source/blender/blenkernel/intern/shrinkwrap.c @@ -50,6 +50,7 @@ #include "BKE_lattice.h" #include "BKE_deform.h" +#include "BKE_editmesh.h" #include "BKE_mesh.h" /* for OMP limits. */ #include "BKE_subsurf.h" @@ -278,6 +279,16 @@ static void shrinkwrap_calc_normal_projection(ShrinkwrapCalcData *calc, bool for BLI_SPACE_TRANSFORM_SETUP(&local2aux, calc->ob, calc->smd->auxTarget); } + /* use editmesh to avoid array allocation */ + if (calc->smd->target && calc->target->type == DM_TYPE_EDITBMESH) { + treeData.em_evil = BKE_editmesh_from_object(calc->smd->target); + treeData.em_evil_all = true; + } + if (calc->smd->auxTarget && auxMesh->type == DM_TYPE_EDITBMESH) { + auxData.em_evil = BKE_editmesh_from_object(calc->smd->auxTarget); + auxData.em_evil_all = true; + } + /* After sucessufuly build the trees, start projection vertexs */ if (bvhtree_from_mesh_looptri(&treeData, calc->target, 0.0, 4, 6) && (auxMesh == NULL || bvhtree_from_mesh_looptri(&auxData, auxMesh, 0.0, 4, 6))) diff --git a/source/blender/blenkernel/intern/softbody.c b/source/blender/blenkernel/intern/softbody.c index b03c99c7a45..dac395645c9 100644 --- a/source/blender/blenkernel/intern/softbody.c +++ b/source/blender/blenkernel/intern/softbody.c @@ -1993,7 +1993,7 @@ static int _softbody_calc_forces_slice_in_a_thread(Scene *scene, Object *ob, flo compare = (obp->colball + bp->colball); sub_v3_v3v3(def, bp->pos, obp->pos); /* rather check the AABBoxes before ever calulating the real distance */ - /* mathematically it is completly nuts, but performance is pretty much (3) times faster */ + /* mathematically it is completely nuts, but performance is pretty much (3) times faster */ if ((ABS(def[0]) > compare) || (ABS(def[1]) > compare) || (ABS(def[2]) > compare)) continue; distance = normalize_v3(def); if (distance < compare ) { @@ -2361,7 +2361,7 @@ static void softbody_calc_forces(Scene *scene, Object *ob, float forcetime, floa sub_v3_v3v3(def, bp->pos, obp->pos); /* rather check the AABBoxes before ever calulating the real distance */ - /* mathematically it is completly nuts, but performance is pretty much (3) times faster */ + /* mathematically it is completely nuts, but performance is pretty much (3) times faster */ if ((ABS(def[0]) > compare) || (ABS(def[1]) > compare) || (ABS(def[2]) > compare)) continue; distance = normalize_v3(def); diff --git a/source/blender/blenkernel/intern/sound.c b/source/blender/blenkernel/intern/sound.c index 0b89931aa75..7e7cc8745fd 100644 --- a/source/blender/blenkernel/intern/sound.c +++ b/source/blender/blenkernel/intern/sound.c @@ -71,27 +71,20 @@ static int sound_cfra; static char **audio_device_names = NULL; #endif -bSound *BKE_sound_new_file(struct Main *bmain, const char *filename) +bSound *BKE_sound_new_file(struct Main *bmain, const char *filepath) { bSound *sound; - - char str[FILE_MAX]; const char *path; + char str[FILE_MAX]; - size_t len; - - BLI_strncpy(str, filename, sizeof(str)); + BLI_strncpy(str, filepath, sizeof(str)); path = /*bmain ? bmain->name :*/ G.main->name; BLI_path_abs(str, path); - len = strlen(filename); - while (len > 0 && filename[len - 1] != '/' && filename[len - 1] != '\\') - len--; - - sound = BKE_libblock_alloc(bmain, ID_SO, filename + len); - BLI_strncpy(sound->name, filename, FILE_MAX); + sound = BKE_libblock_alloc(bmain, ID_SO, BLI_path_basename(filepath)); + BLI_strncpy(sound->name, filepath, FILE_MAX); /* sound->type = SOUND_TYPE_FILE; */ /* XXX unused currently */ BKE_sound_load(bmain, sound); @@ -99,6 +92,37 @@ bSound *BKE_sound_new_file(struct Main *bmain, const char *filename) return sound; } +bSound *BKE_sound_new_file_exists_ex(struct Main *bmain, const char *filepath, bool *r_exists) +{ + bSound *sound; + char str[FILE_MAX], strtest[FILE_MAX]; + + BLI_strncpy(str, filepath, sizeof(str)); + BLI_path_abs(str, bmain->name); + + /* first search an identical filepath */ + for (sound = bmain->sound.first; sound; sound = sound->id.next) { + BLI_strncpy(strtest, sound->name, sizeof(sound->name)); + BLI_path_abs(strtest, ID_BLEND_PATH(bmain, &sound->id)); + + if (BLI_path_cmp(strtest, str) == 0) { + sound->id.us++; /* officially should not, it doesn't link here! */ + if (r_exists) + *r_exists = true; + return sound; + } + } + + if (r_exists) + *r_exists = false; + return BKE_sound_new_file(bmain, filepath); +} + +bSound *BKE_sound_new_file_exists(struct Main *bmain, const char *filepath) +{ + return BKE_sound_new_file_exists_ex(bmain, filepath, NULL); +} + void BKE_sound_free(bSound *sound) { if (sound->packedfile) { diff --git a/source/blender/blenkernel/intern/speaker.c b/source/blender/blenkernel/intern/speaker.c index 7a800555144..30296c7813c 100644 --- a/source/blender/blenkernel/intern/speaker.c +++ b/source/blender/blenkernel/intern/speaker.c @@ -37,11 +37,9 @@ #include "BKE_main.h" #include "BKE_speaker.h" -void *BKE_speaker_add(Main *bmain, const char *name) +void BKE_speaker_init(Speaker *spk) { - Speaker *spk; - - spk = BKE_libblock_alloc(bmain, ID_SPK, name); + BLI_assert(MEMCMP_STRUCT_OFS_IS_ZERO(spk, id)); spk->attenuation = 1.0f; spk->cone_angle_inner = 360.0f; @@ -55,6 +53,15 @@ void *BKE_speaker_add(Main *bmain, const char *name) spk->volume = 1.0f; spk->volume_max = 1.0f; spk->volume_min = 0.0f; +} + +void *BKE_speaker_add(Main *bmain, const char *name) +{ + Speaker *spk; + + spk = BKE_libblock_alloc(bmain, ID_SPK, name); + + BKE_speaker_init(spk); return spk; } diff --git a/source/blender/blenkernel/intern/subsurf_ccg.c b/source/blender/blenkernel/intern/subsurf_ccg.c index 998bb9835a8..a2c625a7ec3 100644 --- a/source/blender/blenkernel/intern/subsurf_ccg.c +++ b/source/blender/blenkernel/intern/subsurf_ccg.c @@ -796,7 +796,7 @@ static void ss_sync_from_derivedmesh(CCGSubSurf *ss, { #ifdef WITH_OPENSUBDIV /* Reset all related descriptors if actual mesh topology changed or if - * other evlauation-related settings changed. + * other evaluation-related settings changed. */ if (!ccgSubSurf_needGrids(ss)) { /* TODO(sergey): Use vertex coordinates and flat subdiv flag. */ @@ -1913,7 +1913,6 @@ static void ccgDM_buffer_copy_normal( int start = 0; CCG_key_top_level(&key, ss); - ccgdm_pbvh_update(ccgdm); for (i = 0; i < totface; i++) { CCGFace *f = ccgdm->faceMap[i].face; @@ -2008,7 +2007,8 @@ static void ccgDM_buffer_copy_triangles( const int *mat_orig_to_new) { GPUBufferMaterial *gpumat, *gpumaterials = dm->drawObject->materials; - const int totmat = dm->drawObject->totmaterial; + const int gpu_totmat = dm->drawObject->totmaterial; + const short dm_totmat = dm->totmat; CCGDerivedMesh *ccgdm = (CCGDerivedMesh *) dm; CCGSubSurf *ss = ccgdm->ss; CCGKey key; @@ -2016,13 +2016,14 @@ static void ccgDM_buffer_copy_triangles( int gridFaces = gridSize - 1; DMFlagMat *faceFlags = ccgdm->faceFlags; int i, totface = ccgSubSurf_getNumFaces(ss); - int matnr = -1, start; + short mat_nr = -1; + int start; int totloops = 0; - FaceCount *fc = MEM_mallocN(sizeof(*fc) * totmat, "gpumaterial.facecount"); + FaceCount *fc = MEM_mallocN(sizeof(*fc) * gpu_totmat, "gpumaterial.facecount"); CCG_key_top_level(&key, ss); - for (i = 0; i < totmat; i++) { + for (i = 0; i < gpu_totmat; i++) { fc[i].i_visible = 0; fc[i].i_tri_visible = 0; fc[i].i_hidden = gpumaterials[i].totpolys - 1; @@ -2037,14 +2038,14 @@ static void ccgDM_buffer_copy_triangles( int mati; if (faceFlags) { - matnr = faceFlags[index].mat_nr; + mat_nr = ME_MAT_NR_TEST(faceFlags[index].mat_nr, dm_totmat); is_hidden = (faceFlags[index].flag & ME_HIDE) != 0; } else { - matnr = 0; + mat_nr = 0; is_hidden = false; } - mati = mat_orig_to_new[matnr]; + mati = mat_orig_to_new[mat_nr]; gpumat = dm->drawObject->materials + mati; if (is_hidden) { @@ -2094,7 +2095,7 @@ static void ccgDM_buffer_copy_triangles( } /* set the visible polygons */ - for (i = 0; i < totmat; i++) { + for (i = 0; i < gpu_totmat; i++) { gpumaterials[i].totvisiblepolys = fc[i].i_visible; } @@ -2116,10 +2117,9 @@ static void ccgDM_buffer_copy_vertex( int totedge = ccgSubSurf_getNumEdges(ss); int start = 0; int edgeSize = ccgSubSurf_getEdgeSize(ss); - + CCG_key_top_level(&key, ss); - ccgdm_pbvh_update(ccgdm); - + for (i = 0; i < totface; i++) { CCGFace *f = ccgdm->faceMap[i].face; int S, x, y, numVerts = ccgSubSurf_getFaceNumVerts(f); @@ -2167,7 +2167,7 @@ static void ccgDM_buffer_copy_color( CCGDerivedMesh *ccgdm = (CCGDerivedMesh *) dm; CCGSubSurf *ss = ccgdm->ss; CCGKey key; - const char *mloopcol = user_data; + const unsigned char *mloopcol = user_data; int gridSize = ccgSubSurf_getGridSize(ss); int gridFaces = gridSize - 1; int i, totface = ccgSubSurf_getNumFaces(ss); @@ -2184,10 +2184,10 @@ static void ccgDM_buffer_copy_color( for (S = 0; S < numVerts; S++) { for (y = 0; y < gridFaces; y++) { for (x = 0; x < gridFaces; x++) { - copy_v3_v3_char((char *)&varray[start + 0], &mloopcol[iface * 16 + 0]); - copy_v3_v3_char((char *)&varray[start + 3], &mloopcol[iface * 16 + 12]); - copy_v3_v3_char((char *)&varray[start + 6], &mloopcol[iface * 16 + 8]); - copy_v3_v3_char((char *)&varray[start + 9], &mloopcol[iface * 16 + 4]); + copy_v3_v3_uchar(&varray[start + 0], &mloopcol[iface * 16 + 0]); + copy_v3_v3_uchar(&varray[start + 3], &mloopcol[iface * 16 + 12]); + copy_v3_v3_uchar(&varray[start + 6], &mloopcol[iface * 16 + 8]); + copy_v3_v3_uchar(&varray[start + 9], &mloopcol[iface * 16 + 4]); start += 12; iface++; @@ -2243,7 +2243,7 @@ static void ccgDM_buffer_copy_uv_texpaint( int i, totface = ccgSubSurf_getNumFaces(ss); int start = 0; DMFlagMat *faceFlags = ccgdm->faceFlags; - int totmaterial = dm->totmat; + int dm_totmat = dm->totmat; MLoopUV **mloopuv_base; MLoopUV *stencil_base; int stencil; @@ -2252,9 +2252,9 @@ static void ccgDM_buffer_copy_uv_texpaint( /* should have been checked for before, reassert */ BLI_assert(DM_get_loop_data_layer(dm, CD_MLOOPUV)); - mloopuv_base = MEM_mallocN(totmaterial * sizeof(*mloopuv_base), "texslots"); + mloopuv_base = MEM_mallocN(dm_totmat * sizeof(*mloopuv_base), "texslots"); - for (i = 0; i < totmaterial; i++) { + for (i = 0; i < dm_totmat; i++) { mloopuv_base[i] = DM_paint_uvlayer_active_get(dm, i); } @@ -2385,9 +2385,9 @@ static void ccgDM_buffer_copy_edge( /* part one, handle all normal edges */ for (j = 0; j < totedge; j++) { CCGFace *f; - int fhandle; - int totvert; - unsigned int S; + int fhandle = 0; + int totvert = 0; + unsigned int S = 0; CCGEdge *e = ccgdm->edgeMap[j].edge; bool isloose = !ccgSubSurf_getEdgeNumFaces(e); @@ -2541,7 +2541,7 @@ static GPUDrawObject *ccgDM_GPUObjectNew(DerivedMesh *dm) GPUDrawObject *gdo; DMFlagMat *faceFlags = ccgdm->faceFlags; int gridFaces = ccgSubSurf_getGridSize(ss) - 1; - int totmat = (faceFlags) ? dm->totmat : 1; + const short dm_totmat = (faceFlags) ? dm->totmat : 1; GPUBufferMaterial *matinfo; int i; unsigned int tot_internal_edges = 0; @@ -2552,16 +2552,16 @@ static GPUDrawObject *ccgDM_GPUObjectNew(DerivedMesh *dm) int totface = ccgSubSurf_getNumFaces(ss); /* object contains at least one material (default included) so zero means uninitialized dm */ - BLI_assert(totmat != 0); + BLI_assert(dm_totmat != 0); - matinfo = MEM_callocN(sizeof(*matinfo) * totmat, "GPU_drawobject_new.mat_orig_to_new"); + matinfo = MEM_callocN(sizeof(*matinfo) * dm_totmat, "GPU_drawobject_new.mat_orig_to_new"); if (faceFlags) { for (i = 0; i < totface; i++) { CCGFace *f = ccgdm->faceMap[i].face; int numVerts = ccgSubSurf_getFaceNumVerts(f); int index = GET_INT_FROM_POINTER(ccgSubSurf_getFaceFaceHandle(f)); - int new_matnr = faceFlags[index].mat_nr; + const short new_matnr = ME_MAT_NR_TEST(faceFlags[index].mat_nr, dm_totmat); matinfo[new_matnr].totelements += numVerts * gridFaces * gridFaces * 6; matinfo[new_matnr].totloops += numVerts * gridFaces * gridFaces * 4; matinfo[new_matnr].totpolys++; @@ -2584,7 +2584,7 @@ static GPUDrawObject *ccgDM_GPUObjectNew(DerivedMesh *dm) gdo->totvert = 0; /* used to count indices, doesn't really matter for ccgsubsurf */ gdo->totedge = (totedge * edgeSize + tot_internal_edges); - GPU_buffer_material_finalize(gdo, matinfo, totmat); + GPU_buffer_material_finalize(gdo, matinfo, dm_totmat); /* store total number of points used for triangles */ gdo->tot_triangle_point = ccgSubSurf_getNumFinalFaces(ss) * 6; @@ -2705,6 +2705,13 @@ static void ccgDM_drawFacesSolid(DerivedMesh *dm, float (*partial_redraw_planes) GPU_buffers_unbind(); } +typedef struct { + DMVertexAttribs attribs; + int numdata; + + GPUAttrib datatypes[GPU_MAX_ATTRIB]; /* TODO, messing up when switching materials many times - [#21056]*/ +} GPUMaterialConv; + /* Only used by non-editmesh types */ static void ccgDM_drawMappedFacesGLSL(DerivedMesh *dm, DMSetMaterial setMaterial, @@ -2715,14 +2722,15 @@ static void ccgDM_drawMappedFacesGLSL(DerivedMesh *dm, CCGSubSurf *ss = ccgdm->ss; CCGKey key; GPUVertexAttribs gattribs; - DMVertexAttribs attribs = {{{NULL}}}; - /* MTFace *tf = dm->getTessFaceDataArray(dm, CD_MTFACE); */ /* UNUSED */ + int a, b, do_draw, new_matnr; + DMFlagMat *faceFlags = ccgdm->faceFlags; + unsigned char *varray; + size_t max_element_size = 0; + int tot_loops = 0; + int totpoly = ccgSubSurf_getNumFaces(ss); int gridSize = ccgSubSurf_getGridSize(ss); int gridFaces = gridSize - 1; int edgeSize = ccgSubSurf_getEdgeSize(ss); - DMFlagMat *faceFlags = ccgdm->faceFlags; - const float (*lnors)[3] = dm->getLoopDataArray(dm, CD_NORMAL); - int a, i, do_draw, numVerts, matnr, new_matnr, totface; #ifdef WITH_OPENSUBDIV if (ccgdm->useGpuBackend) { @@ -2791,154 +2799,358 @@ static void ccgDM_drawMappedFacesGLSL(DerivedMesh *dm, } #endif + glShadeModel(GL_SMOOTH); + CCG_key_top_level(&key, ss); ccgdm_pbvh_update(ccgdm); - do_draw = 0; - matnr = -1; + /* workaround for NVIDIA GPUs on Mac not supporting vertex arrays + interleaved formats, see T43342 */ + if ((GPU_type_matches(GPU_DEVICE_NVIDIA, GPU_OS_MAC, GPU_DRIVER_ANY) && (U.gameflags & USER_DISABLE_VBO)) || + setDrawOptions != NULL) + { + const float (*lnors)[3] = dm->getLoopDataArray(dm, CD_NORMAL); + DMVertexAttribs attribs = {{{NULL}}}; + int i; + int matnr = -1; + do_draw = 0; #define PASSATTRIB(dx, dy, vert) { \ if (attribs.totorco) \ index = getFaceIndex(ss, f, S, x + dx, y + dy, edgeSize, gridSize); \ else \ index = 0; \ - DM_draw_attrib_vertex(&attribs, a, index, vert, ((a) * 4) + vert); \ + DM_draw_attrib_vertex(&attribs, a, index, vert, ((a) * 4) + vert); \ } (void)0 - totface = ccgSubSurf_getNumFaces(ss); - for (a = 0, i = 0; i < totface; i++) { - CCGFace *f = ccgdm->faceMap[i].face; - const float (*ln)[3] = NULL; - int S, x, y, drawSmooth; - int index = GET_INT_FROM_POINTER(ccgSubSurf_getFaceFaceHandle(f)); - int origIndex = ccgDM_getFaceMapIndex(ss, f); - - numVerts = ccgSubSurf_getFaceNumVerts(f); - - if (faceFlags) { - drawSmooth = (lnors || (faceFlags[index].flag & ME_SMOOTH)); - new_matnr = faceFlags[index].mat_nr + 1; - } - else { - drawSmooth = 1; - new_matnr = 1; - } - - if (lnors) { - ln = lnors; - lnors += (gridFaces * gridFaces * numVerts) * 4; - } + totpoly = ccgSubSurf_getNumFaces(ss); + for (a = 0, i = 0; i < totpoly; i++) { + CCGFace *f = ccgdm->faceMap[i].face; + const float (*ln)[3] = NULL; + int S, x, y, drawSmooth; + int index = GET_INT_FROM_POINTER(ccgSubSurf_getFaceFaceHandle(f)); + int origIndex = ccgDM_getFaceMapIndex(ss, f); - if (new_matnr != matnr) { - do_draw = setMaterial(matnr = new_matnr, &gattribs); - if (do_draw) - DM_vertex_attributes_from_gpu(dm, &gattribs, &attribs); - } + int numVerts = ccgSubSurf_getFaceNumVerts(f); - if (!do_draw || (setDrawOptions && (origIndex != ORIGINDEX_NONE) && - (setDrawOptions(userData, origIndex) == DM_DRAW_OPTION_SKIP))) - { - a += gridFaces * gridFaces * numVerts; - continue; - } + if (faceFlags) { + drawSmooth = (lnors || (faceFlags[index].flag & ME_SMOOTH)); + new_matnr = faceFlags[index].mat_nr + 1; + } + else { + drawSmooth = 1; + new_matnr = 1; + } - glShadeModel(drawSmooth ? GL_SMOOTH : GL_FLAT); - for (S = 0; S < numVerts; S++) { - CCGElem *faceGridData = ccgSubSurf_getFaceGridDataArray(ss, f, S); - CCGElem *vda, *vdb; + if (lnors) { + ln = lnors; + lnors += (gridFaces * gridFaces * numVerts) * 4; + } - if (ln) { - glBegin(GL_QUADS); - for (y = 0; y < gridFaces; y++) { - for (x = 0; x < gridFaces; x++) { - float *aco = CCG_grid_elem_co(&key, faceGridData, x, y); - float *bco = CCG_grid_elem_co(&key, faceGridData, x + 1, y); - float *cco = CCG_grid_elem_co(&key, faceGridData, x + 1, y + 1); - float *dco = CCG_grid_elem_co(&key, faceGridData, x, y + 1); + if (new_matnr != matnr) { + do_draw = setMaterial(matnr = new_matnr, &gattribs); + if (do_draw) + DM_vertex_attributes_from_gpu(dm, &gattribs, &attribs); + } - PASSATTRIB(0, 1, 1); - glNormal3fv(ln[1]); - glVertex3fv(dco); - PASSATTRIB(1, 1, 2); - glNormal3fv(ln[2]); - glVertex3fv(cco); - PASSATTRIB(1, 0, 3); - glNormal3fv(ln[3]); - glVertex3fv(bco); - PASSATTRIB(0, 0, 0); - glNormal3fv(ln[0]); - glVertex3fv(aco); + if (!do_draw || (setDrawOptions && (origIndex != ORIGINDEX_NONE) && + (setDrawOptions(userData, origIndex) == DM_DRAW_OPTION_SKIP))) + { + a += gridFaces * gridFaces * numVerts; + continue; + } - ln += 4; - a++; + glShadeModel(drawSmooth ? GL_SMOOTH : GL_FLAT); + for (S = 0; S < numVerts; S++) { + CCGElem *faceGridData = ccgSubSurf_getFaceGridDataArray(ss, f, S); + CCGElem *vda, *vdb; + + if (ln) { + glBegin(GL_QUADS); + for (y = 0; y < gridFaces; y++) { + for (x = 0; x < gridFaces; x++) { + float *aco = CCG_grid_elem_co(&key, faceGridData, x, y); + float *bco = CCG_grid_elem_co(&key, faceGridData, x + 1, y); + float *cco = CCG_grid_elem_co(&key, faceGridData, x + 1, y + 1); + float *dco = CCG_grid_elem_co(&key, faceGridData, x, y + 1); + + PASSATTRIB(0, 1, 1); + glNormal3fv(ln[1]); + glVertex3fv(dco); + PASSATTRIB(1, 1, 2); + glNormal3fv(ln[2]); + glVertex3fv(cco); + PASSATTRIB(1, 0, 3); + glNormal3fv(ln[3]); + glVertex3fv(bco); + PASSATTRIB(0, 0, 0); + glNormal3fv(ln[0]); + glVertex3fv(aco); + + ln += 4; + a++; + } } + glEnd(); } - glEnd(); - } - else if (drawSmooth) { - for (y = 0; y < gridFaces; y++) { - glBegin(GL_QUAD_STRIP); - for (x = 0; x < gridFaces; x++) { + else if (drawSmooth) { + for (y = 0; y < gridFaces; y++) { + glBegin(GL_QUAD_STRIP); + for (x = 0; x < gridFaces; x++) { + vda = CCG_grid_elem(&key, faceGridData, x, y + 0); + vdb = CCG_grid_elem(&key, faceGridData, x, y + 1); + + PASSATTRIB(0, 0, 0); + glNormal3fv(CCG_elem_no(&key, vda)); + glVertex3fv(CCG_elem_co(&key, vda)); + + PASSATTRIB(0, 1, 1); + glNormal3fv(CCG_elem_no(&key, vdb)); + glVertex3fv(CCG_elem_co(&key, vdb)); + + if (x != gridFaces - 1) + a++; + } + vda = CCG_grid_elem(&key, faceGridData, x, y + 0); vdb = CCG_grid_elem(&key, faceGridData, x, y + 1); - - PASSATTRIB(0, 0, 0); + + PASSATTRIB(0, 0, 3); glNormal3fv(CCG_elem_no(&key, vda)); glVertex3fv(CCG_elem_co(&key, vda)); - PASSATTRIB(0, 1, 1); + PASSATTRIB(0, 1, 2); glNormal3fv(CCG_elem_no(&key, vdb)); glVertex3fv(CCG_elem_co(&key, vdb)); - if (x != gridFaces - 1) + glEnd(); + + a++; + } + } + else { + glBegin(GL_QUADS); + for (y = 0; y < gridFaces; y++) { + for (x = 0; x < gridFaces; x++) { + float *aco = CCG_grid_elem_co(&key, faceGridData, x, y); + float *bco = CCG_grid_elem_co(&key, faceGridData, x + 1, y); + float *cco = CCG_grid_elem_co(&key, faceGridData, x + 1, y + 1); + float *dco = CCG_grid_elem_co(&key, faceGridData, x, y + 1); + + ccgDM_glNormalFast(aco, bco, cco, dco); + + PASSATTRIB(0, 1, 1); + glVertex3fv(dco); + PASSATTRIB(1, 1, 2); + glVertex3fv(cco); + PASSATTRIB(1, 0, 3); + glVertex3fv(bco); + PASSATTRIB(0, 0, 0); + glVertex3fv(aco); + a++; + } } + glEnd(); + } + } + } - vda = CCG_grid_elem(&key, faceGridData, x, y + 0); - vdb = CCG_grid_elem(&key, faceGridData, x, y + 1); +#undef PASSATTRIB + } + else { + GPUMaterialConv *matconv; + size_t offset; + int *mat_orig_to_new; + int tot_active_mat; + GPUBuffer *buffer = NULL; - PASSATTRIB(0, 0, 3); - glNormal3fv(CCG_elem_no(&key, vda)); - glVertex3fv(CCG_elem_co(&key, vda)); + GPU_vertex_setup(dm); + GPU_normal_setup(dm); + GPU_triangle_setup(dm); - PASSATTRIB(0, 1, 2); - glNormal3fv(CCG_elem_no(&key, vdb)); - glVertex3fv(CCG_elem_co(&key, vdb)); + tot_active_mat = dm->drawObject->totmaterial; - glEnd(); + matconv = MEM_callocN(sizeof(*matconv) * tot_active_mat, + "cdDM_drawMappedFacesGLSL.matconv"); + mat_orig_to_new = MEM_mallocN(sizeof(*mat_orig_to_new) * dm->totmat, + "cdDM_drawMappedFacesGLSL.mat_orig_to_new"); - a++; + /* part one, check what attributes are needed per material */ + for (a = 0; a < tot_active_mat; a++) { + new_matnr = dm->drawObject->materials[a].mat_nr; + + /* map from original material index to new + * GPUBufferMaterial index */ + mat_orig_to_new[new_matnr] = a; + do_draw = setMaterial(new_matnr + 1, &gattribs); + + if (do_draw) { + int numdata = 0; + DM_vertex_attributes_from_gpu(dm, &gattribs, &matconv[a].attribs); + + if (matconv[a].attribs.totorco && matconv[a].attribs.orco.array) { + matconv[a].datatypes[numdata].index = matconv[a].attribs.orco.gl_index; + matconv[a].datatypes[numdata].size = 3; + matconv[a].datatypes[numdata].type = GL_FLOAT; + numdata++; + } + for (b = 0; b < matconv[a].attribs.tottface; b++) { + if (matconv[a].attribs.tface[b].array) { + matconv[a].datatypes[numdata].index = matconv[a].attribs.tface[b].gl_index; + matconv[a].datatypes[numdata].size = 2; + matconv[a].datatypes[numdata].type = GL_FLOAT; + numdata++; + } + } + for (b = 0; b < matconv[a].attribs.totmcol; b++) { + if (matconv[a].attribs.mcol[b].array) { + matconv[a].datatypes[numdata].index = matconv[a].attribs.mcol[b].gl_index; + matconv[a].datatypes[numdata].size = 4; + matconv[a].datatypes[numdata].type = GL_UNSIGNED_BYTE; + numdata++; + } + } + if (matconv[a].attribs.tottang && matconv[a].attribs.tang.array) { + matconv[a].datatypes[numdata].index = matconv[a].attribs.tang.gl_index; + matconv[a].datatypes[numdata].size = 4; + matconv[a].datatypes[numdata].type = GL_FLOAT; + numdata++; + } + if (numdata != 0) { + matconv[a].numdata = numdata; + max_element_size = max_ii(GPU_attrib_element_size(matconv[a].datatypes, numdata), max_element_size); } } - else { - glBegin(GL_QUADS); - for (y = 0; y < gridFaces; y++) { - for (x = 0; x < gridFaces; x++) { - float *aco = CCG_grid_elem_co(&key, faceGridData, x, y); - float *bco = CCG_grid_elem_co(&key, faceGridData, x + 1, y); - float *cco = CCG_grid_elem_co(&key, faceGridData, x + 1, y + 1); - float *dco = CCG_grid_elem_co(&key, faceGridData, x, y + 1); + } - ccgDM_glNormalFast(aco, bco, cco, dco); + /* part two, generate and fill the arrays with the data */ + if (max_element_size > 0) { + buffer = GPU_buffer_alloc(max_element_size * dm->drawObject->tot_loop_verts, false); - PASSATTRIB(0, 1, 1); - glVertex3fv(dco); - PASSATTRIB(1, 1, 2); - glVertex3fv(cco); - PASSATTRIB(1, 0, 3); - glVertex3fv(bco); - PASSATTRIB(0, 0, 0); - glVertex3fv(aco); - - a++; + if (buffer == NULL) { + buffer = GPU_buffer_alloc(max_element_size * dm->drawObject->tot_loop_verts, true); + } + varray = GPU_buffer_lock_stream(buffer, GPU_BINDING_ARRAY); + if (varray == NULL) { + GPU_buffers_unbind(); + GPU_buffer_free(buffer); + MEM_freeN(mat_orig_to_new); + MEM_freeN(matconv); + fprintf(stderr, "Out of memory, can't draw object\n"); + return; + } + + for (a = 0; a < totpoly; a++) { + CCGFace *f = ccgdm->faceMap[a].face; + int index = GET_INT_FROM_POINTER(ccgSubSurf_getFaceFaceHandle(f)); + int S, x, y, numVerts = ccgSubSurf_getFaceNumVerts(f); + int i; + + if (faceFlags) { + i = mat_orig_to_new[faceFlags[index].mat_nr]; + } + else { + i = mat_orig_to_new[0]; + } + + if (matconv[i].numdata != 0) { + for (S = 0; S < numVerts; S++) { + for (y = 0; y < gridFaces; y++) { + for (x = 0; x < gridFaces; x++) { + + offset = tot_loops * max_element_size; + + if (matconv[i].attribs.totorco && matconv[i].attribs.orco.array) { + int index; + + index = getFaceIndex(ss, f, S, x, y, edgeSize, gridSize); + copy_v3_v3((float *)&varray[offset], + (float *)matconv[i].attribs.orco.array[index]); + index = getFaceIndex(ss, f, S, x + 1, y, edgeSize, gridSize); + copy_v3_v3((float *)&varray[offset + max_element_size], + (float *)matconv[i].attribs.orco.array[index]); + index = getFaceIndex(ss, f, S, x + 1, y + 1, edgeSize, gridSize); + copy_v3_v3((float *)&varray[offset + 2 * max_element_size], + (float *)matconv[i].attribs.orco.array[index]); + index = getFaceIndex(ss, f, S, x, y + 1, edgeSize, gridSize); + copy_v3_v3((float *)&varray[offset + 3 * max_element_size], + (float *)matconv[i].attribs.orco.array[index]); + + offset += sizeof(float) * 3; + } + for (b = 0; b < matconv[i].attribs.tottface; b++) { + if (matconv[i].attribs.tface[b].array) { + const MLoopUV *mloopuv = matconv[i].attribs.tface[b].array + tot_loops; + + copy_v2_v2((float *)&varray[offset], mloopuv[0].uv); + copy_v2_v2((float *)&varray[offset + max_element_size], mloopuv[3].uv); + copy_v2_v2((float *)&varray[offset + 2 * max_element_size], mloopuv[2].uv); + copy_v2_v2((float *)&varray[offset + 3 * max_element_size], mloopuv[1].uv); + + offset += sizeof(float) * 2; + } + } + for (b = 0; b < matconv[i].attribs.totmcol; b++) { + if (matconv[i].attribs.mcol[b].array) { + const MLoopCol *mloopcol = matconv[i].attribs.mcol[b].array + tot_loops; + + copy_v4_v4_uchar(&varray[offset], &mloopcol[0].r); + copy_v4_v4_uchar(&varray[offset + max_element_size], &mloopcol[3].r); + copy_v4_v4_uchar(&varray[offset + 2 * max_element_size], &mloopcol[2].r); + copy_v4_v4_uchar(&varray[offset + 3 * max_element_size], &mloopcol[1].r); + + offset += sizeof(unsigned char) * 4; + } + } + if (matconv[i].attribs.tottang && matconv[i].attribs.tang.array) { + const float (*looptang)[4] = (const float (*)[4])matconv[i].attribs.tang.array + tot_loops; + + copy_v4_v4((float *)&varray[offset], looptang[0]); + copy_v4_v4((float *)&varray[offset + max_element_size], looptang[3]); + copy_v4_v4((float *)&varray[offset + 2 * max_element_size], looptang[2]); + copy_v4_v4((float *)&varray[offset + 3 * max_element_size], looptang[1]); + + offset += sizeof(float) * 4; + } + + tot_loops += 4; + } + } } } - glEnd(); + else { + tot_loops += 4 * numVerts * gridFaces * gridFaces; + } } + GPU_buffer_unlock(buffer, GPU_BINDING_ARRAY); } + + for (a = 0; a < tot_active_mat; a++) { + new_matnr = dm->drawObject->materials[a].mat_nr; + + do_draw = setMaterial(new_matnr + 1, &gattribs); + + if (do_draw) { + if (matconv[a].numdata) { + GPU_interleaved_attrib_setup(buffer, matconv[a].datatypes, matconv[a].numdata, max_element_size); + } + GPU_buffer_draw_elements(dm->drawObject->triangles, GL_TRIANGLES, + dm->drawObject->materials[a].start, dm->drawObject->materials[a].totelements); + if (matconv[a].numdata) { + GPU_interleaved_attrib_unbind(); + } + } + } + + GPU_buffers_unbind(); + if (buffer) + GPU_buffer_free(buffer); + + MEM_freeN(mat_orig_to_new); + MEM_freeN(matconv); } -#undef PASSATTRIB + glShadeModel(GL_FLAT); } static void ccgDM_drawFacesGLSL(DerivedMesh *dm, DMSetMaterial setMaterial) @@ -4805,7 +5017,7 @@ struct DerivedMesh *subsurf_make_derived_from_derived( * * TODO(sergey): There was a good eason why final calculation * used to free entirely cached subsurf structure. reason of - * this is to be investiated still to be sure we don't have + * this is to be investigated still to be sure we don't have * regressions here. */ if (use_gpu_backend) { diff --git a/source/blender/blenkernel/intern/text.c b/source/blender/blenkernel/intern/text.c index 89456763b95..6e41ed3f9a6 100644 --- a/source/blender/blenkernel/intern/text.c +++ b/source/blender/blenkernel/intern/text.c @@ -171,14 +171,12 @@ void BKE_text_free(Text *text) #endif } -Text *BKE_text_add(Main *bmain, const char *name) +void BKE_text_init(Text *ta) { - Text *ta; TextLine *tmp; - - ta = BKE_libblock_alloc(bmain, ID_TXT, name); - ta->id.us = 1; - + + BLI_assert(MEMCMP_STRUCT_OFS_IS_ZERO(ta, id)); + ta->name = NULL; init_undo_text(ta); @@ -206,6 +204,15 @@ Text *BKE_text_add(Main *bmain, const char *name) ta->curc = 0; ta->sell = ta->lines.first; ta->selc = 0; +} + +Text *BKE_text_add(Main *bmain, const char *name) +{ + Text *ta; + + ta = BKE_libblock_alloc(bmain, ID_TXT, name); + + BKE_text_init(ta); return ta; } @@ -1914,9 +1921,13 @@ struct LinkInt { int value; }; -/* unindentLines points to a ListBase composed of LinkInt elements, listing the numbers - * of the lines that should not be indented back. */ -static void txt_undo_add_unindent_op(Text *text, const ListBase *line_index_mask, const int line_index_mask_len) +/** + * UnindentLines points to a #ListBase composed of #LinkInt elements, listing the numbers + * of the lines that should not be indented back. + */ +static void txt_undo_add_unprefix_op( + Text *text, char undo_op, + const ListBase *line_index_mask, const int line_index_mask_len) { struct LinkInt *idata; @@ -1929,7 +1940,7 @@ static void txt_undo_add_unindent_op(Text *text, const ListBase *line_index_mask /* Opening buffer sequence with OP */ text->undo_pos++; - text->undo_buf[text->undo_pos] = UNDO_UNINDENT; + text->undo_buf[text->undo_pos] = undo_op; text->undo_pos++; /* Adding number of line numbers to read */ txt_undo_store_uint32(text->undo_buf, &text->undo_pos, line_index_mask_len); @@ -1944,7 +1955,7 @@ static void txt_undo_add_unindent_op(Text *text, const ListBase *line_index_mask /* Adding current selection */ txt_undo_store_cursors(text); /* Closing with OP (same as above) */ - text->undo_buf[text->undo_pos] = UNDO_UNINDENT; + text->undo_buf[text->undo_pos] = undo_op; /* Marking as last undo operation */ text->undo_buf[text->undo_pos + 1] = 0; } @@ -2244,7 +2255,6 @@ void txt_do_undo(Text *text) break; case UNDO_INDENT: case UNDO_COMMENT: - case UNDO_UNCOMMENT: case UNDO_DUPLICATE: case UNDO_MOVE_LINES_UP: case UNDO_MOVE_LINES_DOWN: @@ -2259,9 +2269,6 @@ void txt_do_undo(Text *text) else if (op == UNDO_COMMENT) { txt_uncomment(text); } - else if (op == UNDO_UNCOMMENT) { - txt_comment(text); - } else if (op == UNDO_DUPLICATE) { txt_delete_line(text, text->curl->next); } @@ -2275,7 +2282,10 @@ void txt_do_undo(Text *text) text->undo_pos--; break; case UNDO_UNINDENT: + case UNDO_UNCOMMENT: { + void (*txt_prefix_fn)(Text *); + void (*txt_unprefix_fn)(Text *); int count; int i; /* Get and restore the cursors */ @@ -2284,7 +2294,16 @@ void txt_do_undo(Text *text) txt_move_to(text, selln, selc, 1); /* Un-unindent */ - txt_indent(text); + if (op == UNDO_UNINDENT) { + txt_prefix_fn = txt_indent; + txt_unprefix_fn = txt_unindent; + } + else { + txt_prefix_fn = txt_comment; + txt_unprefix_fn = txt_uncomment; + } + + txt_prefix_fn(text); /* Get the count */ count = txt_undo_read_uint32(text->undo_buf, &text->undo_pos); @@ -2293,8 +2312,8 @@ void txt_do_undo(Text *text) for (i = 0; i < count; i++) { txt_move_to(text, txt_undo_read_uint32(text->undo_buf, &text->undo_pos), 0, 0); - /* Un-un-unindent */ - txt_unindent(text); + /* Un-un-unindent/comment */ + txt_unprefix_fn(text); } /* Restore selection */ txt_move_to(text, curln, curc, 0); @@ -2823,26 +2842,19 @@ bool txt_replace_char(Text *text, unsigned int add) return true; } -void txt_indent(Text *text) +/** + * Generic prefix operation, use for comment & indent. + * + * \note caller must handle undo. + */ +static void txt_select_prefix(Text *text, const char *add) { int len, num, curc_old; char *tmp; - const char *add = "\t"; - int indentlen = 1; - - /* hardcoded: TXT_TABSIZE = 4 spaces: */ - int spaceslen = TXT_TABSIZE; + const int indentlen = strlen(add); - if (ELEM(NULL, text->curl, text->sell)) { - return; - } - - /* insert spaces rather than tabs */ - if (text->flags & TXT_TABSTOSPACES) { - add = tab_to_spaces; - indentlen = spaceslen; - } + BLI_assert(!ELEM(NULL, text->curl, text->sell)); curc_old = text->curc; @@ -2886,36 +2898,31 @@ void txt_indent(Text *text) num--; } - if (!undoing) { - txt_undo_add_op(text, UNDO_INDENT); - } + /* caller must handle undo */ } -void txt_unindent(Text *text) +/** + * Generic un-prefix operation, use for comment & indent. + * + * \param r_line_index_mask: List of lines that are already at indent level 0, + * to store them later into the undo buffer. + * + * \note caller must handle undo. + */ +static void txt_select_unprefix( + Text *text, const char *remove, + ListBase *r_line_index_mask, int *r_line_index_mask_len) { int num = 0; - const char *remove = "\t"; - int indentlen = 1; + const int indentlen = strlen(remove); bool unindented_first = false; - - /* List of lines that are already at indent level 0, to store them later into the undo buffer */ - ListBase line_index_mask = {NULL, NULL}; - int line_index_mask_len = 0; - int curl_span_init = 0; + int curl_span_init = 0; - /* hardcoded: TXT_TABSIZE = 4 spaces: */ - int spaceslen = TXT_TABSIZE; - - if (ELEM(NULL, text->curl, text->sell)) { - return; - } + BLI_assert(!ELEM(NULL, text->curl, text->sell)); - /* insert spaces rather than tabs */ - if (text->flags & TXT_TABSTOSPACES) { - remove = tab_to_spaces; - indentlen = spaceslen; - } + BLI_listbase_clear(r_line_index_mask); + *r_line_index_mask_len = 0; if (!undoing) { curl_span_init = txt_get_span(text->lines.first, text->curl); @@ -2936,8 +2943,8 @@ void txt_unindent(Text *text) struct LinkInt *idata = MEM_mallocN(sizeof(struct LinkInt), __func__); idata->value = curl_span_init + num; BLI_assert(idata->value == txt_get_span(text->lines.first, text->curl)); - BLI_addtail(&line_index_mask, idata); - line_index_mask_len += 1; + BLI_addtail(r_line_index_mask, idata); + (*r_line_index_mask_len) += 1; } } @@ -2964,57 +2971,20 @@ void txt_unindent(Text *text) text->curl = text->curl->prev; num--; } - - if (!undoing) { - txt_undo_add_unindent_op(text, &line_index_mask, line_index_mask_len); - } - BLI_freelistN(&line_index_mask); + /* caller must handle undo */ } void txt_comment(Text *text) { - int len, num; - char *tmp; - char add = '#'; + const char *prefix = "#"; - if (!text->curl) return; - if (!text->sell) return; // Need to change this need to check if only one line is selected to more than one + if (ELEM(NULL, text->curl, text->sell)) { + return; + } - num = 0; - while (true) { - tmp = MEM_mallocN(text->curl->len + 2, "textline_string"); - - text->curc = 0; - if (text->curc) memcpy(tmp, text->curl->line, text->curc); - tmp[text->curc] = add; - - len = text->curl->len - text->curc; - if (len > 0) memcpy(tmp + text->curc + 1, text->curl->line + text->curc, len); - tmp[text->curl->len + 1] = 0; + txt_select_prefix(text, prefix); - make_new_line(text->curl, tmp); - - text->curc++; - - txt_make_dirty(text); - txt_clean_text(text); - - if (text->curl == text->sell) { - text->selc = text->sell->len; - break; - } - else { - text->curl = text->curl->next; - num++; - } - } - text->curc = 0; - while (num > 0) { - text->curl = text->curl->prev; - num--; - } - if (!undoing) { txt_undo_add_op(text, UNDO_COMMENT); } @@ -3022,46 +2992,55 @@ void txt_comment(Text *text) void txt_uncomment(Text *text) { - int num = 0; - char remove = '#'; + const char *prefix = "#"; + ListBase line_index_mask; + int line_index_mask_len; - if (!text->curl) return; - if (!text->sell) return; + if (ELEM(NULL, text->curl, text->sell)) { + return; + } - while (true) { - int i = 0; - - if (text->curl->line[i] == remove) { - while (i < text->curl->len) { - text->curl->line[i] = text->curl->line[i + 1]; - i++; - } - text->curl->len--; - } - - - txt_make_dirty(text); - txt_clean_text(text); - - if (text->curl == text->sell) { - text->selc = text->sell->len; - break; - } - else { - text->curl = text->curl->next; - num++; - } - + txt_select_unprefix(text, prefix, &line_index_mask, &line_index_mask_len); + + if (!undoing) { + txt_undo_add_unprefix_op(text, UNDO_UNCOMMENT, &line_index_mask, line_index_mask_len); } - text->curc = 0; - while (num > 0) { - text->curl = text->curl->prev; - num--; + + BLI_freelistN(&line_index_mask); +} + +void txt_indent(Text *text) +{ + const char *prefix = (text->flags & TXT_TABSTOSPACES) ? tab_to_spaces : "\t"; + + if (ELEM(NULL, text->curl, text->sell)) { + return; } + + txt_select_prefix(text, prefix); + + if (!undoing) { + txt_undo_add_op(text, UNDO_INDENT); + } +} + +void txt_unindent(Text *text) +{ + const char *prefix = (text->flags & TXT_TABSTOSPACES) ? tab_to_spaces : "\t"; + ListBase line_index_mask; + int line_index_mask_len; + if (ELEM(NULL, text->curl, text->sell)) { + return; + } + + txt_select_unprefix(text, prefix, &line_index_mask, &line_index_mask_len); + if (!undoing) { - txt_undo_add_op(text, UNDO_UNCOMMENT); + txt_undo_add_unprefix_op(text, UNDO_UNINDENT, &line_index_mask, line_index_mask_len); } + + BLI_freelistN(&line_index_mask); } void txt_move_lines(struct Text *text, const int direction) diff --git a/source/blender/blenkernel/intern/texture.c b/source/blender/blenkernel/intern/texture.c index 88a412d5e95..463ca250ad5 100644 --- a/source/blender/blenkernel/intern/texture.c +++ b/source/blender/blenkernel/intern/texture.c @@ -580,6 +580,8 @@ void BKE_texture_free(Tex *tex) void BKE_texture_default(Tex *tex) { + /* BLI_assert(MEMCMP_STRUCT_OFS_IS_ZERO(tex, id)); */ /* Not here, can be called with some pointers set. :/ */ + tex->type = TEX_IMAGE; tex->ima = NULL; tex->stype = 0; diff --git a/source/blender/blenkernel/intern/unit.c b/source/blender/blenkernel/intern/unit.c index 64d561491e2..ab8fbabd329 100644 --- a/source/blender/blenkernel/intern/unit.c +++ b/source/blender/blenkernel/intern/unit.c @@ -730,11 +730,10 @@ void bUnit_ToUnitAltName(char *str, int len_max, const char *orig_str, int syste bUnitCollection *usys = unit_get_system(system, type); bUnitDef *unit; - bUnitDef *unit_def = unit_default(usys); /* find and substitute all units */ for (unit = usys->units; unit->name; unit++) { - if (len_max > 0 && (unit->name_alt || unit == unit_def)) { + if (len_max > 0 && unit->name_alt) { const char *found = unit_find_str(orig_str, unit->name_short); if (found) { int offset = (int)(found - orig_str); diff --git a/source/blender/blenkernel/intern/world.c b/source/blender/blenkernel/intern/world.c index e4736b1f54c..88c98b6d9d8 100644 --- a/source/blender/blenkernel/intern/world.c +++ b/source/blender/blenkernel/intern/world.c @@ -31,6 +31,7 @@ #include <string.h> +#include <stdlib.h> #include <math.h> #include "MEM_guardedalloc.h" @@ -83,12 +84,10 @@ void BKE_world_free(World *wrld) BKE_world_free_ex(wrld, true); } -World *add_world(Main *bmain, const char *name) +void BKE_world_init(World *wrld) { - World *wrld; + BLI_assert(MEMCMP_STRUCT_OFS_IS_ZERO(wrld, id)); - wrld = BKE_libblock_alloc(bmain, ID_WO, name); - wrld->horr = 0.05f; wrld->horg = 0.05f; wrld->horb = 0.05f; @@ -113,6 +112,15 @@ World *add_world(Main *bmain, const char *name) wrld->preview = NULL; wrld->miststa = 5.0f; wrld->mistdist = 25.0f; +} + +World *add_world(Main *bmain, const char *name) +{ + World *wrld; + + wrld = BKE_libblock_alloc(bmain, ID_WO, name); + + BKE_world_init(wrld); return wrld; } diff --git a/source/blender/blenkernel/intern/writeavi.c b/source/blender/blenkernel/intern/writeavi.c index cec455e01b9..82e4405225a 100644 --- a/source/blender/blenkernel/intern/writeavi.c +++ b/source/blender/blenkernel/intern/writeavi.c @@ -147,7 +147,9 @@ bMovieHandle *BKE_movie_handle_get(const char imtype) #endif /* in case all above are disabled */ - (void)imtype;return &mh; + (void)imtype; + + return (mh.append_movie != append_stub) ? &mh : NULL; } /* ****************************************************************** */ @@ -298,8 +300,10 @@ static void context_free_avi(void *context_v) void BKE_movie_filepath_get(char *string, RenderData *rd, bool preview, const char *suffix) { bMovieHandle *mh = BKE_movie_handle_get(rd->im_format.imtype); - if (mh->get_movie_path) + if (mh && mh->get_movie_path) { mh->get_movie_path(string, rd, preview, suffix); - else + } + else { string[0] = '\0'; + } } diff --git a/source/blender/blenkernel/intern/writeffmpeg.c b/source/blender/blenkernel/intern/writeffmpeg.c index 0668e7f95e2..1a63bacf17a 100644 --- a/source/blender/blenkernel/intern/writeffmpeg.c +++ b/source/blender/blenkernel/intern/writeffmpeg.c @@ -746,7 +746,7 @@ static AVStream *alloc_audio_stream(FFMpegContext *context, RenderData *rd, int av_dict_free(&opts); /* need to prevent floating point exception when using vorbis audio codec, - * initialize this value in the same way as it's done in FFmpeg iteslf (sergey) */ + * initialize this value in the same way as it's done in FFmpeg itself (sergey) */ st->codec->time_base.num = 1; st->codec->time_base.den = st->codec->sample_rate; @@ -1198,8 +1198,6 @@ int BKE_ffmpeg_append(void *context_v, RenderData *rd, int start_frame, int fram static void end_ffmpeg_impl(FFMpegContext *context, int is_autosplit) { - unsigned int i; - PRINT("Closing ffmpeg...\n"); #if 0 @@ -1234,15 +1232,6 @@ static void end_ffmpeg_impl(FFMpegContext *context, int is_autosplit) context->video_stream = 0; } - - /* Close the output file */ - if (context->outfile) { - for (i = 0; i < context->outfile->nb_streams; i++) { - if (&context->outfile->streams[i]) { - av_freep(&context->outfile->streams[i]); - } - } - } /* free the temp buffer */ if (context->current_frame) { delete_picture(context->current_frame); @@ -1254,7 +1243,7 @@ static void end_ffmpeg_impl(FFMpegContext *context, int is_autosplit) } } if (context->outfile) { - av_free(context->outfile); + avformat_free_context(context->outfile); context->outfile = 0; } if (context->audio_input_buffer) { diff --git a/source/blender/blenlib/BLI_alloca.h b/source/blender/blenlib/BLI_alloca.h index fd814940624..b44e6c66d2a 100644 --- a/source/blender/blenlib/BLI_alloca.h +++ b/source/blender/blenlib/BLI_alloca.h @@ -34,8 +34,13 @@ #endif #if defined(__GNUC__) || defined(__clang__) +#if defined(__cplusplus) && (__cplusplus > 199711L) +#define BLI_array_alloca(arr, realsize) \ + (decltype(arr))alloca(sizeof(*arr) * (realsize)) +#else #define BLI_array_alloca(arr, realsize) \ (typeof(arr))alloca(sizeof(*arr) * (realsize)) +#endif #else #define BLI_array_alloca(arr, realsize) \ alloca(sizeof(*arr) * (realsize)) diff --git a/source/blender/blenlib/BLI_buffer.h b/source/blender/blenlib/BLI_buffer.h index 4e5b61da532..6ea9e765c1d 100644 --- a/source/blender/blenlib/BLI_buffer.h +++ b/source/blender/blenlib/BLI_buffer.h @@ -23,27 +23,12 @@ /** \file BLI_buffer.h * \ingroup bli - * - * \note this more or less fills same purpose as BLI_array, but makes - * it much easier to resize the array outside of the function it was - * declared in since. - * - * Usage examples: - * \code{.c} - * BLI_buffer_declare_static(int, my_int_array, BLI_BUFFER_NOP, 32); - * - * BLI_buffer_append(my_int_array, int, 42); - * assert(my_int_array.count == 1); - * assert(BLI_buffer_at(my_int_array, int, 0) == 42); - * - * BLI_buffer_free(&my_int_array); - * \endcode */ typedef struct { void *data; - const int elem_size; - int count, alloc_count; + const size_t elem_size; + size_t count, alloc_count; int flag; } BLI_Buffer; @@ -79,7 +64,7 @@ enum { #define BLI_buffer_at(buffer_, type_, index_) ( \ (((type_ *)(buffer_)->data)[ \ (BLI_assert(sizeof(type_) == (buffer_)->elem_size)), \ - (BLI_assert(index_ >= 0 && index_ < (buffer_)->count)), \ + (BLI_assert((int)(index_) >= 0 && (size_t)(index_) < (buffer_)->count)), \ index_])) #define BLI_buffer_array(buffer_, type_) ( \ @@ -88,6 +73,9 @@ enum { #define BLI_buffer_resize_data(buffer_, type_, new_count_) ( \ (BLI_buffer_resize(buffer_, new_count_), new_count_ ? BLI_buffer_array(buffer_, type_) : NULL)) +#define BLI_buffer_reinit_data(buffer_, type_, new_count_) ( \ + (BLI_buffer_reinit(buffer_, new_count_), new_count_ ? BLI_buffer_array(buffer_, type_) : NULL)) + #define BLI_buffer_append(buffer_, type_, val_) ( \ BLI_buffer_resize(buffer_, (buffer_)->count + 1), \ (BLI_buffer_at(buffer_, type_, (buffer_)->count - 1) = val_) \ @@ -98,7 +86,10 @@ enum { } (void)0 /* Never decreases the amount of memory allocated */ -void BLI_buffer_resize(BLI_Buffer *buffer, int new_count); +void BLI_buffer_resize(BLI_Buffer *buffer, const size_t new_count); + +/* Ensure size, throwing away old data, respecting BLI_BUFFER_USE_CALLOC */ +void BLI_buffer_reinit(BLI_Buffer *buffer, const size_t new_count); /* Does not free the buffer structure itself */ void _bli_buffer_free(BLI_Buffer *buffer); diff --git a/source/blender/blenlib/BLI_fileops.h b/source/blender/blenlib/BLI_fileops.h index 33dae45ac26..53ebc81fe22 100644 --- a/source/blender/blenlib/BLI_fileops.h +++ b/source/blender/blenlib/BLI_fileops.h @@ -89,7 +89,7 @@ bool BLI_is_dir(const char *path) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); bool BLI_is_file(const char *path) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); bool BLI_dir_create_recursive(const char *dir) ATTR_NONNULL(); double BLI_dir_free_space(const char *dir) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); -char *BLI_current_working_dir(char *dir, const size_t maxlen) ATTR_NONNULL(); +char *BLI_current_working_dir(char *dir, const size_t maxlen) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); /* Filelist */ diff --git a/source/blender/blenlib/BLI_math_geom.h b/source/blender/blenlib/BLI_math_geom.h index 1a25f9f897f..dfc51895c77 100644 --- a/source/blender/blenlib/BLI_math_geom.h +++ b/source/blender/blenlib/BLI_math_geom.h @@ -119,14 +119,25 @@ float dist_signed_squared_to_corner_v3v3v3( float closest_to_line_v3(float r[3], const float p[3], const float l1[3], const float l2[3]); float closest_to_line_v2(float r[2], const float p[2], const float l1[2], const float l2[2]); void closest_to_line_segment_v3(float r_close[3], const float p[3], const float l1[3], const float l2[3]); +void closest_to_plane_normalized_v3(float r_close[3], const float plane[4], const float pt[3]); void closest_to_plane_v3(float r_close[3], const float plane[4], const float pt[3]); +void closest_to_plane3_normalized_v3(float r_close[3], const float plane[3], const float pt[3]); +void closest_to_plane3_v3(float r_close[3], const float plane[3], const float pt[3]); /* Set 'r' to the point in triangle (t1, t2, t3) closest to point 'p' */ void closest_on_tri_to_point_v3(float r[3], const float p[3], const float t1[3], const float t2[3], const float t3[3]); +float line_point_factor_v3_ex( + const float p[3], const float l1[3], const float l2[3], + const float epsilon, const float fallback); +float line_point_factor_v3( + const float p[3], const float l1[3], const float l2[3]); -float line_point_factor_v3(const float p[3], const float l1[3], const float l2[3]); -float line_point_factor_v2(const float p[2], const float l1[2], const float l2[2]); +float line_point_factor_v2_ex( + const float p[2], const float l1[2], const float l2[2], + const float epsilon, const float fallback); +float line_point_factor_v2( + const float p[2], const float l1[2], const float l2[2]); float line_plane_factor_v3(const float plane_co[3], const float plane_no[3], const float l1[3], const float l2[3]); @@ -165,16 +176,19 @@ bool isect_line_line_strict_v3(const float v1[3], const float v2[3], bool isect_ray_plane_v3( const float p1[3], const float d[3], - const float v0[3], const float v1[3], const float v2[3], + const float plane[4], float *r_lambda, const bool clip); bool isect_point_planes_v3(float (*planes)[4], int totplane, const float p[3]); bool isect_line_plane_v3(float out[3], const float l1[3], const float l2[3], const float plane_co[3], const float plane_no[3]) ATTR_WARN_UNUSED_RESULT; -bool isect_plane_plane_v3(float r_isect_co[3], float r_isect_no[3], - const float plane_a_co[3], const float plane_a_no[3], - const float plane_b_co[3], const float plane_b_no[3]) ATTR_WARN_UNUSED_RESULT; +bool isect_plane_plane_plane_v3( + const float plane_a[4], const float plane_b[4], const float plane_c[4], + float r_isect_co[3]) ATTR_WARN_UNUSED_RESULT; +bool isect_plane_plane_v3( + const float plane_a[4], const float plane_b[4], + float r_isect_co[3], float r_isect_no[3]) ATTR_WARN_UNUSED_RESULT; /* line/ray triangle */ bool isect_line_tri_v3( diff --git a/source/blender/blenlib/BLI_math_inline.h b/source/blender/blenlib/BLI_math_inline.h index 2bf3b9532dd..840cf24f8cf 100644 --- a/source/blender/blenlib/BLI_math_inline.h +++ b/source/blender/blenlib/BLI_math_inline.h @@ -46,9 +46,9 @@ extern "C" { # define MINLINE static inline # if (defined(__APPLE__) && defined(__ppc__)) /* static inline __attribute__ here breaks osx ppc gcc42 build */ -# define MALWAYS_INLINE static __attribute__((always_inline)) +# define MALWAYS_INLINE static __attribute__((always_inline)) __attribute__((unused)) # else -# define MALWAYS_INLINE static inline __attribute__((always_inline)) +# define MALWAYS_INLINE static inline __attribute__((always_inline)) __attribute__((unused)) # endif # endif #else diff --git a/source/blender/blenlib/BLI_math_matrix.h b/source/blender/blenlib/BLI_math_matrix.h index d7a309e0835..5900e391d3e 100644 --- a/source/blender/blenlib/BLI_math_matrix.h +++ b/source/blender/blenlib/BLI_math_matrix.h @@ -153,10 +153,14 @@ void transpose_m4_m4(float R[4][4], float A[4][4]); int compare_m4m4(float mat1[4][4], float mat2[4][4], float limit); -void normalize_m3(float R[3][3]); -void normalize_m3_m3(float R[3][3], float A[3][3]); -void normalize_m4(float R[4][4]); -void normalize_m4_m4(float R[4][4], float A[4][4]); +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_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 orthogonalize_m3(float R[3][3], int axis); void orthogonalize_m4(float R[4][4], int axis); @@ -215,6 +219,8 @@ void mat4_to_loc_rot_size(float loc[3], float rot[3][3], float size[3], float wm 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_polar_decompose(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]); void loc_eulO_size_to_mat4(float R[4][4], @@ -227,6 +233,9 @@ void loc_axisangle_size_to_mat4(float R[4][4], 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 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); + bool is_negative_m3(float mat[3][3]); bool is_negative_m4(float mat[4][4]); diff --git a/source/blender/blenlib/BLI_math_solvers.h b/source/blender/blenlib/BLI_math_solvers.h index ec9ba5538e2..810c84cc830 100644 --- a/source/blender/blenlib/BLI_math_solvers.h +++ b/source/blender/blenlib/BLI_math_solvers.h @@ -46,6 +46,7 @@ extern "C" { bool BLI_eigen_solve_selfadjoint_m3(const float m3[3][3], float r_eigen_values[3], float r_eigen_vectors[3][3]); +void BLI_svd_m3(const float m3[3][3], float r_U[3][3], float r_S[], float r_V[3][3]); /**************************** Inline Definitions ******************************/ #if 0 /* None so far. */ diff --git a/source/blender/blenlib/BLI_math_vector.h b/source/blender/blenlib/BLI_math_vector.h index 493c285d251..01c00ddb48e 100644 --- a/source/blender/blenlib/BLI_math_vector.h +++ b/source/blender/blenlib/BLI_math_vector.h @@ -61,11 +61,14 @@ MINLINE void swap_v2_v2(float a[2], float b[2]); MINLINE void swap_v3_v3(float a[3], float b[3]); MINLINE void swap_v4_v4(float a[4], float b[4]); +/* unsigned char */ +MINLINE void copy_v2_v2_uchar(unsigned char r[2], const unsigned char a[2]); +MINLINE void copy_v3_v3_uchar(unsigned char r[3], const unsigned char a[3]); +MINLINE void copy_v4_v4_uchar(unsigned char r[4], const unsigned char a[4]); /* char */ MINLINE void copy_v2_v2_char(char r[2], const char a[2]); MINLINE void copy_v3_v3_char(char r[3], const char a[3]); MINLINE void copy_v4_v4_char(char r[4], const char a[4]); - /* short */ MINLINE void copy_v2_v2_short(short r[2], const short a[2]); MINLINE void copy_v3_v3_short(short r[3], const short a[3]); @@ -307,7 +310,7 @@ MINLINE void normal_float_to_short_v3(short r[3], const float n[3]); void minmax_v3v3_v3(float min[3], float max[3], const float vec[3]); void minmax_v2v2_v2(float min[2], float max[2], const float vec[2]); -void minmax_v3v3_v3_array(float r_min[3], float r_max[3], float (*vec_arr)[3], int nbr); +void minmax_v3v3_v3_array(float r_min[3], float r_max[3], const float (*vec_arr)[3], int nbr); void dist_ensure_v3_v3fl(float v1[3], const float v2[3], const float dist); void dist_ensure_v2_v2fl(float v1[2], const float v2[2], const float dist); diff --git a/source/blender/blenlib/BLI_memory_utils.h b/source/blender/blenlib/BLI_memory_utils.h new file mode 100644 index 00000000000..32bbdf8a7b5 --- /dev/null +++ b/source/blender/blenlib/BLI_memory_utils.h @@ -0,0 +1,34 @@ +/* + * ***** 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 ***** + */ + +#ifndef __BLI_MEMORY_UTILS_H__ +#define __BLI_MEMORY_UTILS_H__ + +/** \file BLI_memory_utils.h + * \ingroup bli + * \brief Generic memory manipulation API. + */ + +/* it may be defined already */ +#ifndef __BLI_UTILDEFINES_H__ +bool BLI_memory_is_zero(const void *arr, const size_t size); +#endif + +#endif /* __BLI_MEMORY_UTILS_H__ */ diff --git a/source/blender/blenlib/BLI_path_util.h b/source/blender/blenlib/BLI_path_util.h index a344c9d2bc1..1a626ff44bd 100644 --- a/source/blender/blenlib/BLI_path_util.h +++ b/source/blender/blenlib/BLI_path_util.h @@ -99,12 +99,6 @@ int BLI_stringdec(const char *string, char *head, char *start, unsigned short *n void BLI_stringenc(char *string, const char *head, const char *tail, unsigned short numlen, int pic); int BLI_split_name_num(char *left, int *nr, const char *name, const char delim); -/** - * dir can be any input, like from buttons, and this function - * converts it to a regular full path. - * Also removes garbage from directory paths, like /../ or double slashes etc - */ - /* removes trailing slash */ void BLI_cleanup_file(const char *relabase, char *path) ATTR_NONNULL(2); /* same as above but adds a trailing slash */ @@ -118,25 +112,13 @@ bool BLI_path_make_safe(char *path) ATTR_NONNULL(1); /* go back one directory */ bool BLI_parent_dir(char *path) ATTR_NONNULL(); -/** - * Blender's path code replacement function. - * Bases \a path strings leading with "//" by the - * directory \a basepath, and replaces instances of - * '#' with the \a framenum. Results are written - * back into \a path. - * - * \a path The path to convert - * \a basepath The directory to base relative paths with. - * \a framenum The framenumber to replace the frame code with. - * \retval Returns true if the path was relative (started with "//"). - */ bool BLI_path_abs(char *path, const char *basepath) ATTR_NONNULL(); bool BLI_path_frame(char *path, int frame, int digits) ATTR_NONNULL(); bool BLI_path_frame_range(char *path, int sta, int end, int digits) ATTR_NONNULL(); bool BLI_path_frame_get(char *path, int *r_frame, int *numdigits) ATTR_NONNULL(); -void BLI_path_frame_strip(char *path, bool setsharp, char *ext) ATTR_NONNULL(); +void BLI_path_frame_strip(char *path, bool set_frame_char, char *ext) ATTR_NONNULL(); bool BLI_path_frame_check_chars(const char *path) ATTR_NONNULL(); -bool BLI_path_cwd(char *path) ATTR_NONNULL(); +bool BLI_path_cwd(char *path, const size_t maxlen) ATTR_NONNULL(); void BLI_path_rel(char *file, const char *relfile) ATTR_NONNULL(); bool BLI_path_is_rel(const char *path) ATTR_NONNULL() ATTR_WARN_UNUSED_RESULT; @@ -158,10 +140,6 @@ bool BLI_path_suffix(char *string, size_t maxlen, const char *suffix, const char # define BLI_path_ncmp strncmp #endif -#ifdef WITH_ICONV -void BLI_string_to_utf8(char *original, char *utf_8, const char *code); -#endif - /* these values need to be hardcoded in structs, dna does not recognize defines */ /* also defined in DNA_space_types.h */ #ifndef FILE_MAXDIR @@ -183,5 +161,4 @@ void BLI_string_to_utf8(char *original, char *utf_8, const char *code); } #endif -#endif - +#endif /* __BLI_PATH_UTIL_H__ */ diff --git a/source/blender/blenlib/BLI_rect.h b/source/blender/blenlib/BLI_rect.h index a98931d2ae8..59bf3644912 100644 --- a/source/blender/blenlib/BLI_rect.h +++ b/source/blender/blenlib/BLI_rect.h @@ -66,6 +66,8 @@ void BLI_rctf_interp(struct rctf *rect, const struct rctf *rect_a, const struct //void BLI_rcti_interp(struct rctf *rect, struct rctf *rect_a, struct rctf *rect_b, float fac); bool BLI_rctf_clamp_pt_v(const struct rctf *rect, float xy[2]); bool BLI_rcti_clamp_pt_v(const struct rcti *rect, int xy[2]); +bool BLI_rctf_clamp(struct rctf *rect, const struct rctf *rect_bounds, float r_xy[2]); +bool BLI_rcti_clamp(struct rcti *rect, const struct rcti *rect_bounds, int r_xy[2]); bool BLI_rctf_compare(const struct rctf *rect_a, const struct rctf *rect_b, const float limit); bool BLI_rcti_compare(const struct rcti *rect_a, const struct rcti *rect_b); bool BLI_rctf_isect(const struct rctf *src1, const struct rctf *src2, struct rctf *dest); diff --git a/source/blender/blenlib/BLI_utildefines.h b/source/blender/blenlib/BLI_utildefines.h index 65e8dcdba4a..31852fa0f43 100644 --- a/source/blender/blenlib/BLI_utildefines.h +++ b/source/blender/blenlib/BLI_utildefines.h @@ -513,6 +513,17 @@ extern "C" { sizeof(*(struct_var)) - OFFSETOF_STRUCT(struct_var, member)); \ } (void)0 +/* defined + * in memory_utils.c for now. I do not know where we should put it actually... */ +#ifndef __BLI_MEMORY_UTILS_H__ +extern bool BLI_memory_is_zero(const void *arr, const size_t arr_size); +#endif + +#define MEMCMP_STRUCT_OFS_IS_ZERO(struct_var, member) \ + (BLI_memory_is_zero( \ + (char *)(struct_var) + OFFSETOF_STRUCT(struct_var, member), \ + sizeof(*(struct_var)) - OFFSETOF_STRUCT(struct_var, member))) + /* Warning-free macros for storing ints in pointers. Use these _only_ * for storing an int in a pointer, not a pointer in an int (64bit)! */ #define SET_INT_IN_POINTER(i) ((void *)(intptr_t)(i)) @@ -623,9 +634,9 @@ extern "C" { #else # if (defined(__APPLE__) && defined(__ppc__)) /* static inline __attribute__ here breaks osx ppc gcc42 build */ -# define BLI_INLINE static __attribute__((always_inline)) +# define BLI_INLINE static __attribute__((always_inline)) __attribute__((__unused__)) # else -# define BLI_INLINE static inline __attribute__((always_inline)) +# define BLI_INLINE static inline __attribute__((always_inline)) __attribute__((__unused__)) # endif #endif diff --git a/source/blender/blenlib/CMakeLists.txt b/source/blender/blenlib/CMakeLists.txt index dcf7c3b5d39..0de614a5ca7 100644 --- a/source/blender/blenlib/CMakeLists.txt +++ b/source/blender/blenlib/CMakeLists.txt @@ -88,6 +88,7 @@ set(SRC intern/math_statistics.c intern/math_vector.c intern/math_vector_inline.c + intern/memory_utils.c intern/noise.c intern/path_util.c intern/polyfill2d.c @@ -169,6 +170,7 @@ set(SRC BLI_math_statistics.h BLI_math_vector.h BLI_memarena.h + BLI_memory_utils.h BLI_mempool.h BLI_noise.h BLI_path_util.h diff --git a/source/blender/blenlib/intern/BLI_filelist.c b/source/blender/blenlib/intern/BLI_filelist.c index 62690ff4f3c..527d9934797 100644 --- a/source/blender/blenlib/intern/BLI_filelist.c +++ b/source/blender/blenlib/intern/BLI_filelist.c @@ -333,7 +333,8 @@ void BLI_filelist_entry_datetime_to_string( const struct stat *st, const int64_t ts, const bool compact, char r_time[FILELIST_DIRENTRY_TIME_LEN], char r_date[FILELIST_DIRENTRY_DATE_LEN]) { - const struct tm *tm = localtime(st ? &st->st_mtime : &ts); + time_t ts_mtime = ts; + const struct tm *tm = localtime(st ? &st->st_mtime : &ts_mtime); const time_t zero = 0; /* Prevent impossible dates in windows. */ diff --git a/source/blender/blenlib/intern/BLI_ghash.c b/source/blender/blenlib/intern/BLI_ghash.c index 91ac0ce1c43..7e6dabdffef 100644 --- a/source/blender/blenlib/intern/BLI_ghash.c +++ b/source/blender/blenlib/intern/BLI_ghash.c @@ -653,7 +653,7 @@ GHash *BLI_ghash_copy(GHash *gh, GHashKeyCopyFP keycopyfp, GHashValCopyFP valcop } /** - * Reverve given ammount of entries (resize \a gh accordingly if needed). + * Reserve given amount of entries (resize \a gh accordingly if needed). */ void BLI_ghash_reserve(GHash *gh, const unsigned int nentries_reserve) { diff --git a/source/blender/blenlib/intern/array_utils.c b/source/blender/blenlib/intern/array_utils.c index 65c653c9b4f..cef912e42a3 100644 --- a/source/blender/blenlib/intern/array_utils.c +++ b/source/blender/blenlib/intern/array_utils.c @@ -90,7 +90,7 @@ void _bli_array_wrap(void *arr_v, unsigned int arr_len, size_t arr_stride, int d /** *In-place array permute. - * (re-arrange elemrnts based on an array of indices). + * (re-arrange elements based on an array of indices). * * Access via #BLI_array_wrap */ diff --git a/source/blender/blenlib/intern/buffer.c b/source/blender/blenlib/intern/buffer.c index 9e96205a5e8..24b2228c884 100644 --- a/source/blender/blenlib/intern/buffer.c +++ b/source/blender/blenlib/intern/buffer.c @@ -20,30 +20,55 @@ /** \file blender/blenlib/intern/buffer.c * \ingroup bli + * + * Primitive generic buffer library. + * + * - Automatically grow as needed. + * (currently never shrinks). + * - Can be passed between functions. + * - Supports using stack memory by default, + * falling back to heap as needed. + * + * Usage examples: + * \code{.c} + * BLI_buffer_declare_static(int, my_int_array, BLI_BUFFER_NOP, 32); + * + * BLI_buffer_append(my_int_array, int, 42); + * assert(my_int_array.count == 1); + * assert(BLI_buffer_at(my_int_array, int, 0) == 42); + * + * BLI_buffer_free(&my_int_array); + * \endcode + * + * \note this more or less fills same purpose as #BLI_array, + * but supports resizing the array outside of the function + * it was declared in. */ +#include <string.h> + #include "MEM_guardedalloc.h" #include "BLI_buffer.h" #include "BLI_utildefines.h" -#include <string.h> +#include "BLI_strict_flags.h" -static void *buffer_alloc(BLI_Buffer *buffer, int len) +static void *buffer_alloc(BLI_Buffer *buffer, const size_t len) { return ((buffer->flag & BLI_BUFFER_USE_CALLOC) ? MEM_callocN : MEM_mallocN) (buffer->elem_size * len, "BLI_Buffer.data"); } -static void *buffer_realloc(BLI_Buffer *buffer, int len) +static void *buffer_realloc(BLI_Buffer *buffer, const size_t len) { return ((buffer->flag & BLI_BUFFER_USE_CALLOC) ? MEM_recallocN_id : MEM_reallocN_id) (buffer->data, buffer->elem_size * len, "BLI_Buffer.data"); } -void BLI_buffer_resize(BLI_Buffer *buffer, int new_count) +void BLI_buffer_resize(BLI_Buffer *buffer, const size_t new_count) { if (UNLIKELY(new_count > buffer->alloc_count)) { if (buffer->flag & BLI_BUFFER_USE_STATIC) { @@ -65,6 +90,47 @@ void BLI_buffer_resize(BLI_Buffer *buffer, int new_count) buffer->data = buffer_realloc(buffer, buffer->alloc_count); } } + else { + if (buffer->flag & BLI_BUFFER_USE_CALLOC) { + if (new_count > buffer->count) { + memset(POINTER_OFFSET(buffer->data, buffer->elem_size * buffer->count), 0, + buffer->elem_size * (new_count - buffer->count)); + } + } + } + + buffer->count = new_count; +} + +/** + * Similar to #BLI_buffer_resize, but use when the existing data can be: + * - Ignored (malloc'd) + * - Cleared (when BLI_BUFFER_USE_CALLOC is set) + */ +void BLI_buffer_reinit(BLI_Buffer *buffer, size_t new_count) +{ + if (UNLIKELY(new_count > buffer->alloc_count)) { + if ((buffer->flag & BLI_BUFFER_USE_STATIC) == 0) { + if (buffer->data) { + MEM_freeN(buffer->data); + } + } + + if (buffer->alloc_count && (new_count < buffer->alloc_count * 2)) { + buffer->alloc_count *= 2; + } + else { + buffer->alloc_count = new_count; + } + + buffer->data = buffer_alloc(buffer, new_count); + } + else { + if (buffer->flag & BLI_BUFFER_USE_CALLOC) { + memset(buffer->data, 0, + buffer->elem_size * new_count); + } + } buffer->count = new_count; } diff --git a/source/blender/blenlib/intern/fileops.c b/source/blender/blenlib/intern/fileops.c index bc952165b61..ef9a7c0603f 100644 --- a/source/blender/blenlib/intern/fileops.c +++ b/source/blender/blenlib/intern/fileops.c @@ -570,7 +570,7 @@ static int recursive_operation(const char *startfrom, const char *startto, char *from_path = NULL, *to_path = NULL; struct dirent **dirlist = NULL; size_t from_alloc_len = -1, to_alloc_len = -1; - int i, n, ret = 0; + int i, n = 0, ret = 0; do { /* once */ /* ensure there's no trailing slash in file path */ diff --git a/source/blender/blenlib/intern/math_color_blend_inline.c b/source/blender/blenlib/intern/math_color_blend_inline.c index 73a7259ddcd..048ab71c6dc 100644 --- a/source/blender/blenlib/intern/math_color_blend_inline.c +++ b/source/blender/blenlib/intern/math_color_blend_inline.c @@ -36,7 +36,7 @@ #ifndef __MATH_COLOR_BLEND_INLINE_C__ #define __MATH_COLOR_BLEND_INLINE_C__ -/* don't add any saturation to a completly black and white image */ +/* don't add any saturation to a completely black and white image */ #define EPS_SATURATION 0.0005f #define EPS_ALPHA 0.0005f @@ -72,7 +72,7 @@ MINLINE void blend_color_mix_byte(unsigned char dst[4], const unsigned char src1 } else { /* no op */ - copy_v4_v4_char((char *)dst, (char *)src1); + copy_v4_v4_uchar(dst, src1); } } @@ -94,7 +94,7 @@ MINLINE void blend_color_add_byte(unsigned char dst[4], const unsigned char src1 } else { /* no op */ - copy_v4_v4_char((char *)dst, (char *)src1); + copy_v4_v4_uchar(dst, src1); } } @@ -116,7 +116,7 @@ MINLINE void blend_color_sub_byte(unsigned char dst[4], const unsigned char src1 } else { /* no op */ - copy_v4_v4_char((char *)dst, (char *)src1); + copy_v4_v4_uchar(dst, src1); } } @@ -139,7 +139,7 @@ MINLINE void blend_color_mul_byte(unsigned char dst[4], const unsigned char src1 } else { /* no op */ - copy_v4_v4_char((char *)dst, (char *)src1); + copy_v4_v4_uchar(dst, src1); } } @@ -162,7 +162,7 @@ MINLINE void blend_color_lighten_byte(unsigned char dst[4], const unsigned char } else { /* no op */ - copy_v4_v4_char((char *)dst, (char *)src1); + copy_v4_v4_uchar(dst, src1); } } @@ -185,7 +185,7 @@ MINLINE void blend_color_darken_byte(unsigned char dst[4], const unsigned char s } else { /* no op */ - copy_v4_v4_char((char *)dst, (char *)src1); + copy_v4_v4_uchar(dst, src1); } } @@ -202,7 +202,7 @@ MINLINE void blend_color_erase_alpha_byte(unsigned char dst[4], const unsigned c } else { /* no op */ - copy_v4_v4_char((char *)dst, (char *)src1); + copy_v4_v4_uchar(dst, src1); } } @@ -219,7 +219,7 @@ MINLINE void blend_color_add_alpha_byte(unsigned char dst[4], const unsigned cha } else { /* no op */ - copy_v4_v4_char((char *)dst, (char *)src1); + copy_v4_v4_uchar(dst, src1); } } @@ -244,7 +244,7 @@ MINLINE void blend_color_overlay_byte(unsigned char dst[4], unsigned const char } else { /* no op */ - copy_v4_v4_char((char *)dst, (char *)src1); + copy_v4_v4_uchar(dst, src1); } } @@ -270,7 +270,7 @@ MINLINE void blend_color_hardlight_byte(unsigned char dst[4], unsigned const cha } else { /* no op */ - copy_v4_v4_char((char *)dst, (char *)src1); + copy_v4_v4_uchar(dst, src1); } } @@ -289,7 +289,7 @@ MINLINE void blend_color_burn_byte(unsigned char dst[4], unsigned const char src } else { /* no op */ - copy_v4_v4_char((char *)dst, (char *)src1); + copy_v4_v4_uchar(dst, src1); } } @@ -308,7 +308,7 @@ MINLINE void blend_color_linearburn_byte(unsigned char dst[4], unsigned const ch } else { /* no op */ - copy_v4_v4_char((char *)dst, (char *)src1); + copy_v4_v4_uchar(dst, src1); } } @@ -327,7 +327,7 @@ MINLINE void blend_color_dodge_byte(unsigned char dst[4], unsigned const char sr } else { /* no op */ - copy_v4_v4_char((char *)dst, (char *)src1); + copy_v4_v4_uchar(dst, src1); } } @@ -345,7 +345,7 @@ MINLINE void blend_color_screen_byte(unsigned char dst[4], unsigned const char s } else { /* no op */ - copy_v4_v4_char((char *)dst, (char *)src1); + copy_v4_v4_uchar(dst, src1); } } @@ -371,7 +371,7 @@ MINLINE void blend_color_softlight_byte(unsigned char dst[4], unsigned const cha } else { /* no op */ - copy_v4_v4_char((char *)dst, (char *)src1); + copy_v4_v4_uchar(dst, src1); } } @@ -397,7 +397,7 @@ MINLINE void blend_color_pinlight_byte(unsigned char dst[4], unsigned const char } else { /* no op */ - copy_v4_v4_char((char *)dst, (char *)src1); + copy_v4_v4_uchar(dst, src1); } } @@ -423,7 +423,7 @@ MINLINE void blend_color_linearlight_byte(unsigned char dst[4], unsigned const c } else { /* no op */ - copy_v4_v4_char((char *)dst, (char *)src1); + copy_v4_v4_uchar(dst, src1); } } @@ -455,7 +455,7 @@ MINLINE void blend_color_vividlight_byte(unsigned char dst[4], unsigned const ch } else { /* no op */ - copy_v4_v4_char((char *)dst, (char *)src1); + copy_v4_v4_uchar(dst, src1); } } @@ -475,7 +475,7 @@ MINLINE void blend_color_difference_byte(unsigned char dst[4], unsigned const ch } else { /* no op */ - copy_v4_v4_char((char *)dst, (char *)src1); + copy_v4_v4_uchar(dst, src1); } } @@ -494,7 +494,7 @@ MINLINE void blend_color_exclusion_byte(unsigned char dst[4], unsigned const cha } else { /* no op */ - copy_v4_v4_char((char *)dst, (char *)src1); + copy_v4_v4_uchar(dst, src1); } } @@ -521,7 +521,7 @@ MINLINE void blend_color_color_byte(unsigned char dst[4], unsigned const char sr } else { /* no op */ - copy_v4_v4_char((char *)dst, (char *)src1); + copy_v4_v4_uchar(dst, src1); } } @@ -547,7 +547,7 @@ MINLINE void blend_color_hue_byte(unsigned char dst[4], unsigned const char src1 } else { /* no op */ - copy_v4_v4_char((char *)dst, (char *)src1); + copy_v4_v4_uchar(dst, src1); } } @@ -575,7 +575,7 @@ MINLINE void blend_color_saturation_byte(unsigned char dst[4], unsigned const ch } else { /* no op */ - copy_v4_v4_char((char *)dst, (char *)src1); + copy_v4_v4_uchar(dst, src1); } } @@ -601,7 +601,7 @@ MINLINE void blend_color_luminosity_byte(unsigned char dst[4], unsigned const ch } else { /* no op */ - copy_v4_v4_char((char *)dst, (char *)src1); + copy_v4_v4_uchar(dst, src1); } } @@ -621,7 +621,7 @@ MINLINE void blend_color_interpolate_byte(unsigned char dst[4], const unsigned c dst[3] = (unsigned char)divide_round_i(tmp, 255); } else { - copy_v4_v4_char((char *)dst, (char *)src1); + copy_v4_v4_uchar(dst, src1); } } diff --git a/source/blender/blenlib/intern/math_geom.c b/source/blender/blenlib/intern/math_geom.c index 379c8524601..e5fb5533728 100644 --- a/source/blender/blenlib/intern/math_geom.c +++ b/source/blender/blenlib/intern/math_geom.c @@ -380,6 +380,27 @@ void closest_to_plane_v3(float r_close[3], const float plane[4], const float pt[ madd_v3_v3v3fl(r_close, pt, plane, -side / len_sq); } +void closest_to_plane_normalized_v3(float r_close[3], const float plane[4], const float pt[3]) +{ + const float side = plane_point_side_v3(plane, pt); + BLI_ASSERT_UNIT_V3(plane); + madd_v3_v3v3fl(r_close, pt, plane, -side); +} + +void closest_to_plane3_v3(float r_close[3], const float plane[3], const float pt[3]) +{ + const float len_sq = len_squared_v3(plane); + const float side = dot_v3v3(plane, pt); + madd_v3_v3v3fl(r_close, pt, plane, -side / len_sq); +} + +void closest_to_plane3_normalized_v3(float r_close[3], const float plane[3], const float pt[3]) +{ + const float side = dot_v3v3(plane, pt); + BLI_ASSERT_UNIT_V3(plane); + madd_v3_v3v3fl(r_close, pt, plane, -side); +} + float dist_signed_squared_to_plane_v3(const float pt[3], const float plane[4]) { const float len_sq = len_squared_v3(plane); @@ -476,7 +497,7 @@ float dist_to_line_v3(const float p[3], const float l1[3], const float l2[3]) * \note the distance from \a v1 & \a v3 to \a v2 doesnt matter * (it just defines the planes). * - * \return the lowest squared distance to eithe of the planes. + * \return the lowest squared distance to either of the planes. * where ``(return < 0.0)`` is outside. * * <pre> @@ -1235,38 +1256,27 @@ bool isect_ray_tri_v3( /** * if clip is nonzero, will only return true if lambda is >= 0.0 * (i.e. intersection point is along positive d) + * + * \note #line_plane_factor_v3() shares logic. */ bool isect_ray_plane_v3( const float p1[3], const float d[3], - const float v0[3], const float v1[3], const float v2[3], + const float plane[4], float *r_lambda, const bool clip) { - const float epsilon = 0.00000001f; - float p[3], s[3], e1[3], e2[3], q[3]; - float a, f; - /* float u, v; */ /*UNUSED*/ - - sub_v3_v3v3(e1, v1, v0); - sub_v3_v3v3(e2, v2, v0); - - cross_v3_v3v3(p, d, e2); - a = dot_v3v3(e1, p); - /* note: these values were 0.000001 in 2.4x but for projection snapping on - * a human head (1BU == 1m), subsurf level 2, this gave many errors - campbell */ - if ((a > -epsilon) && (a < epsilon)) return false; - f = 1.0f / a; - - sub_v3_v3v3(s, p1, v0); - - /* u = f * dot_v3v3(s, p); */ /*UNUSED*/ - - cross_v3_v3v3(q, s, e1); - - /* v = f * dot_v3v3(d, q); */ /*UNUSED*/ - - *r_lambda = f * dot_v3v3(e2, q); - if (clip && (*r_lambda < 0.0f)) return false; + float h[3], plane_co[3]; + float dot; + dot = dot_v3v3(plane, d); + if (dot == 0.0f) { + return false; + } + mul_v3_v3fl(plane_co, plane, (-plane[3] / len_squared_v3(plane))); + sub_v3_v3v3(h, p1, plane_co); + *r_lambda = -dot_v3v3(plane, h) / dot; + if (clip && (*r_lambda < 0.0f)) { + return false; + } return true; } @@ -1535,28 +1545,90 @@ bool isect_line_plane_v3(float out[3], } /** + * Intersect three planes, return the point where all 3 meet. + * See Graphics Gems 1 pg 305 + * + * \param plane_a, plane_b, plane_c: Planes. + * \param r_isect_co: The resulting intersection point. + */ +bool isect_plane_plane_plane_v3( + const float plane_a[4], const float plane_b[4], const float plane_c[4], + float r_isect_co[3]) +{ + float det; + + det = determinant_m3(UNPACK3(plane_a), UNPACK3(plane_b), UNPACK3(plane_c)); + + if (det != 0.0f) { + float tmp[3]; + + /* (plane_b.xyz.cross(plane_c.xyz) * -plane_a[3] + + * plane_c.xyz.cross(plane_a.xyz) * -plane_b[3] + + * plane_a.xyz.cross(plane_b.xyz) * -plane_c[3]) / det; */ + + cross_v3_v3v3(tmp, plane_c, plane_b); + mul_v3_v3fl(r_isect_co, tmp, plane_a[3]); + + cross_v3_v3v3(tmp, plane_a, plane_c); + madd_v3_v3fl(r_isect_co, tmp, plane_b[3]); + + cross_v3_v3v3(tmp, plane_b, plane_a); + madd_v3_v3fl(r_isect_co, tmp, plane_c[3]); + + mul_v3_fl(r_isect_co, 1.0f / det); + + return true; + } + else { + return false; + } +} + +/** * Intersect two planes, return a point on the intersection and a vector * that runs on the direction of the intersection. - * Return error code is the same as 'isect_line_line_v3'. * - * \param r_isect_co The resulting intersection point. - * \param r_isect_no The resulting vector of the intersection. - * \param plane_a_co The point on the first plane. - * \param plane_a_no The normal of the first plane. - * \param plane_b_co The point on the second plane. - * \param plane_b_no The normal of the second plane. * - * \note return normal isn't unit length + * \note this is a slightly reduced version of #isect_plane_plane_plane_v3 + * + * \param plane_a, plane_b: Planes. + * \param r_isect_co: The resulting intersection point. + * \param r_isect_no: The resulting vector of the intersection. + * + * \note \a r_isect_no isn't unit length. */ -bool isect_plane_plane_v3(float r_isect_co[3], float r_isect_no[3], - const float plane_a_co[3], const float plane_a_no[3], - const float plane_b_co[3], const float plane_b_no[3]) +bool isect_plane_plane_v3( + const float plane_a[4], const float plane_b[4], + float r_isect_co[3], float r_isect_no[3]) { - float plane_a_co_other[3]; - cross_v3_v3v3(r_isect_no, plane_a_no, plane_b_no); /* direction is simply the cross product */ - cross_v3_v3v3(plane_a_co_other, plane_a_no, r_isect_no); - add_v3_v3(plane_a_co_other, plane_a_co); - return isect_line_plane_v3(r_isect_co, plane_a_co, plane_a_co_other, plane_b_co, plane_b_no); + float det, plane_c[3]; + + /* direction is simply the cross product */ + cross_v3_v3v3(plane_c, plane_a, plane_b); + + /* in this case we don't need to use 'determinant_m3' */ + det = len_squared_v3(plane_c); + + if (det != 0.0f) { + float tmp[3]; + + /* (plane_b.xyz.cross(plane_c.xyz) * -plane_a[3] + + * plane_c.xyz.cross(plane_a.xyz) * -plane_b[3]) / det; */ + cross_v3_v3v3(tmp, plane_c, plane_b); + mul_v3_v3fl(r_isect_co, tmp, plane_a[3]); + + cross_v3_v3v3(tmp, plane_a, plane_c); + madd_v3_v3fl(r_isect_co, tmp, plane_b[3]); + + mul_v3_fl(r_isect_co, 1.0f / det); + + copy_v3_v3(r_isect_no, plane_c); + + return true; + } + else { + return false; + } } /** @@ -1574,46 +1646,67 @@ bool isect_tri_tri_epsilon_v3( const float epsilon) { const float *tri_pair[2][3] = {{t_a0, t_a1, t_a2}, {t_b0, t_b1, t_b2}}; - float no_a[3], no_b[3]; - float isect_co[3], isect_no[3]; + float plane_a[4], plane_b[4]; + float plane_co[3], plane_no[3]; BLI_assert((r_i1 != NULL) == (r_i2 != NULL)); - normal_tri_v3(no_a, UNPACK3(tri_pair[0])); - normal_tri_v3(no_b, UNPACK3(tri_pair[1])); + /* normalizing is needed for small triangles T46007 */ + normal_tri_v3(plane_a, UNPACK3(tri_pair[0])); + normal_tri_v3(plane_b, UNPACK3(tri_pair[1])); + + plane_a[3] = -dot_v3v3(plane_a, t_a0); + plane_b[3] = -dot_v3v3(plane_b, t_b0); - if (isect_plane_plane_v3(isect_co, isect_no, t_a0, no_a, t_b0, no_b)) { - float isect_co_other[3]; + if (isect_plane_plane_v3(plane_a, plane_b, plane_co, plane_no) && + (normalize_v3(plane_no) > epsilon)) + { + /** + * Implementation note: its simpler to project the triangles onto the intersection plane + * before intersecting their edges with the ray, defined by 'isect_plane_plane_v3'. + * This way we can use 'line_point_factor_v3_ex' to see if an edge crosses 'co_proj', + * then use the factor to calculate the world-space point. + */ struct { float min, max; } range[2] = {{FLT_MAX, -FLT_MAX}, {FLT_MAX, -FLT_MAX}}; int t; + float co_proj[3]; - add_v3_v3v3(isect_co_other, isect_co, isect_no); + closest_to_plane3_normalized_v3(co_proj, plane_no, plane_co); - /* For both triangles, find the overlap with the line defined by (isect_co, isect_co_other). + /* For both triangles, find the overlap with the line defined by the ray [co_proj, plane_no]. * When the ranges overlap we know the triangles do too. */ for (t = 0; t < 2; t++) { int j, j_prev; + float tri_proj[3][3]; + + closest_to_plane3_normalized_v3(tri_proj[0], plane_no, tri_pair[t][0]); + closest_to_plane3_normalized_v3(tri_proj[1], plane_no, tri_pair[t][1]); + closest_to_plane3_normalized_v3(tri_proj[2], plane_no, tri_pair[t][2]); for (j = 0, j_prev = 2; j < 3; j_prev = j++) { - /* intersection point on the line intersecting both planes */ - float ix_span[3]; - /* intersection point on the triangles edge */ - float ix_tri[3]; - - if (isect_line_line_epsilon_v3( - isect_co, isect_co_other, - tri_pair[t][j], tri_pair[t][j_prev], - ix_span, ix_tri, - epsilon) != 0) - { - const float edge_fac = line_point_factor_v3(ix_tri, tri_pair[t][j], tri_pair[t][j_prev]); - if (edge_fac >= -epsilon && edge_fac <= 1.0f + epsilon) { - const float span_fac = dist_signed_squared_to_plane3_v3(ix_tri, isect_no); - range[t].min = min_ff(range[t].min, span_fac); - range[t].max = max_ff(range[t].max, span_fac); - } + /* note that its important to have a very small nonzero epsilon here + * otherwise this fails for very small faces. + * However if its too small, large adjacent faces will count as intersecting */ + const float edge_fac = line_point_factor_v3_ex(co_proj, tri_proj[j_prev], tri_proj[j], 1e-10f, -1.0f); + /* ignore collinear lines, they are either an edge shared between 2 tri's + * (which runs along [co_proj, plane_no], but can be safely ignored). + * + * or a collinear edge placed away from the ray - which we don't intersect with & can ignore. */ + if (UNLIKELY(edge_fac == -1.0f)) { + /* pass */ + } + else if (edge_fac > 0.0f && edge_fac < 1.0f) { + float ix_tri[3]; + float span_fac; + + interp_v3_v3v3(ix_tri, tri_pair[t][j_prev], tri_pair[t][j], edge_fac); + /* the actual distance, since 'plane_no' is normalized */ + span_fac = dot_v3v3(plane_no, ix_tri); + + range[t].min = min_ff(range[t].min, span_fac); + range[t].max = max_ff(range[t].max, span_fac); } } @@ -1626,9 +1719,9 @@ bool isect_tri_tri_epsilon_v3( (range[0].max < range[1].min)) == 0) { if (r_i1 && r_i2) { - project_plane_v3_v3v3(isect_co, isect_co, isect_no); - madd_v3_v3v3fl(r_i1, isect_co, isect_no, sqrtf_signed(max_ff(range[0].min, range[1].min))); - madd_v3_v3v3fl(r_i2, isect_co, isect_no, sqrtf_signed(min_ff(range[0].max, range[1].max))); + project_plane_v3_v3v3(plane_co, plane_co, plane_no); + madd_v3_v3v3fl(r_i1, plane_co, plane_no, max_ff(range[0].min, range[1].min)); + madd_v3_v3v3fl(r_i2, plane_co, plane_no, min_ff(range[0].max, range[1].max)); } return true; @@ -1933,8 +2026,9 @@ int isect_line_line_epsilon_v3( d = dot_v3v3(c, ab); div = dot_v3v3(ab, ab); + /* important not to use an epsilon here, see: T45919 */ /* test zero length line */ - if (UNLIKELY(div <= epsilon)) { + if (UNLIKELY(div == 0.0f)) { return 0; } /* test if the two lines are coplanar */ @@ -2005,8 +2099,9 @@ bool isect_line_line_strict_v3(const float v1[3], const float v2[3], d = dot_v3v3(c, ab); div = dot_v3v3(ab, ab); + /* important not to use an epsilon here, see: T45919 */ /* test zero length line */ - if (UNLIKELY(div <= epsilon)) { + if (UNLIKELY(div == 0.0f)) { return false; } /* test if the two lines are coplanar */ @@ -2129,8 +2224,13 @@ float closest_to_line_v2(float cp[2], const float p[2], const float l1[2], const /** * A simplified version of #closest_to_line_v3 * we only need to return the ``lambda`` + * + * \param epsilon: avoid approaching divide-by-zero. + * Passing a zero will just check for nonzero division. */ -float line_point_factor_v3(const float p[3], const float l1[3], const float l2[3]) +float line_point_factor_v3_ex( + const float p[3], const float l1[3], const float l2[3], + const float epsilon, const float fallback) { float h[3], u[3]; float dot; @@ -2141,11 +2241,18 @@ float line_point_factor_v3(const float p[3], const float l1[3], const float l2[3 #else /* better check for zero */ dot = dot_v3v3(u, u); - return (dot != 0.0f) ? (dot_v3v3(u, h) / dot) : 0.0f; + return (fabsf(dot) > epsilon) ? (dot_v3v3(u, h) / dot) : fallback; #endif } +float line_point_factor_v3( + const float p[3], const float l1[3], const float l2[3]) +{ + return line_point_factor_v3_ex(p, l1, l2, 0.0f, 0.0f); +} -float line_point_factor_v2(const float p[2], const float l1[2], const float l2[2]) +float line_point_factor_v2_ex( + const float p[2], const float l1[2], const float l2[2], + const float epsilon, const float fallback) { float h[2], u[2]; float dot; @@ -2156,10 +2263,15 @@ float line_point_factor_v2(const float p[2], const float l1[2], const float l2[2 #else /* better check for zero */ dot = dot_v2v2(u, u); - return (dot != 0.0f) ? (dot_v2v2(u, h) / dot) : 0.0f; + return (fabsf(dot) > epsilon) ? (dot_v2v2(u, h) / dot) : fallback; #endif } +float line_point_factor_v2(const float p[2], const float l1[2], const float l2[2]) +{ + return line_point_factor_v2_ex(p, l1, l2, 0.0f, 0.0f); +} + /** * \note #isect_line_plane_v3() shares logic */ @@ -3447,8 +3559,8 @@ void perspective_m4(float mat[4][4], const float left, const float right, const mat[2][3] = -1.0f; mat[3][2] = (-2.0f * nearClip * farClip) / Zdelta; mat[0][1] = mat[0][2] = mat[0][3] = - mat[1][0] = mat[1][2] = mat[1][3] = - mat[3][0] = mat[3][1] = mat[3][3] = 0.0f; + mat[1][0] = mat[1][2] = mat[1][3] = + mat[3][0] = mat[3][1] = mat[3][3] = 0.0f; } diff --git a/source/blender/blenlib/intern/math_matrix.c b/source/blender/blenlib/intern/math_matrix.c index 33d0fb87aca..4bf6d162970 100644 --- a/source/blender/blenlib/intern/math_matrix.c +++ b/source/blender/blenlib/intern/math_matrix.c @@ -516,7 +516,8 @@ void mul_v3_mat3_m4v3(float r[3], float mat[4][4], const float vec[3]) void mul_project_m4_v3(float mat[4][4], float vec[3]) { - const float w = mul_project_m4_v3_zfac(mat, vec); + /* absolute value to not flip the frustum upside down behind the camera */ + const float w = fabsf(mul_project_m4_v3_zfac(mat, vec)); mul_m4_v3(mat, vec); vec[0] /= w; @@ -526,7 +527,7 @@ void mul_project_m4_v3(float mat[4][4], float vec[3]) void mul_v3_project_m4_v3(float r[3], float mat[4][4], const float vec[3]) { - const float w = mul_project_m4_v3_zfac(mat, vec); + const float w = fabsf(mul_project_m4_v3_zfac(mat, vec)); mul_v3_m4v3(r, mat, vec); r[0] /= w; @@ -536,7 +537,7 @@ 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 mat[4][4], const float vec[3]) { - const float w = mul_project_m4_v3_zfac(mat, vec); + const float w = fabsf(mul_project_m4_v3_zfac(mat, vec)); mul_v2_m4v3(r, mat, vec); r[0] /= w; @@ -1247,36 +1248,74 @@ bool is_uniform_scaled_m4(float m[4][4]) return is_uniform_scaled_m3(t); } +void normalize_m3_ex(float mat[3][3], float r_scale[3]) +{ + int i; + for (i = 0; i < 3; i++) { + r_scale[i] = normalize_v3(mat[i]); + } +} void normalize_m3(float mat[3][3]) { - normalize_v3(mat[0]); - normalize_v3(mat[1]); - normalize_v3(mat[2]); + int i; + for (i = 0; i < 3; i++) { + normalize_v3(mat[i]); + } } +void normalize_m3_m3_ex(float rmat[3][3], 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]) { - normalize_v3_v3(rmat[0], mat[0]); - normalize_v3_v3(rmat[1], mat[1]); - normalize_v3_v3(rmat[2], mat[2]); + int i; + for (i = 0; i < 3; i++) { + normalize_v3_v3(rmat[i], mat[i]); + } } +void normalize_m4_ex(float mat[4][4], float r_scale[3]) +{ + int i; + for (i = 0; i < 3; i++) { + r_scale[i] = normalize_v3(mat[i]); + if (r_scale[i] != 0.0f) { + mat[i][3] /= r_scale[i]; + } + } +} void normalize_m4(float mat[4][4]) { - float len; - - len = normalize_v3(mat[0]); - if (len != 0.0f) mat[0][3] /= len; - len = normalize_v3(mat[1]); - if (len != 0.0f) mat[1][3] /= len; - len = normalize_v3(mat[2]); - if (len != 0.0f) mat[2][3] /= len; + int i; + for (i = 0; i < 3; i++) { + float len = normalize_v3(mat[i]); + if (len != 0.0f) { + mat[i][3] /= len; + } + } } +void normalize_m4_m4_ex(float rmat[4][4], float mat[4][4], float r_scale[3]) +{ + int i; + for (i = 0; i < 3; i++) { + r_scale[i] = normalize_v3_v3(rmat[i], mat[i]); + rmat[i][3] = (r_scale[i] != 0.0f) ? (mat[i][3] / r_scale[i]) : mat[i][3]; + } + copy_v4_v4(rmat[3], mat[3]); +} void normalize_m4_m4(float rmat[4][4], float mat[4][4]) { - copy_m4_m4(rmat, mat); - normalize_m4(rmat); + int i; + for (i = 0; i < 3; i++) { + float len = normalize_v3_v3(rmat[i], mat[i]); + rmat[i][3] = (len != 0.0f) ? (mat[i][3] / len) : mat[i][3]; + } + copy_v4_v4(rmat[3], mat[3]); } void adjoint_m2_m2(float m1[2][2], float m[2][2]) @@ -1521,6 +1560,34 @@ void mat4_decompose(float loc[3], float quat[4], float size[3], float wmat[4][4] mat3_to_quat(quat, rot); } +/** + * Right polar decomposition: + * M = UP + * + * U is the 'rotation'-like component, the closest orthogonal matrix to M. + * P is the 'scaling'-like component, defined in U space. + * + * See https://en.wikipedia.org/wiki/Polar_decomposition for more. + */ +void mat3_polar_decompose(float mat3[3][3], float r_U[3][3], float r_P[3][3]) +{ + /* From svd decomposition (M = WSV*), we have: + * U = WV* + * P = VSV* + */ + float W[3][3], S[3][3], V[3][3], Vt[3][3]; + float sval[3]; + + BLI_svd_m3(mat3, W, sval, V); + + size_to_mat3(S, sval); + + transpose_m3_m3(Vt, V); + mul_m3_m3m3(r_U, W, Vt); + mul_m3_series(r_P, V, S, Vt); +} + + void scale_m3_fl(float m[3][3], float scale) { m[0][0] = m[1][1] = m[2][2] = scale; @@ -1660,6 +1727,75 @@ void blend_m4_m4m4(float out[4][4], float dst[4][4], float src[4][4], const floa loc_quat_size_to_mat4(out, floc, fquat, fsize); } +/** + * A polar-decomposition-based interpolation between matrix A and matrix B. + * + * \note This code is about five times slower as the 'naive' interpolation done by \a blend_m3_m3m3 + * (it typically remains below 2 usec on an average i74700, while \a blend_m3_m3m3 remains below 0.4 usec). + * However, it gives expected results even with non-uniformaly scaled matrices, see T46418 for an example. + * + * Based on "Matrix Animation and Polar Decomposition", by Ken Shoemake & Tom Duff + * + * @return R the interpolated matrix. + * @param A the intput matrix which is totally effective with \a t = 0.0. + * @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) +{ + /* 'Rotation' component ('U' part of polar decomposition, the closest orthogonal matrix to M3 rot/scale + * transformation matrix), spherically interpolated. */ + float U_A[3][3], U_B[3][3], U[3][3]; + float quat_A[4], quat_B[4], quat[4]; + /* 'Scaling' component ('P' part of polar decomposition, i.e. scaling in U-defined space), linearly interpolated. */ + float P_A[3][3], P_B[3][3], P[3][3]; + + int i; + + mat3_polar_decompose(A, U_A, P_A); + mat3_polar_decompose(B, U_B, P_B); + + mat3_to_quat(quat_A, U_A); + mat3_to_quat(quat_B, U_B); + interp_qt_qtqt(quat, quat_A, quat_B, t); + quat_to_mat3(U, quat); + + for (i = 0; i < 3; i++) { + interp_v3_v3v3(P[i], P_A[i], P_B[i], t); + } + + /* And we reconstruct rot/scale matrix from interpolated polar components */ + mul_m3_m3m3(R, U, P); +} + +/** + * Complete transform matrix interpolation, based on polar-decomposition-based interpolation from interp_m3_m3m3. + * + * @return R the interpolated matrix. + * @param A the intput matrix which is totally effective with \a t = 0.0. + * @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) +{ + float A3[3][3], B3[3][3], R3[3][3]; + + /* Location component, linearly interpolated. */ + float loc_A[3], loc_B[3], loc[3]; + + copy_v3_v3(loc_A, A[3]); + copy_v3_v3(loc_B, B[3]); + interp_v3_v3v3(loc, loc_A, loc_B, t); + + copy_m3_m4(A3, A); + copy_m3_m4(B3, B); + + interp_m3_m3m3(R3, A3, B3, t); + + copy_m4_m3(R, R3); + copy_v3_v3(R[3], loc); +} + bool is_negative_m3(float mat[3][3]) { float vec[3]; diff --git a/source/blender/blenlib/intern/math_rotation.c b/source/blender/blenlib/intern/math_rotation.c index 5f039e89e89..575710e8d75 100644 --- a/source/blender/blenlib/intern/math_rotation.c +++ b/source/blender/blenlib/intern/math_rotation.c @@ -1631,7 +1631,7 @@ void mat4_to_dquat(DualQuat *dq, float basemat[4][4], float mat[4][4]) copy_m3_m4(mat3, mat); - if (!is_orthonormal_m3(mat3) || (determinant_m4(mat) < 0.0f) || len_v3(dscale) > 1e-4f) { + if (!is_orthonormal_m3(mat3) || (determinant_m4(mat) < 0.0f) || len_squared_v3(dscale) > SQUARE(1e-4f)) { /* extract R and S */ float tmp[4][4]; diff --git a/source/blender/blenlib/intern/math_solvers.c b/source/blender/blenlib/intern/math_solvers.c index 2f962714c8c..d1dad9a6269 100644 --- a/source/blender/blenlib/intern/math_solvers.c +++ b/source/blender/blenlib/intern/math_solvers.c @@ -59,3 +59,16 @@ bool BLI_eigen_solve_selfadjoint_m3(const float m3[3][3], float r_eigen_values[3 return EG3_self_adjoint_eigen_solve(3, (const float *)m3, r_eigen_values, (float *)r_eigen_vectors); } + +/** + * \brief Compute the SVD (Singular Values Decomposition) of given 3D matrix (m3 = USV*). + * + * \param m3 the matrix to decompose. + * \return r_U the computed left singular vector of \a m3 (NULL if not needed). + * \return r_S the computed singular values of \a m3 (NULL if not needed). + * \return r_V the computed right singular vector of \a m3 (NULL if not needed). + */ +void BLI_svd_m3(const float m3[3][3], float r_U[3][3], float r_S[3], float r_V[3][3]) +{ + EG3_svd_square_matrix(3, (const float *)m3, (float *)r_U, (float *)r_S, (float *)r_V); +} diff --git a/source/blender/blenlib/intern/math_statistics.c b/source/blender/blenlib/intern/math_statistics.c index 3f1bae5f58c..a8cb8e2c40d 100644 --- a/source/blender/blenlib/intern/math_statistics.c +++ b/source/blender/blenlib/intern/math_statistics.c @@ -39,7 +39,7 @@ /** * \brief Compute the covariance matrix of given set of nD coordinates. * - * \param n the dimension of the vectors (and hence, of the covairance matrix to compute). + * \param n the dimension of the vectors (and hence, of the covariance matrix to compute). * \param cos_vn the nD points to compute covariance from. * \param nbr_cos_vn the number of nD coordinates in cos_vn. * \param center the center (or mean point) of cos_vn. If NULL, it is assumed cos_vn is already centered. diff --git a/source/blender/blenlib/intern/math_vector.c b/source/blender/blenlib/intern/math_vector.c index 6da0e87355d..8d33e04241a 100644 --- a/source/blender/blenlib/intern/math_vector.c +++ b/source/blender/blenlib/intern/math_vector.c @@ -785,7 +785,7 @@ void minmax_v2v2_v2(float min[2], float max[2], const float vec[2]) if (max[1] < vec[1]) max[1] = vec[1]; } -void minmax_v3v3_v3_array(float r_min[3], float r_max[3], float (*vec_arr)[3], int nbr) +void minmax_v3v3_v3_array(float r_min[3], float r_max[3], const float (*vec_arr)[3], int nbr) { while (nbr--) { minmax_v3v3_v3(r_min, r_max, *vec_arr++); diff --git a/source/blender/blenlib/intern/math_vector_inline.c b/source/blender/blenlib/intern/math_vector_inline.c index c21b09748c9..e625ac18685 100644 --- a/source/blender/blenlib/intern/math_vector_inline.c +++ b/source/blender/blenlib/intern/math_vector_inline.c @@ -97,7 +97,29 @@ MINLINE void copy_v4_fl(float r[4], float f) r[3] = f; } -/* short */ +/* unsigned char */ +MINLINE void copy_v2_v2_uchar(unsigned char r[2], const unsigned char a[2]) +{ + r[0] = a[0]; + r[1] = a[1]; +} + +MINLINE void copy_v3_v3_uchar(unsigned char r[3], const unsigned char a[3]) +{ + r[0] = a[0]; + r[1] = a[1]; + r[2] = a[2]; +} + +MINLINE void copy_v4_v4_uchar(unsigned char r[4], const unsigned char a[4]) +{ + r[0] = a[0]; + r[1] = a[1]; + r[2] = a[2]; + r[3] = a[3]; +} + +/* char */ MINLINE void copy_v2_v2_char(char r[2], const char a[2]) { r[0] = a[0]; diff --git a/source/blender/blenlib/intern/memory_utils.c b/source/blender/blenlib/intern/memory_utils.c new file mode 100644 index 00000000000..2ebb8be5bb4 --- /dev/null +++ b/source/blender/blenlib/intern/memory_utils.c @@ -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. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/blenlib/intern/memory_utils.c + * \ingroup bli + * \brief Generic memory manipulation API. + * + * This is to extend on existing functions + * such as ``memcpy`` & ``memcmp``. + */ +#include <string.h> + +#include "BLI_sys_types.h" +#include "BLI_utildefines.h" + +#include "BLI_memory_utils.h" + +#include "BLI_strict_flags.h" + +/** + * Check if memory is zero'd, as with memset(s, 0, nbytes) + */ +bool BLI_memory_is_zero(const void *s, const size_t nbytes) +{ + const char *s_byte = s; + const char *s_end = (const char *)s + nbytes; + + while ((s_byte != s_end) && (*s_byte == 0)) { + s_byte++; + } + + return (s_byte == s_end); +} diff --git a/source/blender/blenlib/intern/noise.c b/source/blender/blenlib/intern/noise.c index 5febf720b30..4b2ad834d75 100644 --- a/source/blender/blenlib/intern/noise.c +++ b/source/blender/blenlib/intern/noise.c @@ -1546,7 +1546,7 @@ float BLI_gTurbulence(float noisesize, float x, float y, float z, int oct, int h /* * The following code is based on Ken Musgrave's explanations and sample - * source code in the book "Texturing and Modelling: A procedural approach" + * source code in the book "Texturing and Modeling: A procedural approach" */ /* diff --git a/source/blender/blenlib/intern/path_util.c b/source/blender/blenlib/intern/path_util.c index 3a73d4cc0c7..99e512475bb 100644 --- a/source/blender/blenlib/intern/path_util.c +++ b/source/blender/blenlib/intern/path_util.c @@ -191,31 +191,6 @@ int BLI_split_name_num(char *left, int *nr, const char *name, const char delim) } /** - * Looks for a string of digits within name (using BLI_stringdec) and adjusts it by add. - */ -void BLI_newname(char *name, int add) -{ - char head[UNIQUE_NAME_MAX], tail[UNIQUE_NAME_MAX]; - int pic; - unsigned short digits; - - pic = BLI_stringdec(name, head, tail, &digits); - - /* are we going from 100 -> 99 or from 10 -> 9 */ - if (add < 0 && digits < 4 && digits > 0) { - int i, exp; - exp = 1; - for (i = digits; i > 1; i--) exp *= 10; - if (pic >= exp && (pic + add) < exp) digits--; - } - - pic += add; - - if (digits == 4 && pic < 0) pic = 0; - BLI_stringenc(name, head, tail, digits, pic); -} - -/** * Ensures name is unique (according to criteria specified by caller in unique_check callback), * incrementing its numeric suffix as necessary. Returns true if name had to be adjusted. * @@ -332,14 +307,15 @@ static int BLI_path_unc_prefix_len(const char *path); /* defined below in same f /* ******************** string encoding ***************** */ -/* This is quite an ugly function... its purpose is to - * take the dir name, make it absolute, and clean it up, replacing - * excess file entry stuff (like /tmp/../tmp/../) - * note that dir isn't protected for max string names... - * - * If relbase is NULL then its ignored +/** + * Remove redundant characters from \a path and optionally make absolute. + * + * \param relbase: The path this is relative to, or ignored when NULL. + * \param path: Can be any input, and this function converts it to a regular full path. + * Also removes garbage from directory paths, like `/../` or double slashes etc. + * + * \note \a path isn't protected for max string names... */ - void BLI_cleanup_path(const char *relabase, char *path) { ptrdiff_t a; @@ -428,6 +404,9 @@ void BLI_cleanup_path(const char *relabase, char *path) #endif } +/** + * Cleanup filepath ensuring a trailing slash. + */ void BLI_cleanup_dir(const char *relabase, char *dir) { BLI_cleanup_path(relabase, dir); @@ -435,6 +414,9 @@ void BLI_cleanup_dir(const char *relabase, char *dir) } +/** + * Cleanup filepath ensuring no trailing slash. + */ void BLI_cleanup_file(const char *relabase, char *path) { BLI_cleanup_path(relabase, path); @@ -453,6 +435,8 @@ void BLI_cleanup_file(const char *relabase, char *path) * * \note Space case ' ' is a bit of an edge case here - in theory it is allowed, but again can be an issue * in some cases, so we simply replace it by an underscore too (good practice anyway). + * REMOVED based on popular demand (see T45900). + * Percent '%' char is a bit same case - not recommended to use it, but supported by all decent FS/OS around... * * \note On Windows, it also ensures there is no '.' (dot char) at the end of the file, this can lead to issues... * @@ -461,9 +445,9 @@ void BLI_cleanup_file(const char *relabase, char *path) */ bool BLI_filename_make_safe(char *fname) { - const char *invalid = "\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f" + const char *invalid = "\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f" "\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f" - "/\\?%*:|\"<> "; + "/\\?*:|\"<>"; char *fn; bool changed = false; @@ -533,7 +517,7 @@ bool BLI_filename_make_safe(char *fname) bool BLI_path_make_safe(char *path) { /* Simply apply BLI_filename_make_safe() over each component of the path. - * Luckily enough, same 'sfae' rules applies to filenames and dirnames. */ + * Luckily enough, same 'safe' rules applies to filenames and dirnames. */ char *curr_slash, *curr_path = path; bool changed = false; bool skip_first = false; @@ -977,7 +961,7 @@ bool BLI_path_frame_range(char *path, int sta, int end, int digits) */ bool BLI_path_frame_get(char *path, int *r_frame, int *r_numdigits) { - if (path && *path) { + if (*path) { char *file = (char *)BLI_last_slash(path); char *c; int len, numdigits; @@ -1026,9 +1010,9 @@ bool BLI_path_frame_get(char *path, int *r_frame, int *r_numdigits) return false; } -void BLI_path_frame_strip(char *path, bool setsharp, char *ext) +void BLI_path_frame_strip(char *path, bool set_frame_char, char *ext) { - if (path && *path) { + if (*path) { char *file = (char *)BLI_last_slash(path); char *c, *suffix; int len; @@ -1063,15 +1047,12 @@ void BLI_path_frame_strip(char *path, bool setsharp, char *ext) if (numdigits) { /* replace the number with the suffix and terminate the string */ while (numdigits--) { - if (ext) *ext++ = *suffix; - - if (setsharp) *c++ = '#'; - else *c++ = *suffix; - + *ext++ = *suffix; + *c++ = set_frame_char ? '#' : *suffix; suffix++; } - *c = 0; - if (ext) *ext = 0; + *c = '\0'; + *ext = '\0'; } } } @@ -1087,9 +1068,14 @@ bool BLI_path_frame_check_chars(const char *path) } /** - * If path begins with "//", strips that and replaces it with basepath directory. Also converts - * a drive-letter prefix to something more sensible if this is a non-drive-letter-based system. - * Returns true if "//" prefix expansion was done. + * If path begins with "//", strips that and replaces it with basepath directory. + * + * \note Also converts drive-letter prefix to something more sensible + * if this is a non-drive-letter-based system. + * + * \param path: The path to convert. + * \param basepath: The directory to base relative paths with. + * \return true if the path was relative (started with "//"). */ bool BLI_path_abs(char *path, const char *basepath) { @@ -1202,7 +1188,7 @@ bool BLI_path_abs(char *path, const char *basepath) * \note Should only be done with command line paths. * this is _not_ something blenders internal paths support like the "//" prefix */ -bool BLI_path_cwd(char *path) +bool BLI_path_cwd(char *path, const size_t maxlen) { bool wasrelative = true; const int filelen = strlen(path); @@ -1216,24 +1202,15 @@ bool BLI_path_cwd(char *path) #endif if (wasrelative) { - char cwd[FILE_MAX] = ""; - BLI_current_working_dir(cwd, sizeof(cwd)); /* in case the full path to the blend isn't used */ - - if (cwd[0] == '\0') { - printf("Could not get the current working directory - $PWD for an unknown reason.\n"); - } - else { - /* uses the blend path relative to cwd important for loading relative linked files. - * - * cwd should contain c:\ etc on win32 so the relbase can be NULL - * relbase being NULL also prevents // being misunderstood as relative to the current - * blend file which isn't a feature we want to use in this case since were dealing - * with a path from the command line, rather than from inside Blender */ - + char cwd[FILE_MAX]; + /* in case the full path to the blend isn't used */ + if (BLI_current_working_dir(cwd, sizeof(cwd))) { char origpath[FILE_MAX]; BLI_strncpy(origpath, path, FILE_MAX); - - BLI_make_file_string(NULL, path, cwd, origpath); + BLI_join_dirfile(path, maxlen, cwd, origpath); + } + else { + printf("Could not get the current working directory - $PWD for an unknown reason.\n"); } } @@ -1610,17 +1587,16 @@ bool BLI_testextensie_glob(const char *str, const char *ext_fnmatch) while (ext_step[0]) { const char *ext_next; - int len_ext; + size_t len_ext; if ((ext_next = strchr(ext_step, ';'))) { - len_ext = (int)(ext_next - ext_step) + 1; + len_ext = ext_next - ext_step + 1; + BLI_strncpy(pattern, ext_step, (len_ext > sizeof(pattern)) ? sizeof(pattern) : len_ext); } else { - len_ext = sizeof(pattern); + len_ext = BLI_strncpy_rlen(pattern, ext_step, sizeof(pattern)); } - BLI_strncpy(pattern, ext_step, len_ext); - if (fnmatch(pattern, str, FNM_CASEFOLD) == 0) { return true; } @@ -2015,38 +1991,3 @@ void BLI_path_native_slash(char *path) BLI_str_replace_char(path + BLI_path_unc_prefix_len(path), '\\', '/'); #endif } - - -#ifdef WITH_ICONV - -/** - * Converts a string encoded in the charset named by *code to UTF-8. - * Opens a new iconv context each time it is run, which is probably not the - * most efficient. */ -void BLI_string_to_utf8(char *original, char *utf_8, const char *code) -{ - size_t inbytesleft = strlen(original); - size_t outbytesleft = 512; - size_t rv = 0; - iconv_t cd; - - if (NULL == code) { - code = locale_charset(); - } - cd = iconv_open("UTF-8", code); - - if (cd == (iconv_t)(-1)) { - printf("iconv_open Error"); - *utf_8 = '\0'; - return; - } - rv = iconv(cd, &original, &inbytesleft, &utf_8, &outbytesleft); - if (rv == (size_t) -1) { - printf("iconv Error\n"); - iconv_close(cd); - return; - } - *utf_8 = '\0'; - iconv_close(cd); -} -#endif // WITH_ICONV diff --git a/source/blender/blenlib/intern/polyfill2d.c b/source/blender/blenlib/intern/polyfill2d.c index df6caa4b65a..397082b02d2 100644 --- a/source/blender/blenlib/intern/polyfill2d.c +++ b/source/blender/blenlib/intern/polyfill2d.c @@ -799,7 +799,7 @@ static void polyfill_prepare( coords_sign = (cross_poly_v2(coords, coords_tot) >= 0.0f) ? 1 : -1; } else { - /* chech we're passing in correcty args */ + /* check we're passing in correcty args */ #ifdef USE_STRICT_ASSERT #ifndef NDEBUG if (coords_sign == 1) { diff --git a/source/blender/blenlib/intern/rct.c b/source/blender/blenlib/intern/rct.c index 646613d9a29..a5f7fe2a008 100644 --- a/source/blender/blenlib/intern/rct.c +++ b/source/blender/blenlib/intern/rct.c @@ -474,7 +474,7 @@ void BLI_rctf_interp(rctf *rect, const rctf *rect_a, const rctf *rect_b, const f /* BLI_rcti_interp() not needed yet */ -bool BLI_rctf_clamp_pt_v(const struct rctf *rect, float xy[2]) +bool BLI_rctf_clamp_pt_v(const rctf *rect, float xy[2]) { bool changed = false; if (xy[0] < rect->xmin) { xy[0] = rect->xmin; changed = true; } @@ -484,7 +484,7 @@ bool BLI_rctf_clamp_pt_v(const struct rctf *rect, float xy[2]) return changed; } -bool BLI_rcti_clamp_pt_v(const struct rcti *rect, int xy[2]) +bool BLI_rcti_clamp_pt_v(const rcti *rect, int xy[2]) { bool changed = false; if (xy[0] < rect->xmin) { xy[0] = rect->xmin; changed = true; } @@ -494,7 +494,96 @@ bool BLI_rcti_clamp_pt_v(const struct rcti *rect, int xy[2]) return changed; } -bool BLI_rctf_compare(const struct rctf *rect_a, const struct rctf *rect_b, const float limit) +/** + * Clamp \a rect within \a rect_bounds, setting \a r_xy to the offset. + * + * \return true if a change is made. + */ +bool BLI_rctf_clamp(rctf *rect, const rctf *rect_bounds, float r_xy[2]) +{ + bool changed = false; + + r_xy[0] = 0.0f; + r_xy[1] = 0.0f; + + if (rect->xmin < rect_bounds->xmin) { + float ofs = rect_bounds->xmin - rect->xmin; + rect->xmin += ofs; + rect->xmax += ofs; + r_xy[0] += ofs; + changed = true; + } + + if (rect->xmax > rect_bounds->xmax) { + float ofs = rect_bounds->xmax - rect->xmax; + rect->xmin += ofs; + rect->xmax += ofs; + r_xy[0] += ofs; + changed = true; + } + + if (rect->ymin < rect_bounds->ymin) { + float ofs = rect_bounds->ymin - rect->ymin; + rect->ymin += ofs; + rect->ymax += ofs; + r_xy[1] += ofs; + changed = true; + } + + if (rect->ymax > rect_bounds->ymax) { + float ofs = rect_bounds->ymax - rect->ymax; + rect->ymin += ofs; + rect->ymax += ofs; + r_xy[1] += ofs; + changed = true; + } + + return changed; +} + +bool BLI_rcti_clamp(rcti *rect, const rcti *rect_bounds, int r_xy[2]) +{ + bool changed = false; + + r_xy[0] = 0; + r_xy[1] = 0; + + if (rect->xmin < rect_bounds->xmin) { + int ofs = rect_bounds->xmin - rect->xmin; + rect->xmin += ofs; + rect->xmax += ofs; + r_xy[0] += ofs; + changed = true; + } + + if (rect->xmax > rect_bounds->xmax) { + int ofs = rect_bounds->xmax - rect->xmax; + rect->xmin += ofs; + rect->xmax += ofs; + r_xy[0] += ofs; + changed = true; + } + + if (rect->ymin < rect_bounds->ymin) { + int ofs = rect_bounds->ymin - rect->ymin; + rect->ymin += ofs; + rect->ymax += ofs; + r_xy[1] += ofs; + changed = true; + } + + if (rect->ymax > rect_bounds->ymax) { + int ofs = rect_bounds->ymax - rect->ymax; + rect->ymin += ofs; + rect->ymax += ofs; + r_xy[1] += ofs; + changed = true; + } + + return changed; +} + +bool BLI_rctf_compare(const rctf *rect_a, const rctf *rect_b, const float limit) { if (fabsf(rect_a->xmin - rect_b->xmin) < limit) if (fabsf(rect_a->xmax - rect_b->xmax) < limit) @@ -505,7 +594,7 @@ bool BLI_rctf_compare(const struct rctf *rect_a, const struct rctf *rect_b, cons return false; } -bool BLI_rcti_compare(const struct rcti *rect_a, const struct rcti *rect_b) +bool BLI_rcti_compare(const rcti *rect_a, const rcti *rect_b) { if (rect_a->xmin == rect_b->xmin) if (rect_a->xmax == rect_b->xmax) diff --git a/source/blender/blenlib/intern/storage.c b/source/blender/blenlib/intern/storage.c index 7fdf6ec8101..f7a8664c739 100644 --- a/source/blender/blenlib/intern/storage.c +++ b/source/blender/blenlib/intern/storage.c @@ -91,8 +91,14 @@ char *BLI_current_working_dir(char *dir, const size_t maxncpy) { const char *pwd = getenv("PWD"); if (pwd) { - BLI_strncpy(dir, pwd, maxncpy); - return dir; + size_t srclen = BLI_strnlen(pwd, maxncpy); + if (srclen != maxncpy) { + memcpy(dir, pwd, srclen + 1); + return dir; + } + else { + return NULL; + } } return getcwd(dir, maxncpy); diff --git a/source/blender/blenlib/intern/string.c b/source/blender/blenlib/intern/string.c index 6cc00fc60ee..e93d2b7507a 100644 --- a/source/blender/blenlib/intern/string.c +++ b/source/blender/blenlib/intern/string.c @@ -756,7 +756,7 @@ void BLI_str_toupper_ascii(char *str, const size_t len) * * \param str * \param pad - * \return The number of zeto's stripped. + * \return The number of zeros stripped. */ int BLI_str_rstrip_float_zero(char *str, const char pad) { diff --git a/source/blender/blenlib/intern/task.c b/source/blender/blenlib/intern/task.c index 08d40a158ca..a125bf7d8d0 100644 --- a/source/blender/blenlib/intern/task.c +++ b/source/blender/blenlib/intern/task.c @@ -207,7 +207,6 @@ TaskScheduler *BLI_task_scheduler_create(int num_threads) if (pthread_create(&scheduler->threads[i], NULL, task_scheduler_thread_run, thread) != 0) { fprintf(stderr, "TaskScheduler failed to launch thread %d/%d\n", i, num_threads); - MEM_freeN(thread); } } } diff --git a/source/blender/blenlib/intern/timecode.c b/source/blender/blenlib/intern/timecode.c index 4ae9249ec0d..e755a7ae52c 100644 --- a/source/blender/blenlib/intern/timecode.c +++ b/source/blender/blenlib/intern/timecode.c @@ -72,20 +72,20 @@ size_t BLI_timecode_string_from_time( time = -time; } - if (time >= 3600) { + if (time >= 3600.0f) { /* hours */ /* XXX should we only display a single digit for hours since clips are * VERY UNLIKELY to be more than 1-2 hours max? However, that would * go against conventions... */ hours = (int)time / 3600; - time = (float)fmod(time, 3600); + time = fmodf(time, 3600); } - if (time >= 60) { + if (time >= 60.0f) { /* minutes */ minutes = (int)time / 60; - time = (float)fmod(time, 60); + time = fmodf(time, 60); } if (power <= 0) { @@ -163,6 +163,18 @@ size_t BLI_timecode_string_from_time( } break; } + case USER_TIMECODE_SUBRIP: + { + /* SubRip, like SMPTE milliseconds but seconds and milliseconds are separated by a comma, not a dot... */ + + /* precision of decimal part */ + const int ms_dp = (power <= 0) ? (1 - power) : 1; + const int ms = iroundf((time - (float)seconds) * 1000.0f); + + rlen = BLI_snprintf_rlen( + str, maxncpy, "%s%02d:%02d:%02d,%0*d", neg, hours, minutes, seconds, ms_dp, ms); + break; + } case USER_TIMECODE_SECONDS_ONLY: { /* only show the original seconds display */ diff --git a/source/blender/blenlib/intern/winstuff.c b/source/blender/blenlib/intern/winstuff.c index a67e116969e..32ab16b4b5a 100644 --- a/source/blender/blenlib/intern/winstuff.c +++ b/source/blender/blenlib/intern/winstuff.c @@ -93,7 +93,7 @@ void RegisterBlendExtension(void) char RegCmd[MAX_PATH * 2]; char MBox[256]; char *blender_app; -#ifndef WIN64 +#ifndef _WIN64 BOOL IsWOW64; #endif @@ -158,7 +158,7 @@ void RegisterBlendExtension(void) BLI_getInstallationDir(InstallDir); GetSystemDirectory(SysDir, FILE_MAXDIR); -#ifdef WIN64 +#ifdef _WIN64 ThumbHandlerDLL = "BlendThumb64.dll"; #elif defined(__MINGW32__) ThumbHandlerDLL = "BlendThumb.dll"; diff --git a/source/blender/blenloader/BLO_blend_defs.h b/source/blender/blenloader/BLO_blend_defs.h index 44f0fa9aa53..a6b06a080cc 100644 --- a/source/blender/blenloader/BLO_blend_defs.h +++ b/source/blender/blenloader/BLO_blend_defs.h @@ -75,4 +75,6 @@ enum { ENDB = BLEND_MAKE_ID('E', 'N', 'D', 'B'), }; +#define BLEN_THUMB_MEMSIZE_FILE(_x, _y) (sizeof(int) * (size_t)(2 + (_x) * (_y))) + #endif /* __BLO_BLEND_DEFS_H__ */ diff --git a/source/blender/blenloader/BLO_readfile.h b/source/blender/blenloader/BLO_readfile.h index 5f881c0855c..51b016a77f8 100644 --- a/source/blender/blenloader/BLO_readfile.h +++ b/source/blender/blenloader/BLO_readfile.h @@ -36,6 +36,7 @@ extern "C" { #endif +struct BlendThumbnail; struct bScreen; struct LinkNode; struct Main; @@ -43,6 +44,7 @@ struct MemFile; struct ReportList; struct Scene; struct UserDef; +struct View3D; struct bContext; struct BHead; struct FileData; @@ -69,186 +71,39 @@ typedef struct BlendFileData { BlenFileType type; } BlendFileData; -/** - * Open a blender file from a pathname. The function - * returns NULL and sets a report in the list if - * it cannot open the file. - * - * \param filepath The path of the file to open. - * \param reports If the return value is NULL, errors - * indicating the cause of the failure. - * \return The data of the file. - */ -BlendFileData *BLO_read_from_file( - const char *filepath, - struct ReportList *reports); - -/** - * Open a blender file from memory. The function - * returns NULL and sets a report in the list if - * it cannot open the file. - * - * \param mem The file data. - * \param memsize The length of \a mem. - * \param reports If the return value is NULL, errors - * indicating the cause of the failure. - * \return The data of the file. - */ -BlendFileData *BLO_read_from_memory( - const void *mem, int memsize, - struct ReportList *reports); - -/** - * oldmain is old main, from which we will keep libraries, images, .. - * file name is current file, only for retrieving library data */ - +BlendFileData *BLO_read_from_file(const char *filepath, struct ReportList *reports); +BlendFileData *BLO_read_from_memory(const void *mem, int memsize, struct ReportList *reports); BlendFileData *BLO_read_from_memfile( struct Main *oldmain, const char *filename, struct MemFile *memfile, struct ReportList *reports); -/** - * Free's a BlendFileData structure and _all_ the - * data associated with it (the userdef data, and - * the main libblock data). - * - * \param bfd The structure to free. - */ -void -BLO_blendfiledata_free(BlendFileData *bfd); +void BLO_blendfiledata_free(BlendFileData *bfd); -/** - * Open a blendhandle from a file path. - * - * \param filepath: The file path to open. - * \param reports: Report errors in opening the file (can be NULL). - * \return A handle on success, or NULL on failure. - */ -BlendHandle *BLO_blendhandle_from_file( - const char *filepath, - struct ReportList *reports); - -/** - * Open a blendhandle from memory. - * - * \param mem The data to load from. - * \param memsize The size of the data. - * \return A handle on success, or NULL on failure. - */ - -BlendHandle *BLO_blendhandle_from_memory( - const void *mem, int memsize); - -/** - * Gets the names of all the datablocks in a file - * of a certain type (ie. All the scene names in - * a file). - * - * \param bh The blendhandle to access. - * \param ofblocktype The type of names to get. - * \param tot_names The length of the returned list. - * \return A BLI_linklist of strings. The string links - * should be freed with malloc. - */ -struct LinkNode *BLO_blendhandle_get_datablock_names( - BlendHandle *bh, - int ofblocktype, int *tot_names); - -/** - * Gets the previews of all the datablocks in a file - * of a certain type (ie. All the scene names in - * a file). - * - * \param bh The blendhandle to access. - * \param ofblocktype The type of names to get. - * \param tot_prev The length of the returned list. - * \return A BLI_linklist of PreviewImage. The PreviewImage links - * should be freed with malloc. - */ -struct LinkNode *BLO_blendhandle_get_previews( - BlendHandle *bh, - int ofblocktype, int *tot_prev); +BlendHandle *BLO_blendhandle_from_file(const char *filepath, struct ReportList *reports); +BlendHandle *BLO_blendhandle_from_memory(const void *mem, int memsize); -/** - * Gets the names of all the datablock groups in a - * file. (ie. file contains Scene, Mesh, and Lamp - * datablocks). - * - * \param bh The blendhandle to access. - * \return A BLI_linklist of strings. The string links - * should be freed with malloc. - */ +struct LinkNode *BLO_blendhandle_get_datablock_names(BlendHandle *bh, int ofblocktype, int *tot_names); +struct LinkNode *BLO_blendhandle_get_previews(BlendHandle *bh, int ofblocktype, int *tot_prev); struct LinkNode *BLO_blendhandle_get_linkable_groups(BlendHandle *bh); -/** - * Close and free a blendhandle. The handle - * becomes invalid after this call. - * - * \param bh The handle to close. - */ -void -BLO_blendhandle_close(BlendHandle *bh); +void BLO_blendhandle_close(BlendHandle *bh); /***/ #define BLO_GROUP_MAX 32 bool BLO_has_bfile_extension(const char *str); - -/** - * \param path the full path to explode. - * \param r_dir the string that'll contain path up to blend file itself ('library' path). - * \param r_group the string that'll contain 'group' part of the path, if any. May be NULL. - * \param r_name the string that'll contain data's name part of the path, if any. May be NULL. - * \return true if path contains a blend file. - */ bool BLO_library_path_explode(const char *path, char *r_dir, char **r_group, char **r_name); - -/** - * Initialize the BlendHandle for appending or linking library data. - * - * \param mainvar The current main database eg G.main or CTX_data_main(C). - * \param bh A blender file handle as returned by BLO_blendhandle_from_file or BLO_blendhandle_from_memory. - * \param filepath Used for relative linking, copied to the lib->name - * \return the library Main, to be passed to BLO_library_append_named_part as mainl. - */ -struct Main *BLO_library_append_begin( - struct Main *mainvar, BlendHandle **bh, - const char *filepath); - - -/** - * Link/Append a named datablock from an external blend file. - * - * \param mainl The main database to link from (not the active one). - * \param bh The blender file handle. - * \param idname The name of the datablock (without the 2 char ID prefix) - * \param idcode The kind of datablock to link. - * \return the appended ID when found. - */ -struct ID *BLO_library_append_named_part( +struct Main *BLO_library_link_begin(struct Main *mainvar, BlendHandle **bh, const char *filepath); +struct ID *BLO_library_link_named_part(struct Main *mainl, BlendHandle **bh, const short idcode, const char *name); +struct ID *BLO_library_link_named_part_ex( struct Main *mainl, BlendHandle **bh, - const char *idname, const int idcode); - -/** - * Link/Append a named datablock from an external blend file. - * optionally instance the object in the scene when the flags are set. - * - * \param C The context, when NULL instancing object in the scene isn't done. - * \param mainl The main database to link from (not the active one). - * \param bh The blender file handle. - * \param idname The name of the datablock (without the 2 char ID prefix) - * \param idcode The kind of datablock to link. - * \param flag Options for linking, used for instancing. - * \return the appended ID when found. - */ -struct ID *BLO_library_append_named_part_ex( - const struct bContext *C, struct Main *mainl, BlendHandle **bh, - const char *idname, const int idcode, const short flag); - -void BLO_library_append_end(const struct bContext *C, struct Main *mainl, BlendHandle **bh, int idcode, short flag); + const short idcode, const char *name, const short flag, + struct Scene *scene, struct View3D *v3d); +void BLO_library_link_end(struct Main *mainl, BlendHandle **bh, short flag, struct Scene *scene, struct View3D *v3d); -void BLO_library_append_all(struct Main *mainl, BlendHandle *bh); +void BLO_library_link_all(struct Main *mainl, BlendHandle *bh); void *BLO_library_read_struct(struct FileData *fd, struct BHead *bh, const char *blockname); @@ -257,27 +112,17 @@ BlendFileData *blo_read_blendafterruntime(int file, const char *name, int actual /* internal function but we need to expose it */ void blo_lib_link_screen_restore(struct Main *newmain, struct bScreen *curscreen, struct Scene *curscene); -/** - * BLO_expand_main() loops over all ID data in Main to mark relations. - * Set (id->flag & LIB_NEED_EXPAND) to mark expanding. Flags get cleared after expanding. - * - * \param expand_doit_func() gets called for each ID block it finds - */ -void BLO_main_expander(void (*expand_doit_func)(void *, struct Main *, void *)); +typedef void (*BLOExpandDoitCallback) (void *fdhandle, struct Main *mainvar, void *idv); -/** - * BLO_expand_main() loops over all ID data in Main to mark relations. - * Set (id->flag & LIB_NEED_EXPAND) to mark expanding. Flags get cleared after expanding. - * - * \param fdhandle usually filedata, or own handle - * \param mainvar the Main database to expand - */ +void BLO_main_expander(BLOExpandDoitCallback expand_doit_func); void BLO_expand_main(void *fdhandle, struct Main *mainvar); /* Update defaults in startup.blend & userprefs.blend, without having to save and embed it */ void BLO_update_defaults_userpref_blend(void); void BLO_update_defaults_startup_blend(struct Main *mainvar); +struct BlendThumbnail *BLO_thumbnail_from_file(const char *filepath); + #ifdef __cplusplus } #endif diff --git a/source/blender/blenloader/BLO_writefile.h b/source/blender/blenloader/BLO_writefile.h index 7a8429afec0..0d66eb743aa 100644 --- a/source/blender/blenloader/BLO_writefile.h +++ b/source/blender/blenloader/BLO_writefile.h @@ -33,14 +33,14 @@ * \brief external writefile function prototypes. */ +struct BlendThumbnail; struct MemFile; struct Main; struct ReportList; -extern int BLO_write_file(struct Main *mainvar, const char *filepath, int write_flags, struct ReportList *reports, const int *thumb); +extern int BLO_write_file(struct Main *mainvar, const char *filepath, int write_flags, + struct ReportList *reports, const struct BlendThumbnail *thumb); extern int BLO_write_file_mem(struct Main *mainvar, struct MemFile *compare, struct MemFile *current, int write_flags); -#define BLEN_THUMB_SIZE 128 - #endif diff --git a/source/blender/blenloader/intern/readblenentry.c b/source/blender/blenloader/intern/readblenentry.c index e8d7a46687f..cd6df354ca7 100644 --- a/source/blender/blenloader/intern/readblenentry.c +++ b/source/blender/blenloader/intern/readblenentry.c @@ -72,6 +72,13 @@ void BLO_blendhandle_print_sizes(BlendHandle *, void *); /* Access routines used by filesel. */ +/** + * Open a blendhandle from a file path. + * + * \param filepath The file path to open. + * \param reports Report errors in opening the file (can be NULL). + * \return A handle on success, or NULL on failure. + */ BlendHandle *BLO_blendhandle_from_file(const char *filepath, ReportList *reports) { BlendHandle *bh; @@ -81,6 +88,13 @@ BlendHandle *BLO_blendhandle_from_file(const char *filepath, ReportList *reports return bh; } +/** + * Open a blendhandle from memory. + * + * \param mem The data to load from. + * \param memsize The size of the data. + * \return A handle on success, or NULL on failure. + */ BlendHandle *BLO_blendhandle_from_memory(const void *mem, int memsize) { BlendHandle *bh; @@ -120,6 +134,14 @@ void BLO_blendhandle_print_sizes(BlendHandle *bh, void *fp) fprintf(fp, "]\n"); } +/** + * Gets the names of all the datablocks in a file of a certain type (e.g. all the scene names in a file). + * + * \param bh The blendhandle to access. + * \param ofblocktype The type of names to get. + * \param tot_names The length of the returned list. + * \return A BLI_linklist of strings. The string links should be freed with malloc. + */ LinkNode *BLO_blendhandle_get_datablock_names(BlendHandle *bh, int ofblocktype, int *tot_names) { FileData *fd = (FileData *) bh; @@ -142,6 +164,14 @@ LinkNode *BLO_blendhandle_get_datablock_names(BlendHandle *bh, int ofblocktype, return names; } +/** + * Gets the previews of all the datablocks in a file of a certain type (e.g. all the scene previews in a file). + * + * \param bh The blendhandle to access. + * \param ofblocktype The type of names to get. + * \param tot_prev The length of the returned list. + * \return A BLI_linklist of PreviewImage. The PreviewImage links should be freed with malloc. + */ LinkNode *BLO_blendhandle_get_previews(BlendHandle *bh, int ofblocktype, int *tot_prev) { FileData *fd = (FileData *) bh; @@ -232,7 +262,13 @@ LinkNode *BLO_blendhandle_get_previews(BlendHandle *bh, int ofblocktype, int *to return previews; } -LinkNode *BLO_blendhandle_get_linkable_groups(BlendHandle *bh) +/** + * Gets the names of all the linkable datablock types available in a file. (e.g. "Scene", "Mesh", "Lamp", etc.). + * + * \param bh The blendhandle to access. + * \return A BLI_linklist of strings. The string links should be freed with malloc. + */ +LinkNode *BLO_blendhandle_get_linkable_groups(BlendHandle *bh) { FileData *fd = (FileData *) bh; GSet *gathered = BLI_gset_ptr_new("linkable_groups gh"); @@ -260,6 +296,11 @@ LinkNode *BLO_blendhandle_get_linkable_groups(BlendHandle *bh) return names; } +/** + * Close and free a blendhandle. The handle becomes invalid after this call. + * + * \param bh The handle to close. + */ void BLO_blendhandle_close(BlendHandle *bh) { FileData *fd = (FileData *) bh; @@ -269,6 +310,14 @@ void BLO_blendhandle_close(BlendHandle *bh) /**********/ +/** + * Open a blender file from a pathname. The function returns NULL + * and sets a report in the list if it cannot open the file. + * + * \param filepath The path of the file to open. + * \param reports If the return value is NULL, errors indicating the cause of the failure. + * \return The data of the file. + */ BlendFileData *BLO_read_from_file(const char *filepath, ReportList *reports) { BlendFileData *bfd = NULL; @@ -284,6 +333,15 @@ BlendFileData *BLO_read_from_file(const char *filepath, ReportList *reports) return bfd; } +/** + * Open a blender file from memory. The function returns NULL + * and sets a report in the list if it cannot open the file. + * + * \param mem The file data. + * \param memsize The length of \a mem. + * \param reports If the return value is NULL, errors indicating the cause of the failure. + * \return The data of the file. + */ BlendFileData *BLO_read_from_memory(const void *mem, int memsize, ReportList *reports) { BlendFileData *bfd = NULL; @@ -299,11 +357,17 @@ BlendFileData *BLO_read_from_memory(const void *mem, int memsize, ReportList *re return bfd; } +/** + * Used for undo/redo, skips part of libraries reading (assuming their data are already loaded & valid). + * + * \param oldmain old main, from which we will keep libraries and other datablocks that should not have changed. + * \param filename current file, only for retrieving library data. + */ BlendFileData *BLO_read_from_memfile(Main *oldmain, const char *filename, MemFile *memfile, ReportList *reports) { BlendFileData *bfd = NULL; FileData *fd; - ListBase mainlist; + ListBase old_mainlist; fd = blo_openblendermemfile(memfile, reports); if (fd) { @@ -314,9 +378,9 @@ BlendFileData *BLO_read_from_memfile(Main *oldmain, const char *filename, MemFil blo_clear_proxy_pointers_from_lib(oldmain); /* separate libraries from old main */ - blo_split_main(&mainlist, oldmain); + blo_split_main(&old_mainlist, oldmain); /* add the library pointers in oldmap lookup */ - blo_add_library_pointer_map(&mainlist, fd); + blo_add_library_pointer_map(&old_mainlist, fd); /* makes lookup of existing images in old main */ blo_make_image_pointer_map(fd, oldmain); @@ -340,25 +404,55 @@ BlendFileData *BLO_read_from_memfile(Main *oldmain, const char *filename, MemFil /* ensures relinked sounds are not freed */ blo_end_sound_pointer_map(fd, oldmain); - /* move libraries from old main to new main */ - if (bfd && mainlist.first != mainlist.last) { - - /* Library structs themselves */ - bfd->main->library = oldmain->library; - BLI_listbase_clear(&oldmain->library); - - /* add the Library mainlist to the new main */ - BLI_remlink(&mainlist, oldmain); - BLI_addhead(&mainlist, bfd->main); + /* Still in-use libraries have already been moved from oldmain to new mainlist, + * but oldmain itself shall *never* be 'transferred' to new mainlist! */ + BLI_assert(old_mainlist.first == oldmain); + + if (bfd && old_mainlist.first != old_mainlist.last) { + /* Even though directly used libs have been already moved to new main, indirect ones have not. + * This is a bit annoying, but we have no choice but to keep them all for now - means some now unused + * data may remain in memory, but think we'll have to live with it. */ + Main *libmain; + Main *newmain = bfd->main; + ListBase new_mainlist = {newmain, newmain}; + + for (libmain = oldmain->next; libmain; libmain = libmain->next) { + /* Note that LIB_INDIRECT does not work with libraries themselves, so we use non-NULL parent + * to detect indirect-linked ones... */ + if (libmain->curlib && (libmain->curlib->parent != NULL)) { + BLI_remlink(&old_mainlist, libmain); + BLI_addtail(&new_mainlist, libmain); + } +#if 0 + else { + printf("Dropped Main for lib: %s\n", libmain->curlib->id.name); + } +#endif + } + /* In any case, we need to move all lib datablocks themselves - those are 'first level data', + * getting rid of them would imply updating spaces & co to prevent invalid pointers access. */ + BLI_movelisttolist(&newmain->library, &oldmain->library); + + blo_join_main(&new_mainlist); } - blo_join_main(&mainlist); - + + /* printf("Remaining mains/libs in oldmain: %d\n", BLI_listbase_count(&fd->old_mainlist) - 1); */ + + /* That way, libs (aka mains) we did not reuse in new undone/redone state + * will be cleared together with oldmain... */ + blo_join_main(&old_mainlist); + blo_freefiledata(fd); } return bfd; } +/** + * Frees a BlendFileData structure and *all* the data associated with it (the userdef data, and the main libblock data). + * + * \param bfd The structure to free. + */ void BLO_blendfiledata_free(BlendFileData *bfd) { if (bfd->main) { diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c index 7bc6410316d..2c341f97a66 100644 --- a/source/blender/blenloader/intern/readfile.c +++ b/source/blender/blenloader/intern/readfile.c @@ -124,6 +124,7 @@ #include "BKE_global.h" // for G #include "BKE_group.h" #include "BKE_library.h" // for which_libbase +#include "BKE_library_query.h" #include "BKE_idcode.h" #include "BKE_material.h" #include "BKE_main.h" // for Main @@ -618,7 +619,9 @@ static Main *blo_find_main(FileData *fd, const char *filepath, const char *relab m = BKE_main_new(); BLI_addtail(mainlist, m); - lib = BKE_libblock_alloc(m, ID_LI, "lib"); + /* Add library datablock itself to 'main' Main, since libraries are **never** linked data. + * Fixes bug where you could end with all ID_LI datablocks having the same name... */ + lib = BKE_libblock_alloc(mainlist->first, ID_LI, "Lib"); BLI_strncpy(lib->name, filepath, sizeof(lib->name)); BLI_strncpy(lib->filepath, name1, sizeof(lib->filepath)); @@ -851,6 +854,12 @@ BHead *blo_nextbhead(FileData *fd, BHead *thisblock) return(bhead); } +/* Warning! Caller's responsability to ensure given bhead **is** and ID one! */ +const char *bhead_id_name(const FileData *fd, const BHead *bhead) +{ + return (const char *)POINTER_OFFSET(bhead, sizeof(*bhead) + fd->id_name_offs); +} + static void decode_blender_header(FileData *fd) { char header[SIZEOFBLENDERHEADER], num[4]; @@ -917,6 +926,41 @@ static int read_file_dna(FileData *fd) return 0; } +static int *read_file_thumbnail(FileData *fd) +{ + BHead *bhead; + int *blend_thumb = NULL; + + for (bhead = blo_firstbhead(fd); bhead; bhead = blo_nextbhead(fd, bhead)) { + if (bhead->code == TEST) { + const bool do_endian_swap = (fd->flags & FD_FLAGS_SWITCH_ENDIAN) != 0; + int *data = (int *)(bhead + 1); + + if (bhead->len < (2 * sizeof(int))) { + break; + } + + if (do_endian_swap) { + BLI_endian_switch_int32(&data[0]); + BLI_endian_switch_int32(&data[1]); + } + + if (bhead->len < BLEN_THUMB_MEMSIZE_FILE(data[0], data[1])) { + break; + } + + blend_thumb = data; + break; + } + else if (bhead->code != REND) { + /* Thumbnail is stored in TEST immediately after first REND... */ + break; + } + } + + return blend_thumb; +} + static int fd_read_from_file(FileData *filedata, void *buffer, unsigned int size) { int readsize = read(filedata->filedes, buffer, size); @@ -1080,6 +1124,33 @@ FileData *blo_openblenderfile(const char *filepath, ReportList *reports) } } +/** + * Same as blo_openblenderfile(), but does not reads DNA data, only header. Use it for light access + * (e.g. thumbnail reading). + */ +static FileData *blo_openblenderfile_minimal(const char *filepath) +{ + gzFile gzfile; + errno = 0; + gzfile = BLI_gzopen(filepath, "rb"); + + if (gzfile != (gzFile)Z_NULL) { + FileData *fd = filedata_new(); + fd->gzfiledes = gzfile; + fd->read = fd_read_gzip_from_file; + + decode_blender_header(fd); + + if (fd->flags & FD_FLAGS_FILE_OK) { + return fd; + } + + blo_freefiledata(fd); + } + + return NULL; +} + static int fd_read_gzip_from_memory(FileData *filedata, void *buffer, unsigned int size) { int err; @@ -1228,12 +1299,27 @@ void blo_freefiledata(FileData *fd) /* ************ DIV ****************** */ +/** + * Check whether given path ends with a blend file compatible extension (.blend, .ble or .blend.gz). + * + * \param str The path to check. + * \return true is this path ends with a blender file extension. + */ bool BLO_has_bfile_extension(const char *str) { const char *ext_test[4] = {".blend", ".ble", ".blend.gz", NULL}; return BLI_testextensie_array(str, ext_test); } +/** + * Try to explode given path into its 'library components' (i.e. a .blend file, id type/group, and datablock itself). + * + * \param path the full path to explode. + * \param r_dir the string that'll contain path up to blend file itself ('library' path). + * \param r_group the string that'll contain 'group' part of the path, if any. May be NULL. + * \param r_name the string that'll contain data's name part of the path, if any. May be NULL. + * \return true if path contains a blend file. + */ bool BLO_library_path_explode(const char *path, char *r_dir, char **r_group, char **r_name) { /* We might get some data names with slashes, so we have to go up in path until we find blend file itself, @@ -1290,6 +1376,40 @@ bool BLO_library_path_explode(const char *path, char *r_dir, char **r_group, cha return true; } +/** + * Does a very light reading of given .blend file to extract its stored thumbnail. + * + * \param filepath The path of the file to extract thumbnail from. + * \return The raw thumbnail + * (MEM-allocated, as stored in file, use BKE_main_thumbnail_to_imbuf() to convert it to ImBuf image). + */ +BlendThumbnail *BLO_thumbnail_from_file(const char *filepath) +{ + FileData *fd; + BlendThumbnail *data; + int *fd_data; + + fd = blo_openblenderfile_minimal(filepath); + fd_data = fd ? read_file_thumbnail(fd) : NULL; + + if (fd_data) { + const size_t sz = BLEN_THUMB_MEMSIZE(fd_data[0], fd_data[1]); + data = MEM_mallocN(sz, __func__); + + BLI_assert((sz - sizeof(*data)) == (BLEN_THUMB_MEMSIZE_FILE(fd_data[0], fd_data[1]) - (sizeof(*fd_data) * 2))); + data->width = fd_data[0]; + data->height = fd_data[1]; + memcpy(data->rect, &fd_data[2], sz - sizeof(*data)); + } + else { + data = NULL; + } + + blo_freefiledata(fd); + + return data; +} + /* ************** OLD POINTERS ******************* */ static void *newdataadr(FileData *fd, void *adr) /* only direct databocks */ @@ -1680,9 +1800,9 @@ void blo_end_packed_pointer_map(FileData *fd, Main *oldmain) /* undo file support: add all library pointers in lookup */ -void blo_add_library_pointer_map(ListBase *mainlist, FileData *fd) +void blo_add_library_pointer_map(ListBase *old_mainlist, FileData *fd) { - Main *ptr = mainlist->first; + Main *ptr = old_mainlist->first; ListBase *lbarray[MAX_LIBARRAY]; for (ptr = ptr->next; ptr; ptr = ptr->next) { @@ -1693,6 +1813,8 @@ void blo_add_library_pointer_map(ListBase *mainlist, FileData *fd) oldnewmap_insert(fd->libmap, id, id, GS(id->name)); } } + + fd->old_mainlist = old_mainlist; } @@ -4498,15 +4620,15 @@ static void direct_link_latt(FileData *fd, Lattice *lt) /* ************ READ OBJECT ***************** */ -static void lib_link_modifiers__linkModifiers(void *userData, Object *ob, - ID **idpoin) +static void lib_link_modifiers__linkModifiers( + void *userData, Object *ob, ID **idpoin, int cd_flag) { FileData *fd = userData; *idpoin = newlibadr(fd, ob->id.lib, *idpoin); - /* hardcoded bad exception; non-object modifier data gets user count (texture, displace) */ - if (*idpoin && GS((*idpoin)->name)!=ID_OB) + if (*idpoin != NULL && (cd_flag & IDWALK_USER) != 0) { (*idpoin)->us++; + } } static void lib_link_modifiers(FileData *fd, Object *ob) { @@ -5486,16 +5608,10 @@ static void lib_link_scene(FileData *fd, Main *main) } } if (seq->clip) { - seq->clip = newlibadr(fd, sce->id.lib, seq->clip); - if (seq->clip) { - seq->clip->id.us++; - } + seq->clip = newlibadr_us(fd, sce->id.lib, seq->clip); } if (seq->mask) { - seq->mask = newlibadr(fd, sce->id.lib, seq->mask); - if (seq->mask) { - seq->mask->id.us++; - } + seq->mask = newlibadr_us(fd, sce->id.lib, seq->mask); } if (seq->scene_camera) { seq->scene_camera = newlibadr(fd, sce->id.lib, seq->scene_camera); @@ -6437,6 +6553,7 @@ void blo_lib_link_screen_restore(Main *newmain, bScreen *curscreen, Scene *cursc else if (sl->spacetype == SPACE_FILE) { SpaceFile *sfile = (SpaceFile *)sl; sfile->op = NULL; + sfile->previews_timer = NULL; } else if (sl->spacetype == SPACE_ACTION) { SpaceAction *saction = (SpaceAction *)sl; @@ -6520,7 +6637,13 @@ void blo_lib_link_screen_restore(Main *newmain, bScreen *curscreen, Scene *cursc BLI_mempool_iternew(so->treestore, &iter); while ((tselem = BLI_mempool_iterstep(&iter))) { - tselem->id = restore_pointer_by_name(newmain, tselem->id, USER_IGNORE); + /* Do not try to restore pointers to drivers/sequence/etc., can crash in undo case! */ + if (TSE_IS_REAL_ID(tselem)) { + tselem->id = restore_pointer_by_name(newmain, tselem->id, USER_IGNORE); + } + else { + tselem->id = NULL; + } } if (so->treehash) { /* rebuild hash table, because it depends on ids too */ @@ -6967,6 +7090,7 @@ static bool direct_link_screen(FileData *fd, bScreen *sc) sfile->files = NULL; sfile->layout = NULL; sfile->op = NULL; + sfile->previews_timer = NULL; sfile->params = newdataadr(fd, sfile->params); } else if (sl->spacetype == SPACE_CLIP) { @@ -7079,11 +7203,7 @@ static void lib_link_speaker(FileData *fd, Main *main) if (spk->id.flag & LIB_NEED_LINK) { if (spk->adt) lib_link_animdata(fd, &spk->id, spk->adt); - spk->sound= newlibadr(fd, spk->id.lib, spk->sound); - if (spk->sound) { - spk->sound->id.us++; - } - + spk->sound = newlibadr_us(fd, spk->id.lib, spk->sound); spk->id.flag -= LIB_NEED_LINK; } } @@ -7736,14 +7856,66 @@ static BHead *read_data_into_oldnewmap(FileData *fd, BHead *bhead, const char *a static BHead *read_libblock(FileData *fd, Main *main, BHead *bhead, int flag, ID **r_id) { - /* this routine reads a libblock and its direct data. Use link functions - * to connect it all + /* this routine reads a libblock and its direct data. Use link functions to connect it all */ ID *id; ListBase *lb; const char *allocname; bool wrong_id = false; - + + /* In undo case, most libs and linked data should be kept as is from previous state (see BLO_read_from_memfile). + * However, some needed by the snapshot being read may have been removed in previous one, and would go missing. + * This leads e.g. to desappearing objects in some undo/redo case, see T34446. + * That means we have to carefully check whether current lib or libdata already exits in old main, if it does + * we merely copy it over into new main area, otherwise we have to do a full read of that bhead... */ + if (fd->memfile && ELEM(bhead->code, ID_LI, ID_ID)) { + const char *idname = bhead_id_name(fd, bhead); + + /* printf("Checking %s...\n", idname); */ + + if (bhead->code == ID_LI) { + Main *libmain = fd->old_mainlist->first; + /* Skip oldmain itself... */ + for (libmain = libmain->next; libmain; libmain = libmain->next) { + /* printf("... against %s: ", libmain->curlib ? libmain->curlib->id.name : "<NULL>"); */ + if (libmain->curlib && STREQ(idname, libmain->curlib->id.name)) { + Main *oldmain = fd->old_mainlist->first; + /* printf("FOUND!\n"); */ + /* In case of a library, we need to re-add its main to fd->mainlist, because if we have later + * a missing ID_ID, we need to get the correct lib it is linked to! + * Order is crucial, we cannot bulk-add it in BLO_read_from_memfile() like it used to be... */ + BLI_remlink(fd->old_mainlist, libmain); + BLI_remlink_safe(&oldmain->library, libmain->curlib); + BLI_addtail(fd->mainlist, libmain); + BLI_addtail(&main->library, libmain->curlib); + + if (r_id) { + *r_id = NULL; /* Just in case... */ + } + return blo_nextbhead(fd, bhead); + } + /* printf("nothing...\n"); */ + } + } + else { + /* printf("... in %s (%s): ", main->curlib ? main->curlib->id.name : "<NULL>", main->curlib ? main->curlib->name : "<NULL>"); */ + if ((id = BKE_libblock_find_name_ex(main, GS(idname), idname + 2))) { + /* printf("FOUND!\n"); */ + /* Even though we found our linked ID, there is no guarantee its address is still the same... */ + if (id != bhead->old) { + oldnewmap_insert(fd->libmap, bhead->old, id, GS(id->name)); + } + + /* No need to do anything else for ID_ID, it's assumed already present in its lib's main... */ + if (r_id) { + *r_id = NULL; /* Just in case... */ + } + return blo_nextbhead(fd, bhead); + } + /* printf("nothing...\n"); */ + } + } + /* read libblock */ id = read_struct(fd, bhead, "lib block"); if (r_id) @@ -7769,7 +7941,7 @@ static BHead *read_libblock(FileData *fd, Main *main, BHead *bhead, int flag, ID if (id->flag & LIB_FAKEUSER) id->us= 1; else id->us = 0; id->icon_id = 0; - id->flag &= ~(LIB_ID_RECALC|LIB_ID_RECALC_DATA|LIB_DOIT); + id->flag &= ~(LIB_ID_RECALC | LIB_ID_RECALC_DATA | LIB_DOIT | LIB_MISSING); /* this case cannot be direct_linked: it's just the ID part */ if (bhead->code == ID_ID) { @@ -8178,6 +8350,24 @@ BlendFileData *blo_read_file_internal(FileData *fd, const char *filepath) bfd->type = BLENFILETYPE_BLEND; BLI_strncpy(bfd->main->name, filepath, sizeof(bfd->main->name)); + if (G.background) { + /* We only read & store .blend thumbnail in background mode + * (because we cannot re-generate it, no OpenGL available). + */ + const int *data = read_file_thumbnail(fd); + + if (data) { + const size_t sz = BLEN_THUMB_MEMSIZE(data[0], data[1]); + bfd->main->blen_thumb = MEM_mallocN(sz, __func__); + + BLI_assert((sz - sizeof(*bfd->main->blen_thumb)) == + (BLEN_THUMB_MEMSIZE_FILE(data[0], data[1]) - (sizeof(*data) * 2))); + bfd->main->blen_thumb->width = data[0]; + bfd->main->blen_thumb->height = data[1]; + memcpy(bfd->main->blen_thumb->rect, &data[2], sz - sizeof(*bfd->main->blen_thumb)); + } + } + while (bhead) { switch (bhead->code) { case DATA: @@ -8196,26 +8386,10 @@ BlendFileData *blo_read_file_internal(FileData *fd, const char *filepath) bhead = NULL; break; - case ID_LI: - /* skip library datablocks in undo, this works together with - * BLO_read_from_memfile, where the old main->library is restored - * overwriting the libraries from the memory file. previously - * it did not save ID_LI/ID_ID blocks in this case, but they are - * needed to make quit.blend recover them correctly. */ - if (fd->memfile) - bhead = blo_nextbhead(fd, bhead); - else - bhead = read_libblock(fd, bfd->main, bhead, LIB_LOCAL, NULL); - break; case ID_ID: - /* same as above */ - if (fd->memfile) - bhead = blo_nextbhead(fd, bhead); - else - /* always adds to the most recently loaded - * ID_LI block, see direct_link_library. - * this is part of the file format definition. */ - bhead = read_libblock(fd, mainlist.last, bhead, LIB_READ+LIB_EXTERN, NULL); + /* Always adds to the most recently loaded ID_LI block, see direct_link_library. + * This is part of the file format definition. */ + bhead = read_libblock(fd, mainlist.last, bhead, LIB_READ | LIB_EXTERN, NULL); break; /* in 2.50+ files, the file identifier for screens is patched, forward compatibility */ @@ -8228,10 +8402,10 @@ BlendFileData *blo_read_file_internal(FileData *fd, const char *filepath) } /* do before read_libraries, but skip undo case */ - if (fd->memfile==NULL) + if (fd->memfile == NULL) { do_versions(fd, NULL, bfd->main); - - do_versions_userdef(fd, bfd); + do_versions_userdef(fd, bfd); + } read_libraries(fd, &mainlist); @@ -8244,6 +8418,8 @@ BlendFileData *blo_read_file_internal(FileData *fd, const char *filepath) link_global(fd, bfd); /* as last */ + fd->mainlist = NULL; /* Safety, this is local variable, shall not be used afterward. */ + return bfd; } @@ -8367,11 +8543,6 @@ static BHead *find_bhead_from_idname(FileData *fd, const char *idname) #endif } -const char *bhead_id_name(const FileData *fd, const BHead *bhead) -{ - return (const char *)POINTER_OFFSET(bhead, sizeof(*bhead) + fd->id_name_offs); -} - static ID *is_yet_read(FileData *fd, Main *mainvar, BHead *bhead) { const char *idname= bhead_id_name(fd, bhead); @@ -8457,7 +8628,7 @@ static void expand_doit_library(void *fdhandle, Main *mainvar, void *old) } } -static void (*expand_doit)(void *, Main *, void *); +static BLOExpandDoitCallback expand_doit; // XXX deprecated - old animation system static void expand_ipo(FileData *fd, Main *mainvar, Ipo *ipo) @@ -8894,8 +9065,8 @@ static void expand_armature(FileData *fd, Main *mainvar, bArmature *arm) #endif } -static void expand_object_expandModifiers(void *userData, Object *UNUSED(ob), - ID **idpoin) +static void expand_object_expandModifiers( + void *userData, Object *UNUSED(ob), ID **idpoin, int UNUSED(cd_flag)) { struct { FileData *fd; Main *mainvar; } *data= userData; @@ -9232,11 +9403,23 @@ static void expand_gpencil(FileData *fd, Main *mainvar, bGPdata *gpd) expand_animdata(fd, mainvar, gpd->adt); } -void BLO_main_expander(void (*expand_doit_func)(void *, Main *, void *)) +/** + * Set the callback func used over all ID data found by \a BLO_expand_main func. + * + * \param expand_doit_func Called for each ID block it finds. + */ +void BLO_main_expander(BLOExpandDoitCallback expand_doit_func) { expand_doit = expand_doit_func; } +/** + * Loop over all ID data in Main to mark relations. + * Set (id->flag & LIB_NEED_EXPAND) to mark expanding. Flags get cleared after expanding. + * + * \param fdhandle usually filedata, or own handle. + * \param mainvar the Main database to expand. + */ void BLO_expand_main(void *fdhandle, Main *mainvar) { ListBase *lbarray[MAX_LIBARRAY]; @@ -9348,101 +9531,86 @@ static bool object_in_any_scene(Main *mainvar, Object *ob) { Scene *sce; - for (sce= mainvar->scene.first; sce; sce= sce->id.next) { - if (BKE_scene_base_find(sce, ob)) - return 1; + for (sce = mainvar->scene.first; sce; sce = sce->id.next) { + if (BKE_scene_base_find(sce, ob)) { + return true; + } } - return 0; + return false; } -static void give_base_to_objects(Main *mainvar, Scene *sce, Library *lib, const short idcode, const bool is_link, const short active_lay) +static void give_base_to_objects(Main *mainvar, Scene *scene, View3D *v3d, Library *lib, const short flag) { Object *ob; Base *base; - const bool is_group_append = (is_link == false && idcode == ID_GR); + const unsigned int active_lay = (flag & FILE_ACTIVELAY) ? BKE_screen_view3d_layer_active(v3d, scene) : 0; + const bool is_link = (flag & FILE_LINK) != 0; + + BLI_assert(scene); /* give all objects which are LIB_INDIRECT a base, or for a group when *lib has been set */ for (ob = mainvar->object.first; ob; ob = ob->id.next) { - if (ob->id.flag & LIB_INDIRECT) { - /* IF below is quite confusing! - * if we are appending, but this object wasnt just added along with a group, - * then this is already used indirectly in the scene somewhere else and we didnt just append it. - * - * (ob->id.flag & LIB_PRE_EXISTING)==0 means that this is a newly appended object - Campbell */ - if (is_group_append==0 || (ob->id.flag & LIB_PRE_EXISTING)==0) { - bool do_it = false; - - if (ob->id.us == 0) { - do_it = true; - } - else if (idcode==ID_GR) { - if ((is_link == false) && (ob->id.lib == lib)) { - if ((ob->flag & OB_FROMGROUP) && object_in_any_scene(mainvar, ob)==0) { - do_it = true; - } - } - } - else { - /* when appending, make sure any indirectly loaded objects - * get a base else they cant be accessed at all [#27437] */ - if ((is_link == false) && (ob->id.lib == lib)) { - /* we may be appending from a scene where we already - * have a linked object which is not in any scene [#27616] */ - if ((ob->id.flag & LIB_PRE_EXISTING)==0) { - if (object_in_any_scene(mainvar, ob)==0) { - do_it = true; - } - } - } - } - - if (do_it) { - base = MEM_callocN(sizeof(Base), "add_ext_base"); - BLI_addtail(&sce->base, base); - - if (active_lay) ob->lay = sce->lay; - - base->lay = ob->lay; - base->object = ob; - base->flag = ob->flag; + if ((ob->id.flag & LIB_INDIRECT) && (ob->id.flag & LIB_PRE_EXISTING) == 0) { + bool do_it = false; - CLAMP_MIN(ob->id.us, 0); - ob->id.us += 1; - - ob->id.flag -= LIB_INDIRECT; - ob->id.flag |= LIB_EXTERN; + if (ob->id.us == 0) { + do_it = true; + } + else if (!is_link && (ob->id.lib == lib) && (object_in_any_scene(mainvar, ob) == 0)) { + /* When appending, make sure any indirectly loaded objects get a base, else they cant be accessed at all + * (see T27437). */ + do_it = true; + } + + if (do_it) { + base = MEM_callocN(sizeof(Base), __func__); + BLI_addtail(&scene->base, base); + + if (active_lay) { + ob->lay = active_lay; } + + base->lay = ob->lay; + base->object = ob; + base->flag = ob->flag; + + CLAMP_MIN(ob->id.us, 0); + ob->id.us += 1; + + ob->id.flag &= ~LIB_INDIRECT; + ob->id.flag |= LIB_EXTERN; } } } } -static void give_base_to_groups(Main *mainvar, Scene *scene) +static void give_base_to_groups( + Main *mainvar, Scene *scene, View3D *v3d, Library *UNUSED(lib), const short UNUSED(flag)) { Group *group; - + Base *base; + Object *ob; + const unsigned int active_lay = BKE_screen_view3d_layer_active(v3d, scene); + /* give all objects which are tagged a base */ for (group = mainvar->group.first; group; group = group->id.next) { if (group->id.flag & LIB_DOIT) { - Base *base; - Object *ob; - /* any indirect group should not have been tagged */ - BLI_assert((group->id.flag & LIB_INDIRECT)==0); - + BLI_assert((group->id.flag & LIB_INDIRECT) == 0); + /* BKE_object_add(...) messes with the selection */ ob = BKE_object_add_only_object(mainvar, OB_EMPTY, group->id.name + 2); ob->type = OB_EMPTY; - ob->lay = scene->lay; - + ob->lay = active_lay; + /* assign the base */ base = BKE_scene_base_add(scene, ob); base->flag |= SELECT; - base->object->flag= base->flag; + base->object->flag = base->flag; DAG_id_tag_update(&ob->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME); scene->basact = base; - + /* assign the group */ ob->dup_group = group; ob->transflag |= OB_DUPLIGROUP; @@ -9451,11 +9619,30 @@ static void give_base_to_groups(Main *mainvar, Scene *scene) } } +static ID *create_placeholder(Main *mainvar, const char *idname, const short flag) +{ + const short idcode = GS(idname); + ListBase *lb = which_libbase(mainvar, idcode); + ID *ph_id = BKE_libblock_alloc_notest(idcode); + + memcpy(ph_id->name, idname, sizeof(ph_id->name)); + BKE_libblock_init_empty(ph_id); + ph_id->lib = mainvar->curlib; + ph_id->flag = flag | LIB_MISSING; + ph_id->us = (flag & LIB_FAKEUSER) ? 1 : 0; + ph_id->icon_id = 0; + + BLI_addtail(lb, ph_id); + id_sort_by_name(lb, ph_id); + + return ph_id; +} + /* returns true if the item was found * but it may already have already been appended/linked */ -static ID *append_named_part(Main *mainl, FileData *fd, const char *idname, const short idcode) +static ID *link_named_part(Main *mainl, FileData *fd, const short idcode, const char *name) { - BHead *bhead = find_bhead_from_code_name(fd, idcode, idname); + BHead *bhead = find_bhead_from_code_name(fd, idcode, name); ID *id; if (bhead) { @@ -9491,8 +9678,10 @@ static ID *append_named_part(Main *mainl, FileData *fd, const char *idname, cons return id; } -/* simple reader for copy/paste buffers */ -void BLO_library_append_all(Main *mainl, BlendHandle *bh) +/** + * Simple reader for copy/paste buffers. + */ +void BLO_library_link_all(Main *mainl, BlendHandle *bh) { FileData *fd = (FileData *)(bh); BHead *bhead; @@ -9512,33 +9701,33 @@ void BLO_library_append_all(Main *mainl, BlendHandle *bh) } } - -static ID *append_named_part_ex(const bContext *C, Main *mainl, FileData *fd, const char *idname, const int idcode, const int flag) +static ID *link_named_part_ex( + Main *mainl, FileData *fd, const short idcode, const char *name, const short flag, + Scene *scene, View3D *v3d) { - ID *id= append_named_part(mainl, fd, idname, idcode); + ID *id = link_named_part(mainl, fd, idcode, name); if (id && (GS(id->name) == ID_OB)) { /* loose object: give a base */ - Scene *scene = CTX_data_scene(C); /* can be NULL */ if (scene) { Base *base; Object *ob; - - base= MEM_callocN(sizeof(Base), "app_nam_part"); + + base = MEM_callocN(sizeof(Base), "app_nam_part"); BLI_addtail(&scene->base, base); - + ob = (Object *)id; - + /* link at active layer (view3d if available in context, else scene one */ - if ((flag & FILE_ACTIVELAY)) { - View3D *v3d = CTX_wm_view3d(C); + if (flag & FILE_ACTIVELAY) { ob->lay = BKE_screen_view3d_layer_active(v3d, scene); } - + ob->mode = OB_MODE_OBJECT; base->lay = ob->lay; base->object = ob; + base->flag = ob->flag; ob->id.us++; - + if (flag & FILE_AUTOSELECT) { base->flag |= SELECT; base->object->flag = base->flag; @@ -9547,47 +9736,91 @@ static ID *append_named_part_ex(const bContext *C, Main *mainl, FileData *fd, co } } else if (id && (GS(id->name) == ID_GR)) { - /* tag as needing to be instanced */ + /* tag as needing to be instantiated */ if (flag & FILE_GROUP_INSTANCE) id->flag |= LIB_DOIT; } - + return id; } -ID *BLO_library_append_named_part(Main *mainl, BlendHandle **bh, const char *idname, const int idcode) +/** + * Link a named datablock from an external blend file. + * + * \param mainl The main database to link from (not the active one). + * \param bh The blender file handle. + * \param idcode The kind of datablock to link. + * \param name The name of the datablock (without the 2 char ID prefix). + * \return the linked ID when found. + */ +ID *BLO_library_link_named_part(Main *mainl, BlendHandle **bh, const short idcode, const char *name) { FileData *fd = (FileData*)(*bh); - return append_named_part(mainl, fd, idname, idcode); + return link_named_part(mainl, fd, idcode, name); } -ID *BLO_library_append_named_part_ex(const bContext *C, Main *mainl, BlendHandle **bh, const char *idname, const int idcode, const short flag) +/** + * Link a named datablock from an external blend file. + * Optionally instantiate the object/group in the scene when the flags are set. + * + * \param mainl The main database to link from (not the active one). + * \param bh The blender file handle. + * \param idcode The kind of datablock to link. + * \param name The name of the datablock (without the 2 char ID prefix). + * \param flag Options for linking, used for instantiating. + * \param scene The scene in which to instantiate objects/groups (if NULL, no instantiation is done). + * \param v3d The active View3D (only to define active layers for instantiated objects & groups, can be NULL). + * \return the linked ID when found. + */ +ID *BLO_library_link_named_part_ex( + Main *mainl, BlendHandle **bh, + const short idcode, const char *name, const short flag, + Scene *scene, View3D *v3d) { FileData *fd = (FileData*)(*bh); - return append_named_part_ex(C, mainl, fd, idname, idcode, flag); + return link_named_part_ex(mainl, fd, idcode, name, flag, scene, v3d); } -static void append_id_part(FileData *fd, Main *mainvar, ID *id, ID **r_id) +static void link_id_part(ReportList *reports, FileData *fd, Main *mainvar, ID *id, ID **r_id) { - BHead *bhead = find_bhead_from_idname(fd, id->name); + BHead *bhead = NULL; + + if (fd) { + bhead = find_bhead_from_idname(fd, id->name); + } + + id->flag &= ~LIB_READ; if (bhead) { - id->flag &= ~LIB_READ; id->flag |= LIB_NEED_EXPAND; // printf("read lib block %s\n", id->name); read_libblock(fd, mainvar, bhead, id->flag, r_id); } + else { + blo_reportf_wrap( + reports, RPT_WARNING, + TIP_("LIB ERROR: %s: '%s' missing from '%s', parent '%s'"), + BKE_idcode_to_name(GS(id->name)), + id->name + 2, + mainvar->curlib->filepath, + library_parent_filepath(mainvar->curlib)); + + /* Generate a placeholder for this ID (simplified version of read_libblock actually...). */ + if (r_id) { + *r_id = create_placeholder(mainvar, id->name, id->flag); + } + } } /* common routine to append/link something from a library */ -static Main *library_append_begin(Main *mainvar, FileData **fd, const char *filepath) +static Main *library_link_begin(Main *mainvar, FileData **fd, const char *filepath) { Main *mainl; (*fd)->mainlist = MEM_callocN(sizeof(ListBase), "FileData.mainlist"); - /* clear for group instancing tag */ + /* clear for group instantiating tag */ BKE_main_id_tag_listbase(&(mainvar->group), false); /* make mains */ @@ -9606,77 +9839,72 @@ static Main *library_append_begin(Main *mainvar, FileData **fd, const char *file return mainl; } -Main *BLO_library_append_begin(Main *mainvar, BlendHandle **bh, const char *filepath) +/** + * Initialize the BlendHandle for linking library data. + * + * \param mainvar The current main database, e.g. G.main or CTX_data_main(C). + * \param bh A blender file handle as returned by \a BLO_blendhandle_from_file or \a BLO_blendhandle_from_memory. + * \param filepath Used for relative linking, copied to the \a lib->name. + * \return the library Main, to be passed to \a BLO_library_append_named_part as \a mainl. + */ +Main *BLO_library_link_begin(Main *mainvar, BlendHandle **bh, const char *filepath) { FileData *fd = (FileData*)(*bh); - return library_append_begin(mainvar, &fd, filepath); + return library_link_begin(mainvar, &fd, filepath); } - -/* Context == NULL signifies not to do any scene manipulation */ -static void library_append_end(const bContext *C, Main *mainl, FileData **fd, int idcode, short flag) +/* scene and v3d may be NULL. */ +static void library_link_end(Main *mainl, FileData **fd, const short flag, Scene *scene, View3D *v3d) { Main *mainvar; Library *curlib; - + /* expander now is callback function */ BLO_main_expander(expand_doit_library); - + /* make main consistent */ BLO_expand_main(*fd, mainl); - + /* do this when expand found other libs */ read_libraries(*fd, (*fd)->mainlist); - + curlib = mainl->curlib; - + /* make the lib path relative if required */ if (flag & FILE_RELPATH) { /* use the full path, this could have been read by other library even */ BLI_strncpy(curlib->name, curlib->filepath, sizeof(curlib->name)); - + /* uses current .blend file as reference */ BLI_path_rel(curlib->name, G.main->name); } - + blo_join_main((*fd)->mainlist); mainvar = (*fd)->mainlist->first; MEM_freeN((*fd)->mainlist); mainl = NULL; /* blo_join_main free's mainl, cant use anymore */ - + lib_link_all(*fd, mainvar); lib_verify_nodetree(mainvar, false); fix_relpaths_library(G.main->name, mainvar); /* make all relative paths, relative to the open blend file */ - - if (C) { - Scene *scene = CTX_data_scene(C); - - /* give a base to loose objects. If group append, do it for objects too */ - if (scene) { - const bool is_link = (flag & FILE_LINK) != 0; - if (idcode == ID_SCE) { - /* don't instance anything when linking in scenes, assume the scene its self instances the data */ - } - else { - give_base_to_objects(mainvar, scene, curlib, idcode, is_link, flag & FILE_ACTIVELAY); - - if (flag & FILE_GROUP_INSTANCE) { - give_base_to_groups(mainvar, scene); - } - } - } - else { - printf("library_append_end, scene is NULL (objects wont get bases)\n"); + + /* Give a base to loose objects. If group append, do it for objects too. + * Only directly linked objects & groups are instantiated by `BLO_library_link_named_part_ex()` & co, + * here we handle indirect ones and other possible edge-cases. */ + if (scene) { + give_base_to_objects(mainvar, scene, v3d, curlib, flag); + + if (flag & FILE_GROUP_INSTANCE) { + give_base_to_groups(mainvar, scene, v3d, curlib, flag); } } + else { + /* printf("library_append_end, scene is NULL (objects wont get bases)\n"); */ + } - /* clear group instancing tag */ + /* clear group instantiating tag */ BKE_main_id_tag_listbase(&(mainvar->group), false); - - /* has been removed... erm, why? s..ton) */ - /* 20040907: looks like they are give base already in append_named_part(); -Nathan L */ - /* 20041208: put back. It only linked direct, not indirect objects (ton) */ - + /* patch to prevent switch_endian happens twice */ if ((*fd)->flags & FD_FLAGS_SWITCH_ENDIAN) { blo_freefiledata(*fd); @@ -9684,10 +9912,21 @@ static void library_append_end(const bContext *C, Main *mainl, FileData **fd, in } } -void BLO_library_append_end(const bContext *C, struct Main *mainl, BlendHandle **bh, int idcode, short flag) +/** + * Finalize linking from a given .blend file (library). + * Optionally instance the indirect object/group in the scene when the flags are set. + * \note Do not use \a bh after calling this function, it may frees it. + * + * \param mainl The main database to link from (not the active one). + * \param bh The blender file handle (WARNING! may be freed by this function!). + * \param flag Options for linking, used for instantiating. + * \param scene The scene in which to instantiate objects/groups (if NULL, no instantiation is done). + * \param v3d The active View3D (only to define active layers for instantiated objects & groups, can be NULL). + */ +void BLO_library_link_end(Main *mainl, BlendHandle **bh, short flag, Scene *scene, View3D *v3d) { FileData *fd = (FileData*)(*bh); - library_append_end(C, mainl, &fd, idcode, flag); + library_link_end(mainl, &fd, flag, scene, v3d); *bh = (BlendHandle*)fd; } @@ -9815,6 +10054,7 @@ static void read_libraries(FileData *basefd, ListBase *mainlist) } else { mainptr->curlib->filedata = NULL; + mainptr->curlib->id.flag |= LIB_MISSING; } if (fd == NULL) { @@ -9824,37 +10064,29 @@ static void read_libraries(FileData *basefd, ListBase *mainlist) } if (fd) { do_it = true; - a = set_listbasepointers(mainptr, lbarray); - while (a--) { - ID *id = lbarray[a]->first; - - while (id) { - ID *idn = id->next; - if (id->flag & LIB_READ) { - ID *realid = NULL; - BLI_remlink(lbarray[a], id); - - append_id_part(fd, mainptr, id, &realid); - if (!realid) { - blo_reportf_wrap( - fd->reports, RPT_WARNING, - TIP_("LIB ERROR: %s: '%s' missing from '%s', parent '%s'"), - BKE_idcode_to_name(GS(id->name)), - id->name + 2, - mainptr->curlib->filepath, - library_parent_filepath(mainptr->curlib)); - } - - change_idid_adr(mainlist, basefd, id, realid); - - MEM_freeN(id); - } - id = idn; + } + a = set_listbasepointers(mainptr, lbarray); + while (a--) { + ID *id = lbarray[a]->first; + + while (id) { + ID *idn = id->next; + if (id->flag & LIB_READ) { + ID *realid = NULL; + BLI_remlink(lbarray[a], id); + + link_id_part(basefd->reports, fd, mainptr, id, &realid); + + BLI_assert(realid != NULL); + + change_idid_adr(mainlist, basefd, id, realid); + + MEM_freeN(id); } + id = idn; } - - BLO_expand_main(fd, mainptr); } + BLO_expand_main(fd, mainptr); } mainptr = mainptr->next; @@ -9862,6 +10094,7 @@ static void read_libraries(FileData *basefd, ListBase *mainlist) } /* test if there are unread libblocks */ + /* XXX This code block is kept for 2.77, until we are sure it never gets reached anymore. Can be removed later. */ for (mainptr = mainl->next; mainptr; mainptr = mainptr->next) { a = set_listbasepointers(mainptr, lbarray); while (a--) { @@ -9870,10 +10103,12 @@ static void read_libraries(FileData *basefd, ListBase *mainlist) for (id = lbarray[a]->first; id; id = idn) { idn = id->next; if (id->flag & LIB_READ) { + BLI_assert(0); BLI_remlink(lbarray[a], id); blo_reportf_wrap( basefd->reports, RPT_WARNING, - TIP_("LIB ERROR: %s: '%s' unread lib block missing from '%s', parent '%s'"), + TIP_("LIB ERROR: %s: '%s' unread lib block missing from '%s', parent '%s' - " + "Please file a bug report if you see this message"), BKE_idcode_to_name(GS(id->name)), id->name + 2, mainptr->curlib->filepath, diff --git a/source/blender/blenloader/intern/readfile.h b/source/blender/blenloader/intern/readfile.h index ed22daef9ec..f6c3b69c414 100644 --- a/source/blender/blenloader/intern/readfile.h +++ b/source/blender/blenloader/intern/readfile.h @@ -96,7 +96,8 @@ typedef struct FileData { struct GHash *bhead_idname_hash; ListBase *mainlist; - + ListBase *old_mainlist; /* Used for undo. */ + /* ick ick, used to return * data through streamglue. */ @@ -139,7 +140,7 @@ void blo_make_sound_pointer_map(FileData *fd, Main *oldmain); void blo_end_sound_pointer_map(FileData *fd, Main *oldmain); void blo_make_packed_pointer_map(FileData *fd, Main *oldmain); void blo_end_packed_pointer_map(FileData *fd, Main *oldmain); -void blo_add_library_pointer_map(ListBase *mainlist, FileData *fd); +void blo_add_library_pointer_map(ListBase *old_mainlist, FileData *fd); void blo_freefiledata(FileData *fd); diff --git a/source/blender/blenloader/intern/versioning_260.c b/source/blender/blenloader/intern/versioning_260.c index 0809fc69ba2..f84427d608f 100644 --- a/source/blender/blenloader/intern/versioning_260.c +++ b/source/blender/blenloader/intern/versioning_260.c @@ -343,7 +343,7 @@ static void do_versions_mesh_mloopcol_swap_2_62_1(Mesh *me) if (layer->type == CD_MLOOPCOL) { mloopcol = (MLoopCol *)layer->data; for (i = 0; i < me->totloop; i++, mloopcol++) { - SWAP(char, mloopcol->r, mloopcol->b); + SWAP(unsigned char, mloopcol->r, mloopcol->b); } } } diff --git a/source/blender/blenloader/intern/versioning_270.c b/source/blender/blenloader/intern/versioning_270.c index c659eaf820b..3bf24d3574f 100644 --- a/source/blender/blenloader/intern/versioning_270.c +++ b/source/blender/blenloader/intern/versioning_270.c @@ -767,7 +767,6 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main) { SpaceImage *sima = (SpaceImage *) sl; sima->iuser.flag |= IMA_SHOW_STEREO; - sima->iuser.passtype = SCE_PASS_COMBINED; break; } } @@ -855,6 +854,20 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main) #undef BRUSH_TORUS } + if (!MAIN_VERSION_ATLEAST(main, 276, 2)) { + if (!DNA_struct_elem_find(fd->filesdna, "bPoseChannel", "float", "custom_scale")) { + Object *ob; + + for (ob = main->object.first; ob; ob = ob->id.next) { + if (ob->pose) { + bPoseChannel *pchan; + for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) { + pchan->custom_scale = 1.0f; + } + } + } + } + } { bScreen *screen; for (screen = main->screen.first; screen; screen = screen->id.next) { diff --git a/source/blender/blenloader/intern/versioning_defaults.c b/source/blender/blenloader/intern/versioning_defaults.c index 17b0f388af4..c32b3ac51cf 100644 --- a/source/blender/blenloader/intern/versioning_defaults.c +++ b/source/blender/blenloader/intern/versioning_defaults.c @@ -160,7 +160,7 @@ void BLO_update_defaults_startup_blend(Main *bmain) br = (Brush *)BKE_libblock_find_name_ex(bmain, ID_BR, "Fill"); if (!br) { - br = BKE_brush_add(bmain, "Fill"); + br = BKE_brush_add(bmain, "Fill", OB_MODE_TEXTURE_PAINT); br->imagepaint_tool = PAINT_TOOL_FILL; br->ob_mode = OB_MODE_TEXTURE_PAINT; } diff --git a/source/blender/blenloader/intern/writefile.c b/source/blender/blenloader/intern/writefile.c index ec18f6a6bdb..eb778048b17 100644 --- a/source/blender/blenloader/intern/writefile.c +++ b/source/blender/blenloader/intern/writefile.c @@ -291,11 +291,10 @@ static void ww_handle_init(eWriteWrapType ww_type, WriteWrap *r_ww) typedef struct { struct SDNA *sdna; - int file; unsigned char *buf; MemFile *compare, *current; - int tot, count, error, memsize; + int tot, count, error; /* Wrap writing, so we can use zlib or * other compression types later, see: G_FILE_COMPRESS @@ -2092,7 +2091,7 @@ static void write_meshes(WriteData *wd, ListBase *idbase) /* now fill in polys to mfaces */ /* XXX This breaks writing desing, by using temp allocated memory, which will likely generate - * doublons in stored 'old' addresses. + * duplicates in stored 'old' addresses. * This is very bad, but do not see easy way to avoid this, aside from generating those data * outside of save process itself. * Maybe we can live with this, though? @@ -3704,10 +3703,11 @@ static void write_global(WriteData *wd, int fileflags, Main *mainvar) * second are an RGBA image (unsigned char) * note, this uses 'TEST' since new types will segfault on file load for older blender versions. */ -static void write_thumb(WriteData *wd, const int *img) +static void write_thumb(WriteData *wd, const BlendThumbnail *thumb) { - if (img) - writedata(wd, TEST, (2 + img[0] * img[1]) * sizeof(int), img); + if (thumb) { + writedata(wd, TEST, BLEN_THUMB_MEMSIZE_FILE(thumb->width, thumb->height), thumb); + } } /* if MemFile * there's filesave to memory */ @@ -3715,7 +3715,7 @@ static int write_file_handle( Main *mainvar, WriteWrap *ww, MemFile *compare, MemFile *current, - int write_user_block, int write_flags, const int *thumb) + int write_user_block, int write_flags, const BlendThumbnail *thumb) { BHead bhead; ListBase mainlist; @@ -3847,7 +3847,8 @@ static bool do_history(const char *name, ReportList *reports) } /* return: success (1) */ -int BLO_write_file(Main *mainvar, const char *filepath, int write_flags, ReportList *reports, const int *thumb) +int BLO_write_file( + Main *mainvar, const char *filepath, int write_flags, ReportList *reports, const BlendThumbnail *thumb) { char tempname[FILE_MAX+1]; int err, write_user_block; diff --git a/source/blender/blentranslation/BLT_translation.h b/source/blender/blentranslation/BLT_translation.h index 6f24f00acfc..efd59c3fa94 100644 --- a/source/blender/blentranslation/BLT_translation.h +++ b/source/blender/blentranslation/BLT_translation.h @@ -106,7 +106,11 @@ const char *BLT_translate_do_new_dataname(const char *msgctxt, const char *msgid /* Default context for operator names/labels. */ #define BLT_I18NCONTEXT_OPERATOR_DEFAULT "Operator" -/* Mark the msgid applies to several elements (needed in some cases, as english adjectives have no plural mark. :( */ +/* Context for events/keymaps (necessary, since those often use one or two letters, + * easy to get collisions with other areas...). */ +#define BLT_I18NCONTEXT_UI_EVENTS "UI_Events_KeyMaps" + +/* Mark the msgid applies to several elements (needed in some cases, as english adjectives have no plural mark :( ). */ #define BLT_I18NCONTEXT_PLURAL "Plural" /* ID-types contexts. */ @@ -160,6 +164,7 @@ typedef struct { BLT_I18NCONTEXTS_ITEM(BLT_I18NCONTEXT_DEFAULT, "default_real"), \ BLT_I18NCONTEXTS_ITEM(BLT_I18NCONTEXT_DEFAULT_BPYRNA, "default"), \ BLT_I18NCONTEXTS_ITEM(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "operator_default"), \ + BLT_I18NCONTEXTS_ITEM(BLT_I18NCONTEXT_UI_EVENTS, "ui_events_keymaps"), \ BLT_I18NCONTEXTS_ITEM(BLT_I18NCONTEXT_PLURAL, "plural"), \ BLT_I18NCONTEXTS_ITEM(BLT_I18NCONTEXT_ID_ACTION, "id_action"), \ BLT_I18NCONTEXTS_ITEM(BLT_I18NCONTEXT_ID_ARMATURE, "id_armature"), \ diff --git a/source/blender/blentranslation/intern/blt_lang.c b/source/blender/blentranslation/intern/blt_lang.c index cd4545275ee..1ad62fa5869 100644 --- a/source/blender/blentranslation/intern/blt_lang.c +++ b/source/blender/blentranslation/intern/blt_lang.c @@ -97,7 +97,7 @@ static void fill_locales(void) BLI_join_dirfile(languages, FILE_MAX, languages_path, "languages"); line = lines = BLI_file_read_as_lines(languages); - /* This whole "parsing" code is a bit weak, in that it expects strictly formated input file... + /* This whole "parsing" code is a bit weak, in that it expects strictly formatted input file... * Should not be a problem, though, as this file is script-generated! */ /* First loop to find highest locale ID */ diff --git a/source/blender/bmesh/bmesh.h b/source/blender/bmesh/bmesh.h index 0595a867ac2..78c814af86e 100644 --- a/source/blender/bmesh/bmesh.h +++ b/source/blender/bmesh/bmesh.h @@ -57,10 +57,14 @@ * * \subsection bm_loop The Loop * + * Loops can be thought of as a *face-corner*, since faces don't reference verts or edges directly. * Each loop connects the face to one of its corner vertices, * and also references an edge which connects this loop's vertex to the next loop's vertex. * - * Loops store several handy pointers: + * Loops allow faces to access their verts and edges, + * while edges and faces store their loops, allowing access in the opposite direction too. + * + * Loop pointers: * * - BMLoop#v - pointer to the vertex associated with this loop. * - BMLoop#e - pointer to the edge associated with this loop, @@ -199,18 +203,6 @@ * * There may be a better place for this section, but adding here for now. * - * \subsection bm_todo_tools Tools - * - * Probably most of these will be bmesh operators. - * - * - make ngons flat. - * - solidify (precise mode), keeps even wall thickness, re-creates outlines of offset faces with plane-plane - * intersections. - * - split vert (we already have in our API, just no tool). - * - flip selected region (invert all faces about the plane defined by the selected region outline) - * - interactive dissolve (like the knife tool but draw over edges to dissolve) - * - * * \subsection bm_todo_optimize Optimizations * * - skip normal calc when its not needed (when calling chain of operators & for modifiers, flag as dirty) @@ -218,11 +210,6 @@ * - ability to call BMO's with option not to create return data (will save some time) * - binary diff UNDO, currently this uses huge amount of ram when all shapes are stored for each undo step for eg. * - use two different iterator types for BMO map/buffer types. - * - * - * \subsection bm_todo_tools_enhance Tool Enhancements - * - * - vert slide UV correction (like we have for edge slide) */ #ifdef __cplusplus diff --git a/source/blender/bmesh/intern/bmesh_core.c b/source/blender/bmesh/intern/bmesh_core.c index 5bb418a5102..e67aa1da340 100644 --- a/source/blender/bmesh/intern/bmesh_core.c +++ b/source/blender/bmesh/intern/bmesh_core.c @@ -2016,7 +2016,7 @@ bool BM_vert_splice_check_double(BMVert *v_a, BMVert *v_b) * * \return Success * - * \warning This does't work for collapsing edges, + * \warning This doesn't work for collapsing edges, * where \a v and \a vtarget are connected by an edge * (assert checks for this case). */ @@ -2395,6 +2395,8 @@ void bmesh_edge_separate( * Disconnects a face from its vertex fan at loop \a l_sep * * \return The newly created BMVert + * + * \note Will be a no-op and return original vertex if only two edges at that vertex. */ BMVert *bmesh_urmv_loop(BMesh *bm, BMLoop *l_sep) { @@ -2406,8 +2408,10 @@ BMVert *bmesh_urmv_loop(BMesh *bm, BMLoop *l_sep) /* peel the face from the edge radials on both sides of the * loop vert, disconnecting the face from its fan */ - bmesh_edge_separate(bm, l_sep->e, l_sep, false); - bmesh_edge_separate(bm, l_sep->prev->e, l_sep->prev, false); + if (!BM_edge_is_boundary(l_sep->e)) + bmesh_edge_separate(bm, l_sep->e, l_sep, false); + if (!BM_edge_is_boundary(l_sep->prev->e)) + bmesh_edge_separate(bm, l_sep->prev->e, l_sep->prev, false); /* do inline, below */ #if 0 diff --git a/source/blender/bmesh/intern/bmesh_marking.c b/source/blender/bmesh/intern/bmesh_marking.c index 17b6d1d99e7..cd3c8325831 100644 --- a/source/blender/bmesh/intern/bmesh_marking.c +++ b/source/blender/bmesh/intern/bmesh_marking.c @@ -102,6 +102,7 @@ static bool bm_vert_is_edge_select_any(const BMVert *v) } #endif +#if 0 static bool bm_edge_is_face_select_any_other(BMLoop *l_first) { const BMLoop *l_iter = l_first; @@ -114,6 +115,7 @@ static bool bm_edge_is_face_select_any_other(BMLoop *l_first) } return false; } +#endif #if 0 static bool bm_edge_is_face_select_any(const BMEdge *e) @@ -498,6 +500,20 @@ void BM_face_select_set(BMesh *bm, BMFace *f, const bool select) BM_elem_flag_disable(f, BM_ELEM_SELECT); bm->totfacesel -= 1; } + /** + * \note This allows a temporarily invalid state - where for eg + * an edge bay be de-selected, but an adjacent face remains selected. + * + * Rely on #BM_mesh_select_mode_flush to correct these cases. + */ +#if 1 + l_iter = l_first = BM_FACE_FIRST_LOOP(f); + do { + BM_vert_select_set(bm, l_iter->v, false); + BM_edge_select_set(bm, l_iter->e, false); + } while ((l_iter = l_iter->next) != l_first); +#else + /* disabled, see T46494 */ /* flush down to edges */ l_iter = l_first = BM_FACE_FIRST_LOOP(f); @@ -515,6 +531,7 @@ void BM_face_select_set(BMesh *bm, BMFace *f, const bool select) BM_vert_select_set(bm, l_iter->v, false); } } while ((l_iter = l_iter->next) != l_first); +#endif } } diff --git a/source/blender/bmesh/intern/bmesh_mesh.c b/source/blender/bmesh/intern/bmesh_mesh.c index 2c4a98b0b7e..9036e882b0b 100644 --- a/source/blender/bmesh/intern/bmesh_mesh.c +++ b/source/blender/bmesh/intern/bmesh_mesh.c @@ -1438,6 +1438,24 @@ int BM_mesh_elem_count(BMesh *bm, const char htype) } /** + * Special case: Python uses custom-data layers to hold PyObject references. + * These have to be kept in-place, else the PyObject's we point to, wont point back to us. + * + * \note ``ele_src`` Is a duplicate, so we don't need to worry about getting in a feedback loop. + * + * \note If there are other customdata layers which need this functionality, it should be generalized. + * However #BM_mesh_remap is currently the only place where this is done. + */ +static void bm_mesh_remap_cd_update( + BMHeader *ele_dst, BMHeader *ele_src, + const int cd_elem_pyptr) +{ + void **pyptr_dst_p = BM_ELEM_CD_GET_VOID_P(((BMElem *)ele_dst), cd_elem_pyptr); + void **pyptr_src_p = BM_ELEM_CD_GET_VOID_P(((BMElem *)ele_src), cd_elem_pyptr); + *pyptr_dst_p = *pyptr_src_p; +} + +/** * Remaps the vertices, edges and/or faces of the bmesh as indicated by vert/edge/face_idx arrays * (xxx_idx[org_index] = new_index). * @@ -1477,6 +1495,7 @@ void BM_mesh_remap( BMVert **verts_pool, *verts_copy, **vep; int i, totvert = bm->totvert; const unsigned int *new_idx; + const int cd_vert_pyptr = CustomData_get_offset(&bm->vdata, CD_BM_ELEM_PYPTR); /* Init the old-to-new vert pointers mapping */ vptr_map = BLI_ghash_ptr_new_ex("BM_mesh_remap vert pointers mapping", bm->totvert); @@ -1498,6 +1517,9 @@ void BM_mesh_remap( *new_vep = *ve; /* printf("mapping vert from %d to %d (%p/%p to %p)\n", i, *new_idx, *vep, verts_pool[i], new_vep);*/ BLI_ghash_insert(vptr_map, *vep, new_vep); + if (cd_vert_pyptr != -1) { + bm_mesh_remap_cd_update(&(*vep)->head, &new_vep->head, cd_vert_pyptr); + } } bm->elem_index_dirty |= BM_VERT; bm->elem_table_dirty |= BM_VERT; @@ -1510,6 +1532,7 @@ void BM_mesh_remap( BMEdge **edges_pool, *edges_copy, **edp; int i, totedge = bm->totedge; const unsigned int *new_idx; + const int cd_edge_pyptr = CustomData_get_offset(&bm->edata, CD_BM_ELEM_PYPTR); /* Init the old-to-new vert pointers mapping */ eptr_map = BLI_ghash_ptr_new_ex("BM_mesh_remap edge pointers mapping", bm->totedge); @@ -1530,6 +1553,9 @@ void BM_mesh_remap( *new_edp = *ed; BLI_ghash_insert(eptr_map, *edp, new_edp); /* printf("mapping edge from %d to %d (%p/%p to %p)\n", i, *new_idx, *edp, edges_pool[i], new_edp);*/ + if (cd_edge_pyptr != -1) { + bm_mesh_remap_cd_update(&(*edp)->head, &new_edp->head, cd_edge_pyptr); + } } bm->elem_index_dirty |= BM_EDGE; bm->elem_table_dirty |= BM_EDGE; @@ -1542,6 +1568,7 @@ void BM_mesh_remap( BMFace **faces_pool, *faces_copy, **fap; int i, totface = bm->totface; const unsigned int *new_idx; + const int cd_poly_pyptr = CustomData_get_offset(&bm->pdata, CD_BM_ELEM_PYPTR); /* Init the old-to-new vert pointers mapping */ fptr_map = BLI_ghash_ptr_new_ex("BM_mesh_remap face pointers mapping", bm->totface); @@ -1561,6 +1588,9 @@ void BM_mesh_remap( BMFace *new_fap = faces_pool[*new_idx]; *new_fap = *fa; BLI_ghash_insert(fptr_map, *fap, new_fap); + if (cd_poly_pyptr != -1) { + bm_mesh_remap_cd_update(&(*fap)->head, &new_fap->head, cd_poly_pyptr); + } } bm->elem_index_dirty |= BM_FACE | BM_LOOP; @@ -1573,8 +1603,11 @@ void BM_mesh_remap( /* Verts' pointers, only edge pointers... */ if (eptr_map) { BM_ITER_MESH (ve, &iter, bm, BM_VERTS_OF_MESH) { -/* printf("Vert e: %p -> %p\n", ve->e, BLI_ghash_lookup(eptr_map, (const void *)ve->e));*/ - ve->e = BLI_ghash_lookup(eptr_map, (const void *)ve->e); +/* printf("Vert e: %p -> %p\n", ve->e, BLI_ghash_lookup(eptr_map, ve->e));*/ + if (ve->e) { + ve->e = BLI_ghash_lookup(eptr_map, ve->e); + BLI_assert(ve->e); + } } } @@ -1583,24 +1616,30 @@ void BM_mesh_remap( if (vptr_map || eptr_map) { BM_ITER_MESH (ed, &iter, bm, BM_EDGES_OF_MESH) { if (vptr_map) { -/* printf("Edge v1: %p -> %p\n", ed->v1, BLI_ghash_lookup(vptr_map, (const void *)ed->v1));*/ -/* printf("Edge v2: %p -> %p\n", ed->v2, BLI_ghash_lookup(vptr_map, (const void *)ed->v2));*/ - ed->v1 = BLI_ghash_lookup(vptr_map, (const void *)ed->v1); - ed->v2 = BLI_ghash_lookup(vptr_map, (const void *)ed->v2); +/* printf("Edge v1: %p -> %p\n", ed->v1, BLI_ghash_lookup(vptr_map, ed->v1));*/ +/* printf("Edge v2: %p -> %p\n", ed->v2, BLI_ghash_lookup(vptr_map, ed->v2));*/ + ed->v1 = BLI_ghash_lookup(vptr_map, ed->v1); + ed->v2 = BLI_ghash_lookup(vptr_map, ed->v2); + BLI_assert(ed->v1); + BLI_assert(ed->v2); } if (eptr_map) { /* printf("Edge v1_disk_link prev: %p -> %p\n", ed->v1_disk_link.prev,*/ -/* BLI_ghash_lookup(eptr_map, (const void *)ed->v1_disk_link.prev));*/ +/* BLI_ghash_lookup(eptr_map, ed->v1_disk_link.prev));*/ /* printf("Edge v1_disk_link next: %p -> %p\n", ed->v1_disk_link.next,*/ -/* BLI_ghash_lookup(eptr_map, (const void *)ed->v1_disk_link.next));*/ +/* BLI_ghash_lookup(eptr_map, ed->v1_disk_link.next));*/ /* printf("Edge v2_disk_link prev: %p -> %p\n", ed->v2_disk_link.prev,*/ -/* BLI_ghash_lookup(eptr_map, (const void *)ed->v2_disk_link.prev));*/ +/* BLI_ghash_lookup(eptr_map, ed->v2_disk_link.prev));*/ /* printf("Edge v2_disk_link next: %p -> %p\n", ed->v2_disk_link.next,*/ -/* BLI_ghash_lookup(eptr_map, (const void *)ed->v2_disk_link.next));*/ - ed->v1_disk_link.prev = BLI_ghash_lookup(eptr_map, (const void *)ed->v1_disk_link.prev); - ed->v1_disk_link.next = BLI_ghash_lookup(eptr_map, (const void *)ed->v1_disk_link.next); - ed->v2_disk_link.prev = BLI_ghash_lookup(eptr_map, (const void *)ed->v2_disk_link.prev); - ed->v2_disk_link.next = BLI_ghash_lookup(eptr_map, (const void *)ed->v2_disk_link.next); +/* BLI_ghash_lookup(eptr_map, ed->v2_disk_link.next));*/ + ed->v1_disk_link.prev = BLI_ghash_lookup(eptr_map, ed->v1_disk_link.prev); + ed->v1_disk_link.next = BLI_ghash_lookup(eptr_map, ed->v1_disk_link.next); + ed->v2_disk_link.prev = BLI_ghash_lookup(eptr_map, ed->v2_disk_link.prev); + ed->v2_disk_link.next = BLI_ghash_lookup(eptr_map, ed->v2_disk_link.next); + BLI_assert(ed->v1_disk_link.prev); + BLI_assert(ed->v1_disk_link.next); + BLI_assert(ed->v2_disk_link.prev); + BLI_assert(ed->v2_disk_link.next); } } } @@ -1609,20 +1648,57 @@ void BM_mesh_remap( BM_ITER_MESH (fa, &iter, bm, BM_FACES_OF_MESH) { BM_ITER_ELEM (lo, &iterl, fa, BM_LOOPS_OF_FACE) { if (vptr_map) { -/* printf("Loop v: %p -> %p\n", lo->v, BLI_ghash_lookup(vptr_map, (const void *)lo->v));*/ - lo->v = BLI_ghash_lookup(vptr_map, (const void *)lo->v); +/* printf("Loop v: %p -> %p\n", lo->v, BLI_ghash_lookup(vptr_map, lo->v));*/ + lo->v = BLI_ghash_lookup(vptr_map, lo->v); + BLI_assert(lo->v); } if (eptr_map) { -/* printf("Loop e: %p -> %p\n", lo->e, BLI_ghash_lookup(eptr_map, (const void *)lo->e));*/ - lo->e = BLI_ghash_lookup(eptr_map, (const void *)lo->e); +/* printf("Loop e: %p -> %p\n", lo->e, BLI_ghash_lookup(eptr_map, lo->e));*/ + lo->e = BLI_ghash_lookup(eptr_map, lo->e); + BLI_assert(lo->e); } if (fptr_map) { -/* printf("Loop f: %p -> %p\n", lo->f, BLI_ghash_lookup(fptr_map, (const void *)lo->f));*/ - lo->f = BLI_ghash_lookup(fptr_map, (const void *)lo->f); +/* printf("Loop f: %p -> %p\n", lo->f, BLI_ghash_lookup(fptr_map, lo->f));*/ + lo->f = BLI_ghash_lookup(fptr_map, lo->f); + BLI_assert(lo->f); } } } + /* Selection history */ + { + BMEditSelection *ese; + for (ese = bm->selected.first; ese; ese = ese->next) { + switch (ese->htype) { + case BM_VERT: + if (vptr_map) { + ese->ele = BLI_ghash_lookup(vptr_map, ese->ele); + BLI_assert(ese->ele); + } + break; + case BM_EDGE: + if (eptr_map) { + ese->ele = BLI_ghash_lookup(eptr_map, ese->ele); + BLI_assert(ese->ele); + } + break; + case BM_FACE: + if (fptr_map) { + ese->ele = BLI_ghash_lookup(fptr_map, ese->ele); + BLI_assert(ese->ele); + } + break; + } + } + } + + if (fptr_map) { + if (bm->act_face) { + bm->act_face = BLI_ghash_lookup(fptr_map, bm->act_face); + BLI_assert(bm->act_face); + } + } + if (vptr_map) BLI_ghash_free(vptr_map, NULL, NULL); if (eptr_map) diff --git a/source/blender/bmesh/intern/bmesh_opdefines.c b/source/blender/bmesh/intern/bmesh_opdefines.c index 3e814948ade..f3496b31255 100644 --- a/source/blender/bmesh/intern/bmesh_opdefines.c +++ b/source/blender/bmesh/intern/bmesh_opdefines.c @@ -262,7 +262,7 @@ static BMOpDefine bmo_bisect_edges_def = { /* slots_in */ {{"edges", BMO_OP_SLOT_ELEMENT_BUF, {BM_EDGE}}, /* input edges */ {"cuts", BMO_OP_SLOT_INT}, /* number of cuts */ - {"edge_percents", BMO_OP_SLOT_MAPPING, {BMO_OP_SLOT_SUBTYPE_MAP_FLT}}, + {"edge_percents", BMO_OP_SLOT_MAPPING, {(int)BMO_OP_SLOT_SUBTYPE_MAP_FLT}}, {{'\0'}}, }, /* slots_out */ @@ -322,7 +322,7 @@ static BMOpDefine bmo_find_doubles_def = { {{'\0'}}, }, /* slots_out */ - {{"targetmap.out", BMO_OP_SLOT_MAPPING, {BMO_OP_SLOT_SUBTYPE_MAP_ELEM}}, + {{"targetmap.out", BMO_OP_SLOT_MAPPING, {(int)BMO_OP_SLOT_SUBTYPE_MAP_ELEM}}, {{'\0'}}, }, bmo_find_doubles_exec, @@ -401,7 +401,7 @@ static BMOpDefine bmo_pointmerge_facedata_def = { "pointmerge_facedata", /* slots_in */ {{"verts", BMO_OP_SLOT_ELEMENT_BUF, {BM_VERT}}, /* input vertices */ - {"vert_snap", BMO_OP_SLOT_ELEMENT_BUF, {BM_VERT | BMO_OP_SLOT_SUBTYPE_ELEM_IS_SINGLE}}, /* snap vertex */ + {"vert_snap", BMO_OP_SLOT_ELEMENT_BUF, {BM_VERT | (int)BMO_OP_SLOT_SUBTYPE_ELEM_IS_SINGLE}}, /* snap vertex */ {{'\0'}}, }, {{{'\0'}}}, /* no output */ @@ -474,7 +474,7 @@ static BMOpDefine bmo_weld_verts_def = { "weld_verts", /* slots_in */ /* maps welded vertices to verts they should weld to */ - {{"targetmap", BMO_OP_SLOT_MAPPING, {BMO_OP_SLOT_SUBTYPE_MAP_ELEM}}, + {{"targetmap", BMO_OP_SLOT_MAPPING, {(int)BMO_OP_SLOT_SUBTYPE_MAP_ELEM}}, {{'\0'}}, }, {{{'\0'}}}, /* no output */ @@ -819,8 +819,8 @@ static BMOpDefine bmo_transform_def = { static BMOpDefine bmo_object_load_bmesh_def = { "object_load_bmesh", /* slots_in */ - {{"scene", BMO_OP_SLOT_PTR, {BMO_OP_SLOT_SUBTYPE_PTR_SCENE}}, - {"object", BMO_OP_SLOT_PTR, {BMO_OP_SLOT_SUBTYPE_PTR_OBJECT}}, + {{"scene", BMO_OP_SLOT_PTR, {(int)BMO_OP_SLOT_SUBTYPE_PTR_SCENE}}, + {"object", BMO_OP_SLOT_PTR, {(int)BMO_OP_SLOT_SUBTYPE_PTR_OBJECT}}, {{'\0'}}, }, {{{'\0'}}}, /* no output */ @@ -839,9 +839,9 @@ static BMOpDefine bmo_bmesh_to_mesh_def = { /* slots_in */ { /* pointer to a mesh structure to fill in */ - {"mesh", BMO_OP_SLOT_PTR, {BMO_OP_SLOT_SUBTYPE_PTR_MESH}}, + {"mesh", BMO_OP_SLOT_PTR, {(int)BMO_OP_SLOT_SUBTYPE_PTR_MESH}}, /* pointer to an object structure */ - {"object", BMO_OP_SLOT_PTR, {BMO_OP_SLOT_SUBTYPE_PTR_OBJECT}}, + {"object", BMO_OP_SLOT_PTR, {(int)BMO_OP_SLOT_SUBTYPE_PTR_OBJECT}}, {"skip_tessface", BMO_OP_SLOT_BOOL}, /* don't calculate mfaces */ {{'\0'}}, }, @@ -861,9 +861,9 @@ static BMOpDefine bmo_mesh_to_bmesh_def = { /* slots_in */ { /* pointer to a Mesh structure */ - {"mesh", BMO_OP_SLOT_PTR, {BMO_OP_SLOT_SUBTYPE_PTR_MESH}}, + {"mesh", BMO_OP_SLOT_PTR, {(int)BMO_OP_SLOT_SUBTYPE_PTR_MESH}}, /* pointer to an Object structure */ - {"object", BMO_OP_SLOT_PTR, {BMO_OP_SLOT_SUBTYPE_PTR_OBJECT}}, + {"object", BMO_OP_SLOT_PTR, {(int)BMO_OP_SLOT_SUBTYPE_PTR_OBJECT}}, {"use_shapekey", BMO_OP_SLOT_BOOL}, /* load active shapekey coordinates into verts */ {{'\0'}}, }, @@ -1035,7 +1035,7 @@ static BMOpDefine bmo_extrude_face_region_def = { "extrude_face_region", /* slots_in */ {{"geom", BMO_OP_SLOT_ELEMENT_BUF, {BM_VERT | BM_EDGE | BM_FACE}}, /* edges and faces */ - {"edges_exclude", BMO_OP_SLOT_MAPPING, {BMO_OP_SLOT_SUBTYPE_MAP_EMPTY}}, + {"edges_exclude", BMO_OP_SLOT_MAPPING, {(int)BMO_OP_SLOT_SUBTYPE_MAP_EMPTY}}, {"use_keep_orig", BMO_OP_SLOT_BOOL}, /* keep original geometry */ {"use_select_history", BMO_OP_SLOT_BOOL}, /* pass to duplicate */ {{'\0'}}, @@ -1170,7 +1170,7 @@ static BMOpDefine bmo_triangulate_def = { /* slots_out */ {{"edges.out", BMO_OP_SLOT_ELEMENT_BUF, {BM_EDGE}}, {"faces.out", BMO_OP_SLOT_ELEMENT_BUF, {BM_FACE}}, - {"face_map.out", BMO_OP_SLOT_MAPPING, {BMO_OP_SLOT_SUBTYPE_MAP_ELEM}}, + {"face_map.out", BMO_OP_SLOT_MAPPING, {(int)BMO_OP_SLOT_SUBTYPE_MAP_ELEM}}, {{'\0'}}, }, bmo_triangulate_exec, @@ -1215,8 +1215,8 @@ static BMOpDefine bmo_subdivide_edges_def = { {"along_normal", BMO_OP_SLOT_FLT}, {"cuts", BMO_OP_SLOT_INT}, {"seed", BMO_OP_SLOT_INT}, - {"custom_patterns", BMO_OP_SLOT_MAPPING, {BMO_OP_SLOT_SUBTYPE_MAP_INTERNAL}}, /* uses custom pointers */ - {"edge_percents", BMO_OP_SLOT_MAPPING, {BMO_OP_SLOT_SUBTYPE_MAP_FLT}}, + {"custom_patterns", BMO_OP_SLOT_MAPPING, {(int)BMO_OP_SLOT_SUBTYPE_MAP_INTERNAL}}, /* uses custom pointers */ + {"edge_percents", BMO_OP_SLOT_MAPPING, {(int)BMO_OP_SLOT_SUBTYPE_MAP_FLT}}, {"quad_corner_type", BMO_OP_SLOT_INT}, /* quad corner type, see bmesh_operators.h */ {"use_grid_fill", BMO_OP_SLOT_BOOL}, /* fill in fully-selected faces with a grid */ @@ -1322,7 +1322,7 @@ static BMOpDefine bmo_duplicate_def = { /* slots_in */ {{"geom", BMO_OP_SLOT_ELEMENT_BUF, {BM_VERT | BM_EDGE | BM_FACE}}, /* destination bmesh, if NULL will use current on */ - {"dest", BMO_OP_SLOT_PTR, {BMO_OP_SLOT_SUBTYPE_PTR_BMESH}}, + {"dest", BMO_OP_SLOT_PTR, {(int)BMO_OP_SLOT_SUBTYPE_PTR_BMESH}}, {"use_select_history", BMO_OP_SLOT_BOOL}, {{'\0'}}, }, @@ -1331,11 +1331,11 @@ static BMOpDefine bmo_duplicate_def = { {"geom.out", BMO_OP_SLOT_ELEMENT_BUF, {BM_VERT | BM_EDGE | BM_FACE}}, /* facemap maps from source faces to dupe * faces, and from dupe faces to source faces */ - {"vert_map.out", BMO_OP_SLOT_MAPPING, {BMO_OP_SLOT_SUBTYPE_MAP_ELEM}}, - {"edge_map.out", BMO_OP_SLOT_MAPPING, {BMO_OP_SLOT_SUBTYPE_MAP_ELEM}}, - {"face_map.out", BMO_OP_SLOT_MAPPING, {BMO_OP_SLOT_SUBTYPE_MAP_ELEM}}, - {"boundary_map.out", BMO_OP_SLOT_MAPPING, {BMO_OP_SLOT_SUBTYPE_MAP_ELEM}}, - {"isovert_map.out", BMO_OP_SLOT_MAPPING, {BMO_OP_SLOT_SUBTYPE_MAP_ELEM}}, + {"vert_map.out", BMO_OP_SLOT_MAPPING, {(int)BMO_OP_SLOT_SUBTYPE_MAP_ELEM}}, + {"edge_map.out", BMO_OP_SLOT_MAPPING, {(int)BMO_OP_SLOT_SUBTYPE_MAP_ELEM}}, + {"face_map.out", BMO_OP_SLOT_MAPPING, {(int)BMO_OP_SLOT_SUBTYPE_MAP_ELEM}}, + {"boundary_map.out", BMO_OP_SLOT_MAPPING, {(int)BMO_OP_SLOT_SUBTYPE_MAP_ELEM}}, + {"isovert_map.out", BMO_OP_SLOT_MAPPING, {(int)BMO_OP_SLOT_SUBTYPE_MAP_ELEM}}, {{'\0'}}, }, bmo_duplicate_exec, @@ -1354,14 +1354,14 @@ static BMOpDefine bmo_split_def = { /* slots_in */ {{"geom", BMO_OP_SLOT_ELEMENT_BUF, {BM_VERT | BM_EDGE | BM_FACE}}, /* destination bmesh, if NULL will use current one */ - {"dest", BMO_OP_SLOT_PTR, {BMO_OP_SLOT_SUBTYPE_PTR_BMESH}}, + {"dest", BMO_OP_SLOT_PTR, {(int)BMO_OP_SLOT_SUBTYPE_PTR_BMESH}}, {"use_only_faces", BMO_OP_SLOT_BOOL}, /* when enabled. don't duplicate loose verts/edges */ {{'\0'}}, }, /* slots_out */ {{"geom.out", BMO_OP_SLOT_ELEMENT_BUF, {BM_VERT | BM_EDGE | BM_FACE}}, - {"boundary_map.out", BMO_OP_SLOT_MAPPING, {BMO_OP_SLOT_SUBTYPE_MAP_ELEM}}, - {"isovert_map.out", BMO_OP_SLOT_MAPPING, {BMO_OP_SLOT_SUBTYPE_MAP_ELEM}}, + {"boundary_map.out", BMO_OP_SLOT_MAPPING, {(int)BMO_OP_SLOT_SUBTYPE_MAP_ELEM}}, + {"isovert_map.out", BMO_OP_SLOT_MAPPING, {(int)BMO_OP_SLOT_SUBTYPE_MAP_ELEM}}, {{'\0'}}, }, bmo_split_exec, diff --git a/source/blender/bmesh/intern/bmesh_queries.c b/source/blender/bmesh/intern/bmesh_queries.c index 09284ea3549..1a8ea1e3a0d 100644 --- a/source/blender/bmesh/intern/bmesh_queries.c +++ b/source/blender/bmesh/intern/bmesh_queries.c @@ -317,7 +317,7 @@ float BM_loop_point_side_of_loop_test(const BMLoop *l, const float co[3]) * Check if a point is inside the edge defined by a loop * (within the plane defined by the loops edge & face normal). * - * \return signed, squared distablce to the edge plane, less than 0.0 when outside. + * \return signed, squared distance to the edge plane, less than 0.0 when outside. */ float BM_loop_point_side_of_edge_test(const BMLoop *l, const float co[3]) { diff --git a/source/blender/bmesh/operators/bmo_extrude.c b/source/blender/bmesh/operators/bmo_extrude.c index 435b9e60949..3eae98b3c46 100644 --- a/source/blender/bmesh/operators/bmo_extrude.c +++ b/source/blender/bmesh/operators/bmo_extrude.c @@ -137,7 +137,7 @@ void bmo_extrude_discrete_faces_exec(BMesh *bm, BMOperator *op) * This function won't crash if its not but won't work right either. * \a e_b is the new edge. * - * \note The edge this face comes from needs to be from the first and second verts fo the face. + * \note The edge this face comes from needs to be from the first and second verts to the face. * The caller must ensure this else we will copy from the wrong source. */ static void bm_extrude_copy_face_loop_attributes(BMesh *bm, BMFace *f) @@ -728,9 +728,9 @@ static void solidify_add_thickness(BMesh *bm, const float dist) if (BMO_elem_flag_test(bm, f, FACE_MARK)) { /* array for passing verts to angle_poly_v3 */ - float *face_angles = BLI_buffer_resize_data(&face_angles_buf, float, f->len); + float *face_angles = BLI_buffer_reinit_data(&face_angles_buf, float, f->len); /* array for receiving angles from angle_poly_v3 */ - float **verts = BLI_buffer_resize_data(&verts_buf, float *, f->len); + float **verts = BLI_buffer_reinit_data(&verts_buf, float *, f->len); BM_ITER_ELEM_INDEX (l, &loopIter, f, BM_LOOPS_OF_FACE, i) { verts[i] = l->v->co; diff --git a/source/blender/bmesh/operators/bmo_inset.c b/source/blender/bmesh/operators/bmo_inset.c index 6664bf6dc46..118a19d3082 100644 --- a/source/blender/bmesh/operators/bmo_inset.c +++ b/source/blender/bmesh/operators/bmo_inset.c @@ -208,14 +208,11 @@ static void bm_loop_customdata_merge( */ const void *data_src; - CustomData_data_add( + CustomData_data_mix_value( type, BM_ELEM_CD_GET_VOID_P(l_a_inner_inset, offset), - BM_ELEM_CD_GET_VOID_P(l_b_inner_inset, offset)); - CustomData_data_multiply( - type, - BM_ELEM_CD_GET_VOID_P(l_a_inner_inset, offset), - 0.5f); + BM_ELEM_CD_GET_VOID_P(l_b_inner_inset, offset), + CDT_MIX_MIX, 0.5f); CustomData_data_copy_value( type, BM_ELEM_CD_GET_VOID_P(l_a_inner_inset, offset), diff --git a/source/blender/bmesh/operators/bmo_planar_faces.c b/source/blender/bmesh/operators/bmo_planar_faces.c index 4e3ac58a813..2856d3d18a6 100644 --- a/source/blender/bmesh/operators/bmo_planar_faces.c +++ b/source/blender/bmesh/operators/bmo_planar_faces.c @@ -21,7 +21,7 @@ /** \file blender/bmesh/operators/bmo_planar_faces.c * \ingroup bmesh * - * Iternatively flatten 4+ sided faces. + * Iteratively flatten 4+ sided faces. */ #include "MEM_guardedalloc.h" @@ -117,7 +117,7 @@ void bmo_planar_faces_exec(BMesh *bm, BMOperator *op) } va = *va_p; - closest_to_plane_v3(co, plane, l_iter->v->co); + closest_to_plane_normalized_v3(co, plane, l_iter->v->co); va->co_tot += 1; interp_v3_v3v3(va->co, va->co, co, 1.0f / (float)va->co_tot); diff --git a/source/blender/bmesh/operators/bmo_subdivide.c b/source/blender/bmesh/operators/bmo_subdivide.c index 45e3c8d193d..38fa2cfdcc8 100644 --- a/source/blender/bmesh/operators/bmo_subdivide.c +++ b/source/blender/bmesh/operators/bmo_subdivide.c @@ -163,6 +163,85 @@ static BMEdge *connect_smallest_face(BMesh *bm, BMVert *v_a, BMVert *v_b, BMFace return NULL; } + +/** + * Specialized slerp that uses a sphere defined by each points normal. + */ +static void interp_slerp_co_no_v3( + const float co_a[3], const float no_a[3], + const float co_b[3], const float no_b[3], + const float no_dir[3], /* caller already knows, avoid normalize */ + float fac, + float r_co[3]) +{ + /* center of the sphere defined by both normals */ + float center[3]; + + BLI_assert(len_squared_v3v3(no_a, no_b) != 0); + + /* calculate sphere 'center' */ + { + /* use point on plane to */ + float plane_a[4], plane_b[4], plane_c[4]; + float no_mid[3], no_ortho[3]; + /* pass this as an arg instead */ +#if 0 + float no_dir[3]; +#endif + + float v_a_no_ortho[3], v_b_no_ortho[3]; + + add_v3_v3v3(no_mid, no_a, no_b); + normalize_v3(no_mid); + +#if 0 + sub_v3_v3v3(no_dir, co_a, co_b); + normalize_v3(no_dir); +#endif + + /* axis of slerp */ + cross_v3_v3v3(no_ortho, no_mid, no_dir); + normalize_v3(no_ortho); + + /* create planes */ + cross_v3_v3v3(v_a_no_ortho, no_ortho, no_a); + cross_v3_v3v3(v_b_no_ortho, no_ortho, no_b); + project_v3_plane(v_a_no_ortho, no_ortho, v_a_no_ortho); + project_v3_plane(v_b_no_ortho, no_ortho, v_b_no_ortho); + + plane_from_point_normal_v3(plane_a, co_a, v_a_no_ortho); + plane_from_point_normal_v3(plane_b, co_b, v_b_no_ortho); + plane_from_point_normal_v3(plane_c, co_b, no_ortho); + + /* find the sphere center from 3 planes */ + if (isect_plane_plane_plane_v3(plane_a, plane_b, plane_c, center)) { + /* pass */ + } + else { + mid_v3_v3v3(center, co_a, co_b); + } + } + + /* calculate the final output 'r_co' */ + { + float ofs_a[3], ofs_b[3], ofs_slerp[3]; + float dist_a, dist_b; + + sub_v3_v3v3(ofs_a, co_a, center); + sub_v3_v3v3(ofs_b, co_b, center); + + dist_a = normalize_v3(ofs_a); + dist_b = normalize_v3(ofs_b); + + if (interp_v3_v3v3_slerp(ofs_slerp, ofs_a, ofs_b, fac)) { + madd_v3_v3v3fl(r_co, center, ofs_slerp, interpf(dist_b, dist_a, fac)); + } + else { + interp_v3_v3v3(r_co, co_a, co_b, fac); + } + } +} + /* calculates offset for co, based on fractal, sphere or smooth settings */ static void alter_co( BMVert *v, BMEdge *UNUSED(e_orig), @@ -179,32 +258,72 @@ static void alter_co( mul_v3_fl(co, params->smooth); } else if (params->use_smooth) { - /* we calculate an offset vector vec1[], to be added to *co */ - float dir[3], tvec[3]; - float fac, len, val; + /* calculating twice and blending gives smoother results, + * removing visible seams. */ +#define USE_SPHERE_DUAL_BLEND - sub_v3_v3v3(dir, v_a->co, v_b->co); - len = (float)M_SQRT1_2 * normalize_v3(dir); + const float eps_unit_vec = 1e-5f; + float smooth; + float no_dir[3]; - /* cosine angle */ - fac = dot_v3v3(dir, v_a->no); - mul_v3_v3fl(tvec, v_a->no, fac); +#ifdef USE_SPHERE_DUAL_BLEND + float no_reflect[3], co_a[3], co_b[3]; +#endif - /* cosine angle */ - fac = -dot_v3v3(dir, v_b->no); - madd_v3_v3fl(tvec, v_b->no, fac); + sub_v3_v3v3(no_dir, v_a->co, v_b->co); + normalize_v3(no_dir); - /* falloff for multi subdivide */ - val = fabsf(1.0f - 2.0f * fabsf(0.5f - perc)); - val = bmesh_subd_falloff_calc(params->smooth_falloff, val); +#ifndef USE_SPHERE_DUAL_BLEND + if (len_squared_v3v3(v_a->no, v_b->no) < eps_unit_vec) { + interp_v3_v3v3(co, v_a->co, v_b->co, perc); + } + else { + interp_slerp_co_no_v3(v_a->co, v_a->no, v_b->co, v_b->no, no_dir, perc, co); + } +#else + /* sphere-a */ + reflect_v3_v3v3(no_reflect, v_a->no, no_dir); + if (len_squared_v3v3(v_a->no, no_reflect) < eps_unit_vec) { + interp_v3_v3v3(co_a, v_a->co, v_b->co, perc); + } + else { + interp_slerp_co_no_v3(v_a->co, v_a->no, v_b->co, no_reflect, no_dir, perc, co_a); + } + + /* sphere-b */ + reflect_v3_v3v3(no_reflect, v_b->no, no_dir); + if (len_squared_v3v3(v_b->no, no_reflect) < eps_unit_vec) { + interp_v3_v3v3(co_b, v_a->co, v_b->co, perc); + } + else { + interp_slerp_co_no_v3(v_a->co, no_reflect, v_b->co, v_b->no, no_dir, perc, co_b); + } + + /* blend both spheres */ + interp_v3_v3v3(co, co_a, co_b, perc); +#endif /* USE_SPHERE_DUAL_BLEND */ + + /* apply falloff */ + if (params->smooth_falloff == SUBD_FALLOFF_LIN) { + smooth = 1.0f; + } + else { + smooth = fabsf(1.0f - 2.0f * fabsf(0.5f - perc)); + smooth = 1.0f + bmesh_subd_falloff_calc(params->smooth_falloff, smooth); + } if (params->use_smooth_even) { - val *= shell_v3v3_mid_normalized_to_dist(v_a->no, v_b->no); + smooth *= shell_v3v3_mid_normalized_to_dist(v_a->no, v_b->no); } - mul_v3_fl(tvec, params->smooth * val * len); + smooth *= params->smooth; + if (smooth != 1.0f) { + float co_flat[3]; + interp_v3_v3v3(co_flat, v_a->co, v_b->co, perc); + interp_v3_v3v3(co, co_flat, co, smooth); + } - add_v3_v3(co, tvec); +#undef USE_SPHERE_DUAL_BLEND } if (params->use_fractal) { diff --git a/source/blender/bmesh/tools/bmesh_bevel.c b/source/blender/bmesh/tools/bmesh_bevel.c index e20d4e61d01..5a7788c0b62 100644 --- a/source/blender/bmesh/tools/bmesh_bevel.c +++ b/source/blender/bmesh/tools/bmesh_bevel.c @@ -348,7 +348,7 @@ static EdgeHalf *next_bev(BevVert *bv, EdgeHalf *from_e) /* Return a good representative face (for materials, etc.) for faces * created around/near BoundVert v. * Sometimes care about a second choice, if there is one. - * If r_fother paramenter is non-NULL and there is another, different, + * If r_fother parameter is non-NULL and there is another, different, * possible frep, return the other one in that parameter. */ static BMFace *boundvert_rep_face(BoundVert *v, BMFace **r_fother) { @@ -823,7 +823,7 @@ static void offset_meet(EdgeHalf *e1, EdgeHalf *e2, BMVert *v, BMFace *f, bool e if (!ff) continue; plane_from_point_normal_v3(plane, v->co, ff->no); - closest_to_plane_v3(dropco, plane, meetco); + closest_to_plane_normalized_v3(dropco, plane, meetco); if (point_between_edges(dropco, v, ff, e, e->next)) { copy_v3_v3(meetco, dropco); break; @@ -2947,7 +2947,7 @@ static void bevel_build_rings(BevelParams *bp, BMesh *bm, BevVert *bv) BLI_array_append(ve, v == vm->boundstart ? NULL : frep_e); } else { - BLI_array_append(vf, frep); + BLI_array_append(vf, boundvert_rep_face(v, NULL)); BLI_array_append(ve, NULL); } } while ((v = v->next) != vm->boundstart); @@ -4032,7 +4032,7 @@ static float find_superellipse_chord_u(float u0, float d2goal, float r) * Return the u's in *r_params, which should point to an array of size n+1. */ static void find_even_superellipse_params(int n, float r, float *r_params) { - float d2low, d2high, d2, d2final, u; + float d2low, d2high, d2 = 0.0f, d2final, u; int i, j, n2; const int maxiters = 40; const float d2tol = 1e-6f; diff --git a/source/blender/bmesh/tools/bmesh_intersect.c b/source/blender/bmesh/tools/bmesh_intersect.c index 169ad49195c..19cf2d29aff 100644 --- a/source/blender/bmesh/tools/bmesh_intersect.c +++ b/source/blender/bmesh/tools/bmesh_intersect.c @@ -1000,7 +1000,7 @@ bool BM_mesh_intersect( if (BM_vert_in_edge(e, v_prev)) { v_prev = BM_edge_split(bm, e, v_prev, NULL, CLAMPIS(fac, 0.0f, 1.0f)); - BLI_assert( BM_vert_in_edge(e, v_end)); + BLI_assert(BM_vert_in_edge(e, v_end)); if (!BM_edge_exists(v_prev, vi) && !BM_vert_splice_check_double(v_prev, vi) && @@ -1017,6 +1017,7 @@ bool BM_mesh_intersect( } } } + UNUSED_VARS_NDEBUG(v_end); } } #endif diff --git a/source/blender/collada/AnimationImporter.cpp b/source/blender/collada/AnimationImporter.cpp index e5f7bb2eb89..1bcf51f9d1f 100644 --- a/source/blender/collada/AnimationImporter.cpp +++ b/source/blender/collada/AnimationImporter.cpp @@ -153,15 +153,13 @@ void AnimationImporter::animation_to_fcurves(COLLADAFW::AnimationCurve *curve) calchandles_fcurve(fcu); fcurves.push_back(fcu); + unused_curves.push_back(fcu); } } break; default: fprintf(stderr, "Output dimension of %d is not yet supported (animation id = %s)\n", (int)dim, curve->getOriginalId().c_str()); } - - for (std::vector<FCurve *>::iterator it = fcurves.begin(); it != fcurves.end(); it++) - unused_curves.push_back(*it); } @@ -175,6 +173,11 @@ void AnimationImporter::fcurve_deg_to_rad(FCurve *cu) } } +void AnimationImporter::fcurve_is_used(FCurve *fcu) +{ + unused_curves.erase(std::remove(unused_curves.begin(), unused_curves.end(), fcu), unused_curves.end()); +} + void AnimationImporter::add_fcurves_to_object(Object *ob, std::vector<FCurve *>& curves, char *rna_path, int array_index, Animation *animated) { @@ -225,6 +228,7 @@ void AnimationImporter::add_fcurves_to_object(Object *ob, std::vector<FCurve *>& /* add F-Curve to group */ action_groups_add_channel(act, grp, fcu); + fcurve_is_used(fcu); } #if 0 @@ -235,10 +239,8 @@ void AnimationImporter::add_fcurves_to_object(Object *ob, std::vector<FCurve *>& } else { BLI_addtail(&act->curves, fcu); + fcurve_is_used(fcu); } - - // curve is used, so remove it from unused_curves - unused_curves.erase(std::remove(unused_curves.begin(), unused_curves.end(), fcu), unused_curves.end()); } } @@ -438,7 +440,7 @@ void AnimationImporter::modify_fcurve(std::vector<FCurve *> *curves, const char if (array_index == -1) fcu->array_index = i; else fcu->array_index = array_index; - unused_curves.erase(std::remove(unused_curves.begin(), unused_curves.end(), fcu), unused_curves.end()); + fcurve_is_used(fcu); } } @@ -448,7 +450,7 @@ void AnimationImporter::unused_fcurve(std::vector<FCurve *> *curves) std::vector<FCurve *>::iterator it; for (it = curves->begin(); it != curves->end(); it++) { FCurve *fcu = *it; - unused_curves.erase(std::remove(unused_curves.begin(), unused_curves.end(), fcu), unused_curves.end()); + fcurve_is_used(fcu); } } @@ -621,6 +623,7 @@ void AnimationImporter:: Assign_color_animations(const COLLADAFW::UniqueId& list for (iter = animcurves.begin(); iter != animcurves.end(); iter++) { FCurve *fcu = *iter; BLI_addtail(AnimCurves, fcu); + fcurve_is_used(fcu); } } @@ -660,6 +663,7 @@ void AnimationImporter:: Assign_float_animations(const COLLADAFW::UniqueId& list /** XXX What About animtype "rotation" ? */ BLI_addtail(AnimCurves, fcu); + fcurve_is_used(fcu); } } } @@ -705,6 +709,7 @@ void AnimationImporter::Assign_lens_animations(const COLLADAFW::UniqueId& listid } BLI_addtail(AnimCurves, fcu); + fcurve_is_used(fcu); } } } @@ -840,8 +845,10 @@ void AnimationImporter::apply_matrix_curves(Object *ob, std::vector<FCurve *>& a add_bone_fcurve(ob, node, newcu[i]); else BLI_addtail(curves, newcu[i]); + // fcurve_is_used(newcu[i]); // never added to unused } + if (is_joint) { bPoseChannel *chan = BKE_pose_channel_find_name(ob->pose, bone_name); chan->rotmode = ROT_MODE_QUAT; @@ -891,8 +898,6 @@ void AnimationImporter::translate_Animations(COLLADAFW::Node *node, std::multimap<COLLADAFW::UniqueId, Object *>& object_map, std::map<COLLADAFW::UniqueId, const COLLADAFW::Object *> FW_object_map) { - AnimationImporter::AnimMix *animType = get_animation_type(node, FW_object_map); - bool is_joint = node->getType() == COLLADAFW::Node::JOINT; COLLADAFW::UniqueId uid = node->getUniqueId(); COLLADAFW::Node *root = root_map.find(uid) == root_map.end() ? node : root_map[uid]; @@ -908,6 +913,8 @@ void AnimationImporter::translate_Animations(COLLADAFW::Node *node, return; } + + AnimationImporter::AnimMix *animType = get_animation_type(node, FW_object_map); bAction *act; if ( (animType->transform) != 0) { @@ -966,6 +973,7 @@ void AnimationImporter::translate_Animations(COLLADAFW::Node *node, FCurve *fcu = *iter; BLI_addtail(AnimCurves, fcu); + fcurve_is_used(fcu); } } @@ -1108,6 +1116,8 @@ void AnimationImporter::translate_Animations(COLLADAFW::Node *node, } } } + + delete animType; } void AnimationImporter::add_bone_animation_sampled(Object *ob, std::vector<FCurve *>& animcurves, COLLADAFW::Node *root, COLLADAFW::Node *node, COLLADAFW::Transformation *tm) @@ -1233,6 +1243,7 @@ void AnimationImporter::add_bone_animation_sampled(Object *ob, std::vector<FCurv // add curves for (int i = 0; i < totcu; i++) { add_bone_fcurve(ob, node, newcu[i]); + // fcurve_is_used(newcu[i]); // never added to unused } bPoseChannel *chan = BKE_pose_channel_find_name(ob->pose, bone_name); @@ -1832,7 +1843,7 @@ bool AnimationImporter::evaluate_animation(COLLADAFW::Transformation *tm, float i++; j = 0; } - unused_curves.erase(std::remove(unused_curves.begin(), unused_curves.end(), *it), unused_curves.end()); + fcurve_is_used(*it); } COLLADAFW::Matrix tm(matrix); diff --git a/source/blender/collada/AnimationImporter.h b/source/blender/collada/AnimationImporter.h index 565fe183d02..15dee8ff5f4 100644 --- a/source/blender/collada/AnimationImporter.h +++ b/source/blender/collada/AnimationImporter.h @@ -85,7 +85,10 @@ private: void fcurve_deg_to_rad(FCurve *cu); + void fcurve_is_used(FCurve *fcu); + void add_fcurves_to_object(Object *ob, std::vector<FCurve*>& curves, char *rna_path, int array_index, Animation *animated); + int typeFlag; diff --git a/source/blender/collada/ArmatureImporter.cpp b/source/blender/collada/ArmatureImporter.cpp index 6ddce75ec33..fd08e1ebfab 100644 --- a/source/blender/collada/ArmatureImporter.cpp +++ b/source/blender/collada/ArmatureImporter.cpp @@ -255,9 +255,13 @@ void ArmatureImporter::connect_bone_chains(bArmature *armature, Bone *parentbone { BoneExtended *dominant_child = NULL; int maxlen = 0; - Bone *child = (Bone *)parentbone->childbase.first; - if (child && (import_settings->find_chains || child->next==NULL) ) - { + Bone *child; + + if (parentbone == NULL) + return; + + child = (Bone *)parentbone->childbase.first; + if (child && (import_settings->find_chains || child->next==NULL)) { for (; child; child = child->next) { BoneExtended *be = extended_bones[child->name]; if (be != NULL) { diff --git a/source/blender/collada/DocumentImporter.cpp b/source/blender/collada/DocumentImporter.cpp index 0aff5147060..674a79f0fe7 100644 --- a/source/blender/collada/DocumentImporter.cpp +++ b/source/blender/collada/DocumentImporter.cpp @@ -136,11 +136,14 @@ bool DocumentImporter::import() const std::string encodedFilename = bc_url_encode(mFilename); if (!root.loadDocument(encodedFilename)) { fprintf(stderr, "COLLADAFW::Root::loadDocument() returned false on 1st pass\n"); + delete ehandler; return false; } - if (errorHandler.hasError()) + if (errorHandler.hasError()) { + delete ehandler; return false; + } /** TODO set up scene graph and such here */ @@ -151,10 +154,10 @@ bool DocumentImporter::import() if (!root2.loadDocument(encodedFilename)) { fprintf(stderr, "COLLADAFW::Root::loadDocument() returned false on 2nd pass\n"); + delete ehandler; return false; } - - + delete ehandler; return true; @@ -223,6 +226,7 @@ void DocumentImporter::finish() for (unsigned int i = 0; i < roots.getCount(); i++) { std::vector<Object *> *objects_done = write_node(roots[i], NULL, sce, NULL, false); objects_to_scale->insert(objects_to_scale->end(), objects_done->begin(), objects_done->end()); + delete objects_done; } // update scene @@ -275,6 +279,8 @@ void DocumentImporter::finish() } bc_match_scale(objects_to_scale, unit_converter, !this->import_settings->import_units); + + delete objects_to_scale; } @@ -499,6 +505,9 @@ std::vector<Object *> *DocumentImporter::write_node(COLLADAFW::Node *node, COLLA std::string id = node->getOriginalId(); std::string name = node->getName(); + // if node has child nodes write them + COLLADAFW::NodePointerArray &child_nodes = node->getChildNodes(); + std::vector<Object *> *objects_done = new std::vector<Object *>(); std::vector<Object *> *root_objects = new std::vector<Object *>(); @@ -524,7 +533,7 @@ std::vector<Object *> *DocumentImporter::write_node(COLLADAFW::Node *node, COLLA if (parent_node == NULL) { // for skeletons without root node all has been done above. // Skeletons with root node are handled further down. - return root_objects; + goto finally; } } else { @@ -638,7 +647,9 @@ std::vector<Object *> *DocumentImporter::write_node(COLLADAFW::Node *node, COLLA // XXX: if there're multiple instances, only one is stored - if (!ob) return root_objects; + if (!ob) { + goto finally; + } for (std::vector<Object *>::iterator it = objects_done->begin(); it != objects_done->end(); ++it) { ob = *it; @@ -673,9 +684,6 @@ std::vector<Object *> *DocumentImporter::write_node(COLLADAFW::Node *node, COLLA } } - // if node has child nodes write them - COLLADAFW::NodePointerArray &child_nodes = node->getChildNodes(); - if (objects_done->size() > 0) { ob = *objects_done->begin(); } @@ -684,9 +692,15 @@ std::vector<Object *> *DocumentImporter::write_node(COLLADAFW::Node *node, COLLA } for (unsigned int i = 0; i < child_nodes.getCount(); i++) { - write_node(child_nodes[i], node, sce, ob, is_library_node); + std::vector<Object *> *child_objects; + child_objects = write_node(child_nodes[i], node, sce, ob, is_library_node); + delete child_objects; } + +finally: + delete objects_done; + return root_objects; } @@ -725,7 +739,9 @@ bool DocumentImporter::writeLibraryNodes(const COLLADAFW::LibraryNodes *libraryN const COLLADAFW::NodePointerArray& nodes = libraryNodes->getNodes(); for (unsigned int i = 0; i < nodes.getCount(); i++) { - write_node(nodes[i], NULL, sce, NULL, true); + std::vector<Object *> *child_objects; + child_objects = write_node(nodes[i], NULL, sce, NULL, true); + delete child_objects; } return true; diff --git a/source/blender/compositor/intern/COM_CompositorContext.h b/source/blender/compositor/intern/COM_CompositorContext.h index d7ec653f480..3cc6e9d4ac8 100644 --- a/source/blender/compositor/intern/COM_CompositorContext.h +++ b/source/blender/compositor/intern/COM_CompositorContext.h @@ -24,7 +24,6 @@ #define _COM_CompositorContext_h #include <vector> -#include "BKE_text.h" #include <string> #include "DNA_node_types.h" #include "DNA_color_types.h" diff --git a/source/blender/compositor/intern/COM_ExecutionGroup.cpp b/source/blender/compositor/intern/COM_ExecutionGroup.cpp index 5cb757d7dcb..184c381f42a 100644 --- a/source/blender/compositor/intern/COM_ExecutionGroup.cpp +++ b/source/blender/compositor/intern/COM_ExecutionGroup.cpp @@ -40,7 +40,6 @@ #include "MEM_guardedalloc.h" #include "BLI_math.h" #include "BLI_string.h" -#include "BKE_global.h" #include "PIL_time.h" #include "WM_api.h" #include "WM_types.h" diff --git a/source/blender/compositor/intern/COM_ExecutionSystem.cpp b/source/blender/compositor/intern/COM_ExecutionSystem.cpp index caeaa07d9f9..143528e68b1 100644 --- a/source/blender/compositor/intern/COM_ExecutionSystem.cpp +++ b/source/blender/compositor/intern/COM_ExecutionSystem.cpp @@ -36,8 +36,6 @@ extern "C" { #include "COM_ReadBufferOperation.h" #include "COM_Debug.h" -#include "BKE_global.h" - #ifdef WITH_CXX_GUARDEDALLOC #include "MEM_guardedalloc.h" #endif diff --git a/source/blender/compositor/intern/COM_MemoryBuffer.cpp b/source/blender/compositor/intern/COM_MemoryBuffer.cpp index 2dbf0a6aa46..7ee5e2f7c57 100644 --- a/source/blender/compositor/intern/COM_MemoryBuffer.cpp +++ b/source/blender/compositor/intern/COM_MemoryBuffer.cpp @@ -195,59 +195,30 @@ void MemoryBuffer::addPixel(int x, int y, const float color[4]) } } -typedef struct ReadEWAData { - MemoryBuffer *buffer; - PixelSampler sampler; - float ufac, vfac; -} ReadEWAData; - static void read_ewa_pixel_sampled(void *userdata, int x, int y, float result[4]) { - ReadEWAData *data = (ReadEWAData *) userdata; - switch (data->sampler) { - case COM_PS_NEAREST: - data->buffer->read(result, x, y); - break; - case COM_PS_BILINEAR: - data->buffer->readBilinear(result, - (float)x + data->ufac, - (float)y + data->vfac); - break; - case COM_PS_BICUBIC: - /* TOOD(sergey): no readBicubic method yet */ - data->buffer->readBilinear(result, - (float)x + data->ufac, - (float)y + data->vfac); - break; - default: - zero_v4(result); - break; - } + MemoryBuffer *buffer = (MemoryBuffer *) userdata; + buffer->read(result, x, y); } -void MemoryBuffer::readEWA(float *result, const float uv[2], const float derivatives[2][2], PixelSampler sampler) +void MemoryBuffer::readEWA(float *result, const float uv[2], const float derivatives[2][2]) { BLI_assert(this->m_datatype == COM_DT_COLOR); - ReadEWAData data; - data.buffer = this; - data.sampler = sampler; - data.ufac = uv[0] - floorf(uv[0]); - data.vfac = uv[1] - floorf(uv[1]); - - int width = this->getWidth(), height = this->getHeight(); + float inv_width = 1.0f / (float)this->getWidth(), + inv_height = 1.0f / (float)this->getHeight(); /* TODO(sergey): Render pipeline uses normalized coordinates and derivatives, * but compositor uses pixel space. For now let's just divide the values and * switch compositor to normalized space for EWA later. */ - float uv_normal[2] = {uv[0] / width, uv[1] / height}; - float du_normal[2] = {derivatives[0][0] / width, derivatives[0][1] / height}; - float dv_normal[2] = {derivatives[1][0] / width, derivatives[1][1] / height}; + float uv_normal[2] = {uv[0] * inv_width, uv[1] * inv_height}; + float du_normal[2] = {derivatives[0][0] * inv_width, derivatives[0][1] * inv_height}; + float dv_normal[2] = {derivatives[1][0] * inv_width, derivatives[1][1] * inv_height}; BLI_ewa_filter(this->getWidth(), this->getHeight(), false, true, uv_normal, du_normal, dv_normal, read_ewa_pixel_sampled, - &data, + this, result); } diff --git a/source/blender/compositor/intern/COM_MemoryBuffer.h b/source/blender/compositor/intern/COM_MemoryBuffer.h index 0b5fc21e69e..de8c14e1a66 100644 --- a/source/blender/compositor/intern/COM_MemoryBuffer.h +++ b/source/blender/compositor/intern/COM_MemoryBuffer.h @@ -262,7 +262,7 @@ public: BLI_bilinear_interpolation_fl(this->m_buffer, result, this->m_width, this->m_height, this->m_num_channels, u, v); } - void readEWA(float *result, const float uv[2], const float derivatives[2][2], PixelSampler sampler); + void readEWA(float *result, const float uv[2], const float derivatives[2][2]); /** * @brief is this MemoryBuffer a temporarily buffer (based on an area, not on a chunk) diff --git a/source/blender/compositor/intern/COM_Node.h b/source/blender/compositor/intern/COM_Node.h index 6046af24c55..559ca46ae8b 100644 --- a/source/blender/compositor/intern/COM_Node.h +++ b/source/blender/compositor/intern/COM_Node.h @@ -24,7 +24,6 @@ #define __COM_NODE_H__ #include "DNA_node_types.h" -#include "BKE_text.h" #include <vector> #include <string> #include <algorithm> diff --git a/source/blender/compositor/intern/COM_SocketReader.h b/source/blender/compositor/intern/COM_SocketReader.h index 7ba208ebbf6..ab8a3c06ef5 100644 --- a/source/blender/compositor/intern/COM_SocketReader.h +++ b/source/blender/compositor/intern/COM_SocketReader.h @@ -93,8 +93,7 @@ protected: */ virtual void executePixelFiltered(float /*output*/[4], float /*x*/, float /*y*/, - float /*dx*/[2], float /*dy*/[2], - PixelSampler /*sampler*/) {} + float /*dx*/[2], float /*dy*/[2]) {} public: inline void readSampled(float result[4], float x, float y, PixelSampler sampler) { @@ -103,8 +102,8 @@ public: inline void read(float result[4], int x, int y, void *chunkData) { executePixel(result, x, y, chunkData); } - inline void readFiltered(float result[4], float x, float y, float dx[2], float dy[2], PixelSampler sampler) { - executePixelFiltered(result, x, y, dx, dy, sampler); + inline void readFiltered(float result[4], float x, float y, float dx[2], float dy[2]) { + executePixelFiltered(result, x, y, dx, dy); } virtual void *initializeTileData(rcti * /*rect*/) { return 0; } diff --git a/source/blender/compositor/intern/COM_WorkScheduler.h b/source/blender/compositor/intern/COM_WorkScheduler.h index 71c5f859418..27afdf6efd0 100644 --- a/source/blender/compositor/intern/COM_WorkScheduler.h +++ b/source/blender/compositor/intern/COM_WorkScheduler.h @@ -59,7 +59,7 @@ public: * @brief schedule a chunk of a group to be calculated. * An execution group schedules a chunk in the WorkScheduler * when ExecutionGroup.isOpenCL is set the work will be handled by a OpenCLDevice - * otherwide the work is scheduled for an CPUDevice + * otherwise the work is scheduled for an CPUDevice * @see ExecutionGroup.execute * @param group the execution group * @param chunkNumber the number of the chunk in the group to be executed diff --git a/source/blender/compositor/intern/COM_compositor.cpp b/source/blender/compositor/intern/COM_compositor.cpp index 7f7fc141aca..397540e8e2f 100644 --- a/source/blender/compositor/intern/COM_compositor.cpp +++ b/source/blender/compositor/intern/COM_compositor.cpp @@ -25,9 +25,7 @@ extern "C" { #include "BKE_node.h" #include "BLI_threads.h" } -#include "BKE_main.h" #include "BKE_scene.h" -#include "BKE_global.h" #include "COM_compositor.h" #include "COM_ExecutionSystem.h" diff --git a/source/blender/compositor/nodes/COM_ChannelMatteNode.cpp b/source/blender/compositor/nodes/COM_ChannelMatteNode.cpp index b04f86dea08..cc573274c34 100644 --- a/source/blender/compositor/nodes/COM_ChannelMatteNode.cpp +++ b/source/blender/compositor/nodes/COM_ChannelMatteNode.cpp @@ -33,41 +33,45 @@ ChannelMatteNode::ChannelMatteNode(bNode *editorNode) : Node(editorNode) void ChannelMatteNode::convertToOperations(NodeConverter &converter, const CompositorContext &/*context*/) const { bNode *node = this->getbNode(); - + NodeInput *inputSocketImage = this->getInputSocket(0); NodeOutput *outputSocketImage = this->getOutputSocket(0); NodeOutput *outputSocketMatte = this->getOutputSocket(1); - - NodeOperation *convert = NULL; + + NodeOperation *convert = NULL, *inv_convert = NULL; /* colorspace */ switch (node->custom1) { case CMP_NODE_CHANNEL_MATTE_CS_RGB: break; case CMP_NODE_CHANNEL_MATTE_CS_HSV: /* HSV */ convert = new ConvertRGBToHSVOperation(); + inv_convert = new ConvertHSVToRGBOperation(); break; case CMP_NODE_CHANNEL_MATTE_CS_YUV: /* YUV */ convert = new ConvertRGBToYUVOperation(); + inv_convert = new ConvertYUVToRGBOperation(); break; case CMP_NODE_CHANNEL_MATTE_CS_YCC: /* YCC */ convert = new ConvertRGBToYCCOperation(); ((ConvertRGBToYCCOperation *)convert)->setMode(0); /* BLI_YCC_ITU_BT601 */ + inv_convert = new ConvertYCCToRGBOperation(); + ((ConvertYCCToRGBOperation *)inv_convert)->setMode(0); /* BLI_YCC_ITU_BT601 */ break; default: break; } - + ChannelMatteOperation *operation = new ChannelMatteOperation(); /* pass the ui properties to the operation */ operation->setSettings((NodeChroma *)node->storage, node->custom2); converter.addOperation(operation); - + SetAlphaOperation *operationAlpha = new SetAlphaOperation(); converter.addOperation(operationAlpha); - - if (convert) { + + if (convert != NULL) { converter.addOperation(convert); - + converter.mapInputSocket(inputSocketImage, convert->getInputSocket(0)); converter.addLink(convert->getOutputSocket(), operation->getInputSocket(0)); converter.addLink(convert->getOutputSocket(), operationAlpha->getInputSocket(0)); @@ -76,11 +80,18 @@ void ChannelMatteNode::convertToOperations(NodeConverter &converter, const Compo converter.mapInputSocket(inputSocketImage, operation->getInputSocket(0)); converter.mapInputSocket(inputSocketImage, operationAlpha->getInputSocket(0)); } - + converter.mapOutputSocket(outputSocketMatte, operation->getOutputSocket(0)); - converter.addLink(operation->getOutputSocket(), operationAlpha->getInputSocket(1)); - converter.mapOutputSocket(outputSocketImage, operationAlpha->getOutputSocket()); - - converter.addPreview(operationAlpha->getOutputSocket()); + + if (inv_convert != NULL) { + converter.addOperation(inv_convert); + converter.addLink(operationAlpha->getOutputSocket(0), inv_convert->getInputSocket(0)); + converter.mapOutputSocket(outputSocketImage, inv_convert->getOutputSocket()); + converter.addPreview(inv_convert->getOutputSocket()); + } + else { + converter.mapOutputSocket(outputSocketImage, operationAlpha->getOutputSocket()); + converter.addPreview(operationAlpha->getOutputSocket()); + } } diff --git a/source/blender/compositor/nodes/COM_DistanceMatteNode.cpp b/source/blender/compositor/nodes/COM_DistanceMatteNode.cpp index 5f3feda5de7..99061cf8824 100644 --- a/source/blender/compositor/nodes/COM_DistanceMatteNode.cpp +++ b/source/blender/compositor/nodes/COM_DistanceMatteNode.cpp @@ -66,6 +66,8 @@ void DistanceMatteNode::convertToOperations(NodeConverter &converter, const Comp ConvertRGBToYCCOperation *operationYCCImage = new ConvertRGBToYCCOperation(); ConvertRGBToYCCOperation *operationYCCMatte = new ConvertRGBToYCCOperation(); + operationYCCImage->setMode(0); /* BLI_YCC_ITU_BT601 */ + operationYCCMatte->setMode(0); /* BLI_YCC_ITU_BT601 */ converter.addOperation(operationYCCImage); converter.addOperation(operationYCCMatte); @@ -79,10 +81,20 @@ void DistanceMatteNode::convertToOperations(NodeConverter &converter, const Comp operation = matte; } + converter.mapOutputSocket(outputSocketMatte, operation->getOutputSocket(0)); converter.addLink(operation->getOutputSocket(), operationAlpha->getInputSocket(1)); - converter.mapOutputSocket(outputSocketMatte, operation->getOutputSocket()); - converter.mapOutputSocket(outputSocketImage, operationAlpha->getOutputSocket()); - - converter.addPreview(operationAlpha->getOutputSocket()); + if (storage->channel != 1) { + ConvertYCCToRGBOperation *inv_convert = new ConvertYCCToRGBOperation(); + inv_convert->setMode(0); /* BLI_YCC_ITU_BT601 */ + + converter.addOperation(inv_convert); + converter.addLink(operationAlpha->getOutputSocket(0), inv_convert->getInputSocket(0)); + converter.mapOutputSocket(outputSocketImage, inv_convert->getOutputSocket()); + converter.addPreview(inv_convert->getOutputSocket()); + } + else { + converter.mapOutputSocket(outputSocketImage, operationAlpha->getOutputSocket()); + converter.addPreview(operationAlpha->getOutputSocket()); + } } diff --git a/source/blender/compositor/nodes/COM_ImageNode.cpp b/source/blender/compositor/nodes/COM_ImageNode.cpp index 572e63a2ced..facd422c217 100644 --- a/source/blender/compositor/nodes/COM_ImageNode.cpp +++ b/source/blender/compositor/nodes/COM_ImageNode.cpp @@ -40,19 +40,19 @@ ImageNode::ImageNode(bNode *editorNode) : Node(editorNode) } NodeOperation *ImageNode::doMultilayerCheck(NodeConverter &converter, RenderLayer *rl, Image *image, ImageUser *user, - int framenumber, int outputsocketIndex, int passtype, int view, DataType datatype) const + int framenumber, int outputsocketIndex, int passindex, int view, DataType datatype) const { NodeOutput *outputSocket = this->getOutputSocket(outputsocketIndex); MultilayerBaseOperation *operation = NULL; switch (datatype) { case COM_DT_VALUE: - operation = new MultilayerValueOperation(passtype, view); + operation = new MultilayerValueOperation(passindex, view); break; case COM_DT_VECTOR: - operation = new MultilayerVectorOperation(passtype, view); + operation = new MultilayerVectorOperation(passindex, view); break; case COM_DT_COLOR: - operation = new MultilayerColorOperation(passtype, view); + operation = new MultilayerColorOperation(passindex, view); break; default: break; @@ -124,20 +124,21 @@ void ImageNode::convertToOperations(NodeConverter &converter, const CompositorCo } if (rpass) { + int passindex = BLI_findindex(&rl->passes, rpass); switch (rpass->channels) { case 1: operation = doMultilayerCheck(converter, rl, image, imageuser, framenumber, index, - rpass->passtype, view, COM_DT_VALUE); + passindex, view, COM_DT_VALUE); break; /* using image operations for both 3 and 4 channels (RGB and RGBA respectively) */ /* XXX any way to detect actual vector images? */ case 3: operation = doMultilayerCheck(converter, rl, image, imageuser, framenumber, index, - rpass->passtype, view, COM_DT_VECTOR); + passindex, view, COM_DT_VECTOR); break; case 4: operation = doMultilayerCheck(converter, rl, image, imageuser, framenumber, index, - rpass->passtype, view, COM_DT_COLOR); + passindex, view, COM_DT_COLOR); break; default: /* dummy operation is added below */ diff --git a/source/blender/compositor/operations/COM_CurveBaseOperation.cpp b/source/blender/compositor/operations/COM_CurveBaseOperation.cpp index 408395bfcf0..9bb5ac88343 100644 --- a/source/blender/compositor/operations/COM_CurveBaseOperation.cpp +++ b/source/blender/compositor/operations/COM_CurveBaseOperation.cpp @@ -34,14 +34,25 @@ CurveBaseOperation::CurveBaseOperation() : NodeOperation() { this->m_curveMapping = NULL; } + +CurveBaseOperation::~CurveBaseOperation() +{ + if (this->m_curveMapping) { + curvemapping_free(this->m_curveMapping); + this->m_curveMapping = NULL; + } +} + void CurveBaseOperation::initExecution() { curvemapping_initialize(this->m_curveMapping); } void CurveBaseOperation::deinitExecution() { - curvemapping_free(this->m_curveMapping); - this->m_curveMapping = NULL; + if (this->m_curveMapping) { + curvemapping_free(this->m_curveMapping); + this->m_curveMapping = NULL; + } } void CurveBaseOperation::setCurveMapping(CurveMapping *mapping) diff --git a/source/blender/compositor/operations/COM_CurveBaseOperation.h b/source/blender/compositor/operations/COM_CurveBaseOperation.h index 6bfce26f532..154eb18e387 100644 --- a/source/blender/compositor/operations/COM_CurveBaseOperation.h +++ b/source/blender/compositor/operations/COM_CurveBaseOperation.h @@ -33,6 +33,7 @@ protected: CurveMapping *m_curveMapping; public: CurveBaseOperation(); + ~CurveBaseOperation(); /** * Initialize the execution diff --git a/source/blender/compositor/operations/COM_DisplaceOperation.cpp b/source/blender/compositor/operations/COM_DisplaceOperation.cpp index 6dfef8a0a11..9b3377e887a 100644 --- a/source/blender/compositor/operations/COM_DisplaceOperation.cpp +++ b/source/blender/compositor/operations/COM_DisplaceOperation.cpp @@ -60,7 +60,7 @@ void DisplaceOperation::executePixelSampled(float output[4], float x, float y, P } else { /* EWA filtering (without nearest it gets blurry with NO distortion) */ - this->m_inputColorProgram->readFiltered(output, uv[0], uv[1], deriv[0], deriv[1], COM_PS_BILINEAR); + this->m_inputColorProgram->readFiltered(output, uv[0], uv[1], deriv[0], deriv[1]); } } diff --git a/source/blender/compositor/operations/COM_GaussianBokehBlurOperation.cpp b/source/blender/compositor/operations/COM_GaussianBokehBlurOperation.cpp index 37d59229e50..7c4132238e3 100644 --- a/source/blender/compositor/operations/COM_GaussianBokehBlurOperation.cpp +++ b/source/blender/compositor/operations/COM_GaussianBokehBlurOperation.cpp @@ -273,7 +273,7 @@ void GaussianBlurReferenceOperation::executePixel(float output[4], int x, int y, float *gausstaby, *gausstabcentx; int i, j; float *src; - register float sum, val; + float sum, val; float rval, gval, bval, aval; int imgx = getWidth(); int imgy = getHeight(); diff --git a/source/blender/compositor/operations/COM_IDMaskOperation.cpp b/source/blender/compositor/operations/COM_IDMaskOperation.cpp index a021f07d2a7..68e681c1326 100644 --- a/source/blender/compositor/operations/COM_IDMaskOperation.cpp +++ b/source/blender/compositor/operations/COM_IDMaskOperation.cpp @@ -38,7 +38,9 @@ void IDMaskOperation::executePixelSampled(float output[4], float x, float y, Pix float inputValue[4]; this->m_inputProgram->readSampled(inputValue, x, y, sampler); - const float a = (inputValue[0] == this->m_objectIndex) ? 1.0f : 0.0f; + /* 'round' since sampling may adjust value slightly. + * ID-mask input are originally integers too. */ + const float a = (roundf(inputValue[0]) == this->m_objectIndex) ? 1.0f : 0.0f; output[0] = a; } diff --git a/source/blender/compositor/operations/COM_MapUVOperation.cpp b/source/blender/compositor/operations/COM_MapUVOperation.cpp index ffa48ce3956..d091675286d 100644 --- a/source/blender/compositor/operations/COM_MapUVOperation.cpp +++ b/source/blender/compositor/operations/COM_MapUVOperation.cpp @@ -53,7 +53,7 @@ void MapUVOperation::executePixelSampled(float output[4], float x, float y, Pixe } /* EWA filtering */ - this->m_inputColorProgram->readFiltered(output, uv[0], uv[1], deriv[0], deriv[1], COM_PS_BILINEAR); + this->m_inputColorProgram->readFiltered(output, uv[0], uv[1], deriv[0], deriv[1]); /* UV to alpha threshold */ const float threshold = this->m_alpha * 0.05f; diff --git a/source/blender/compositor/operations/COM_MovieDistortionOperation.h b/source/blender/compositor/operations/COM_MovieDistortionOperation.h index 577712eda56..85f075ab65a 100644 --- a/source/blender/compositor/operations/COM_MovieDistortionOperation.h +++ b/source/blender/compositor/operations/COM_MovieDistortionOperation.h @@ -36,9 +36,9 @@ extern "C" { class DistortionCache { private: - float m_k1; - float m_k2; - float m_k3; + short m_distortion_model; + float m_k1, m_k2, m_k3; + float m_division_k1, m_division_k2; float m_principal_x; float m_principal_y; float m_pixel_aspect; @@ -59,9 +59,12 @@ public: bool inverted, const int margin[2]) { + this->m_distortion_model = movieclip->tracking.camera.distortion_model; this->m_k1 = movieclip->tracking.camera.k1; this->m_k2 = movieclip->tracking.camera.k2; this->m_k3 = movieclip->tracking.camera.k3; + this->m_division_k1 = movieclip->tracking.camera.division_k1; + this->m_division_k2 = movieclip->tracking.camera.division_k2; this->m_principal_x = movieclip->tracking.camera.principal[0]; this->m_principal_y = movieclip->tracking.camera.principal[1]; this->m_pixel_aspect = movieclip->tracking.camera.pixel_aspect; @@ -101,9 +104,12 @@ public: int calibration_width, int claibration_height, bool inverted) { - return this->m_k1 == movieclip->tracking.camera.k1 && + return this->m_distortion_model == movieclip->tracking.camera.distortion_model && + this->m_k1 == movieclip->tracking.camera.k1 && this->m_k2 == movieclip->tracking.camera.k2 && this->m_k3 == movieclip->tracking.camera.k3 && + this->m_division_k1 == movieclip->tracking.camera.division_k1 && + this->m_division_k2 == movieclip->tracking.camera.division_k2 && this->m_principal_x == movieclip->tracking.camera.principal[0] && this->m_principal_y == movieclip->tracking.camera.principal[1] && this->m_pixel_aspect == movieclip->tracking.camera.pixel_aspect && diff --git a/source/blender/compositor/operations/COM_MultilayerImageOperation.cpp b/source/blender/compositor/operations/COM_MultilayerImageOperation.cpp index 00be3b1cdde..b57dd4e32c3 100644 --- a/source/blender/compositor/operations/COM_MultilayerImageOperation.cpp +++ b/source/blender/compositor/operations/COM_MultilayerImageOperation.cpp @@ -27,9 +27,9 @@ extern "C" { # include "IMB_imbuf_types.h" } -MultilayerBaseOperation::MultilayerBaseOperation(int passtype, int view) : BaseImageOperation() +MultilayerBaseOperation::MultilayerBaseOperation(int passindex, int view) : BaseImageOperation() { - this->m_passtype = passtype; + this->m_passId = passindex; this->m_view = view; } @@ -39,7 +39,7 @@ ImBuf *MultilayerBaseOperation::getImBuf() int view = this->m_imageUser->view; this->m_imageUser->view = this->m_view; - this->m_imageUser->passtype = this->m_passtype; + this->m_imageUser->pass = this->m_passId; if (BKE_image_multilayer_index(this->m_image->rr, this->m_imageUser)) { ImBuf *ibuf = BaseImageOperation::getImBuf(); diff --git a/source/blender/compositor/operations/COM_MultilayerImageOperation.h b/source/blender/compositor/operations/COM_MultilayerImageOperation.h index 2e140577d74..46a9319c373 100644 --- a/source/blender/compositor/operations/COM_MultilayerImageOperation.h +++ b/source/blender/compositor/operations/COM_MultilayerImageOperation.h @@ -29,7 +29,7 @@ class MultilayerBaseOperation : public BaseImageOperation { private: - int m_passtype; + int m_passId; int m_view; RenderLayer *m_renderlayer; protected: @@ -38,13 +38,13 @@ public: /** * Constructor */ - MultilayerBaseOperation(int passtype, int view); + MultilayerBaseOperation(int passindex, int view); void setRenderLayer(RenderLayer *renderlayer) { this->m_renderlayer = renderlayer; } }; class MultilayerColorOperation : public MultilayerBaseOperation { public: - MultilayerColorOperation(int passtype, int view) : MultilayerBaseOperation(passtype, view) { + MultilayerColorOperation(int passindex, int view) : MultilayerBaseOperation(passindex, view) { this->addOutputSocket(COM_DT_COLOR); } void executePixelSampled(float output[4], float x, float y, PixelSampler sampler); @@ -52,7 +52,7 @@ public: class MultilayerValueOperation : public MultilayerBaseOperation { public: - MultilayerValueOperation(int passtype, int view) : MultilayerBaseOperation(passtype, view) { + MultilayerValueOperation(int passindex, int view) : MultilayerBaseOperation(passindex, view) { this->addOutputSocket(COM_DT_VALUE); } void executePixelSampled(float output[4], float x, float y, PixelSampler sampler); @@ -60,7 +60,7 @@ public: class MultilayerVectorOperation : public MultilayerBaseOperation { public: - MultilayerVectorOperation(int passtype, int view) : MultilayerBaseOperation(passtype, view) { + MultilayerVectorOperation(int passindex, int view) : MultilayerBaseOperation(passindex, view) { this->addOutputSocket(COM_DT_VECTOR); } void executePixelSampled(float output[4], float x, float y, PixelSampler sampler); diff --git a/source/blender/compositor/operations/COM_PlaneDistortCommonOperation.cpp b/source/blender/compositor/operations/COM_PlaneDistortCommonOperation.cpp index d7d1c9c0c93..1145abd076a 100644 --- a/source/blender/compositor/operations/COM_PlaneDistortCommonOperation.cpp +++ b/source/blender/compositor/operations/COM_PlaneDistortCommonOperation.cpp @@ -108,8 +108,7 @@ void PlaneDistortWarpImageOperation::executePixelSampled(float output[4], float warpCoord(x, y, this->m_samples[0].perspectiveMatrix, uv, deriv); m_pixelReader->readFiltered(output, uv[0], uv[1], - deriv[0], deriv[1], - COM_PS_BILINEAR); + deriv[0], deriv[1]); } else { zero_v4(output); @@ -118,8 +117,7 @@ void PlaneDistortWarpImageOperation::executePixelSampled(float output[4], float warpCoord(x, y, this->m_samples[sample].perspectiveMatrix, uv, deriv); m_pixelReader->readFiltered(color, uv[0], uv[1], - deriv[0], deriv[1], - COM_PS_BILINEAR); + deriv[0], deriv[1]); add_v4_v4(output, color); } mul_v4_fl(output, 1.0f / (float)this->m_motion_blur_samples); diff --git a/source/blender/compositor/operations/COM_ReadBufferOperation.cpp b/source/blender/compositor/operations/COM_ReadBufferOperation.cpp index bf0f24e06be..6dbe132257a 100644 --- a/source/blender/compositor/operations/COM_ReadBufferOperation.cpp +++ b/source/blender/compositor/operations/COM_ReadBufferOperation.cpp @@ -89,7 +89,7 @@ void ReadBufferOperation::executePixelExtend(float output[4], float x, float y, } } -void ReadBufferOperation::executePixelFiltered(float output[4], float x, float y, float dx[2], float dy[2], PixelSampler sampler) +void ReadBufferOperation::executePixelFiltered(float output[4], float x, float y, float dx[2], float dy[2]) { if (m_single_value) { /* write buffer has a single value stored at (0,0) */ @@ -98,7 +98,7 @@ void ReadBufferOperation::executePixelFiltered(float output[4], float x, float y else { const float uv[2] = { x, y }; const float deriv[2][2] = { {dx[0], dx[1]}, {dy[0], dy[1]} }; - m_buffer->readEWA(output, uv, deriv, sampler); + m_buffer->readEWA(output, uv, deriv); } } diff --git a/source/blender/compositor/operations/COM_ReadBufferOperation.h b/source/blender/compositor/operations/COM_ReadBufferOperation.h index 7e5bc55a8ca..cd706ed0b75 100644 --- a/source/blender/compositor/operations/COM_ReadBufferOperation.h +++ b/source/blender/compositor/operations/COM_ReadBufferOperation.h @@ -43,7 +43,7 @@ public: void executePixelSampled(float output[4], float x, float y, PixelSampler sampler); void executePixelExtend(float output[4], float x, float y, PixelSampler sampler, MemoryBufferExtend extend_x, MemoryBufferExtend extend_y); - void executePixelFiltered(float output[4], float x, float y, float dx[2], float dy[2], PixelSampler sampler); + void executePixelFiltered(float output[4], float x, float y, float dx[2], float dy[2]); const bool isReadBufferOperation() const { return true; } void setOffset(unsigned int offset) { this->m_offset = offset; } unsigned int getOffset() const { return this->m_offset; } diff --git a/source/blender/compositor/operations/COM_RenderLayersProg.cpp b/source/blender/compositor/operations/COM_RenderLayersProg.cpp index 1a7e775113b..2a45690a9f2 100644 --- a/source/blender/compositor/operations/COM_RenderLayersProg.cpp +++ b/source/blender/compositor/operations/COM_RenderLayersProg.cpp @@ -150,6 +150,7 @@ void RenderLayersBaseProg::executePixelSampled(float output[4], float x, float y expected_element_size = 4; } else { + expected_element_size = 0; BLI_assert(!"Something horribly wrong just happened"); } BLI_assert(expected_element_size == actual_element_size); diff --git a/source/blender/depsgraph/DEG_depsgraph.h b/source/blender/depsgraph/DEG_depsgraph.h index b91f99ecd20..f37ba71ab65 100644 --- a/source/blender/depsgraph/DEG_depsgraph.h +++ b/source/blender/depsgraph/DEG_depsgraph.h @@ -193,6 +193,8 @@ void DEG_evaluate_on_refresh(struct EvaluationContext *eval_ctx, Depsgraph *graph, struct Scene *scene); +bool DEG_needs_eval(Depsgraph *graph); + /* Editors Integration -------------------------- */ /* Mechanism to allow editors to be informed of depsgraph updates, @@ -203,10 +205,16 @@ typedef void (*DEG_EditorUpdateIDCb)(struct Main *bmain, struct ID *id); typedef void (*DEG_EditorUpdateSceneCb)(struct Main *bmain, struct Scene *scene, int updated); +typedef void (*DEG_EditorUpdateScenePreCb)(struct Main *bmain, + struct Scene *scene, + bool time); /* Set callbacks which are being called when depsgraph changes. */ void DEG_editors_set_update_cb(DEG_EditorUpdateIDCb id_func, - DEG_EditorUpdateSceneCb scene_func); + DEG_EditorUpdateSceneCb scene_func, + DEG_EditorUpdateScenePreCb scene_pre_func); + +void DEG_editors_update_pre(struct Main *bmain, struct Scene *scene, bool time); #ifdef __cplusplus } /* extern "C" */ diff --git a/source/blender/depsgraph/intern/depsgraph.cc b/source/blender/depsgraph/intern/depsgraph.cc index 12b3a36b33e..dedb6e322ba 100644 --- a/source/blender/depsgraph/intern/depsgraph.cc +++ b/source/blender/depsgraph/intern/depsgraph.cc @@ -58,11 +58,12 @@ extern "C" { static DEG_EditorUpdateIDCb deg_editor_update_id_cb = NULL; static DEG_EditorUpdateSceneCb deg_editor_update_scene_cb = NULL; +static DEG_EditorUpdateScenePreCb deg_editor_update_scene_pre_cb = NULL; Depsgraph::Depsgraph() : root_node(NULL), need_update(false), - layers((1 << 20) - 1) + layers(0) { BLI_spin_init(&lock); } @@ -355,11 +356,16 @@ DepsRelation *Depsgraph::add_new_relation(OperationDepsNode *from, DepsRelation *rel = OBJECT_GUARDED_NEW(DepsRelation, from, to, type, description); /* TODO(sergey): Find a better place for this. */ #ifdef WITH_OPENSUBDIV - if (type == DEPSREL_TYPE_GEOMETRY_EVAL) { + ComponentDepsNode *comp_node = from->owner; + if (comp_node->type == DEPSNODE_TYPE_GEOMETRY) { IDDepsNode *id_to = to->owner->owner; - if ((id_to->eval_flags & DAG_EVAL_NEED_CPU) == 0) { - id_to->tag_update(this); - id_to->eval_flags |= DAG_EVAL_NEED_CPU; + IDDepsNode *id_from = from->owner->owner; + Object *object_to = (Object *)id_to->id; + if (id_to != id_from && (object_to->recalc & OB_RECALC_ALL)) { + if ((id_from->eval_flags & DAG_EVAL_NEED_CPU) == 0) { + id_from->tag_update(this); + id_from->eval_flags |= DAG_EVAL_NEED_CPU; + } } } #endif @@ -464,10 +470,19 @@ void DEG_graph_free(Depsgraph *graph) /* Set callbacks which are being called when depsgraph changes. */ void DEG_editors_set_update_cb(DEG_EditorUpdateIDCb id_func, - DEG_EditorUpdateSceneCb scene_func) + DEG_EditorUpdateSceneCb scene_func, + DEG_EditorUpdateScenePreCb scene_pre_func) { deg_editor_update_id_cb = id_func; deg_editor_update_scene_cb = scene_func; + deg_editor_update_scene_pre_cb = scene_pre_func; +} + +void DEG_editors_update_pre(Main *bmain, Scene *scene, bool time) +{ + if (deg_editor_update_scene_pre_cb != NULL) { + deg_editor_update_scene_pre_cb(bmain, scene, time); + } } void deg_editors_id_update(Main *bmain, ID *id) diff --git a/source/blender/depsgraph/intern/depsgraph_build.h b/source/blender/depsgraph/intern/depsgraph_build.h index 4088a3289ef..c5b04ec299c 100644 --- a/source/blender/depsgraph/intern/depsgraph_build.h +++ b/source/blender/depsgraph/intern/depsgraph_build.h @@ -108,7 +108,7 @@ struct DepsgraphNodeBuilder { void build_object_constraints(Scene *scene, Object *ob); void build_pose_constraints(Object *ob, bPoseChannel *pchan); void build_rigidbody(Scene *scene); - void build_particles(Object *ob); + void build_particles(Scene *scene, Object *ob); void build_animdata(ID *id); OperationDepsNode *build_driver(ID *id, FCurve *fcurve); void build_ik_pose(Scene *scene, Object *ob, bPoseChannel *pchan, bConstraint *con); diff --git a/source/blender/depsgraph/intern/depsgraph_build_nodes.cc b/source/blender/depsgraph/intern/depsgraph_build_nodes.cc index 31e32ac3e75..4463df61f91 100644 --- a/source/blender/depsgraph/intern/depsgraph_build_nodes.cc +++ b/source/blender/depsgraph/intern/depsgraph_build_nodes.cc @@ -448,7 +448,7 @@ void DepsgraphNodeBuilder::build_object(Scene *scene, Base *base, Object *ob) /* particle systems */ if (ob->particlesystem.first) { - build_particles(ob); + build_particles(scene, ob); } /* grease pencil */ @@ -676,7 +676,7 @@ void DepsgraphNodeBuilder::build_rigidbody(Scene *scene) } } -void DepsgraphNodeBuilder::build_particles(Object *ob) +void DepsgraphNodeBuilder::build_particles(Scene *scene, Object *ob) { /** * Particle Systems Nodes @@ -707,7 +707,7 @@ void DepsgraphNodeBuilder::build_particles(Object *ob) /* this particle system */ // TODO: for now, this will just be a placeholder "ubereval" node add_operation_node(psys_comp, - DEPSOP_TYPE_EXEC, function_bind(BKE_particle_system_eval, _1, ob, psys), + DEPSOP_TYPE_EXEC, function_bind(BKE_particle_system_eval, _1, scene, ob, psys), DEG_OPCODE_PSYS_EVAL, psys->name); } diff --git a/source/blender/depsgraph/intern/depsgraph_build_relations.cc b/source/blender/depsgraph/intern/depsgraph_build_relations.cc index 649105a0df2..c348adaaf53 100644 --- a/source/blender/depsgraph/intern/depsgraph_build_relations.cc +++ b/source/blender/depsgraph/intern/depsgraph_build_relations.cc @@ -812,6 +812,10 @@ void DepsgraphRelationBuilder::build_driver(ID *id, FCurve *fcu) ComponentKey geometry_key(shape_key->from, DEPSNODE_TYPE_GEOMETRY); add_relation(driver_key, geometry_key, DEPSREL_TYPE_DRIVER, "[Driver -> ShapeKey Geom]"); } + else if (strstr(fcu->rna_path, "key_blocks[")) { + ComponentKey geometry_key(id, DEPSNODE_TYPE_GEOMETRY); + add_relation(driver_key, geometry_key, DEPSREL_TYPE_DRIVER, "[Driver -> ShapeKey Geom]"); + } else { if (GS(id->name) == ID_OB) { /* assume that driver affects a transform... */ diff --git a/source/blender/depsgraph/intern/depsgraph_debug.cc b/source/blender/depsgraph/intern/depsgraph_debug.cc index 59351495df0..7f3f328502f 100644 --- a/source/blender/depsgraph/intern/depsgraph_debug.cc +++ b/source/blender/depsgraph/intern/depsgraph_debug.cc @@ -59,8 +59,6 @@ extern "C" { /* ****************** */ /* Graphviz Debugging */ -static SpinLock lock; - #define NL "\r\n" /* Only one should be enabled, defines whether graphviz nodes @@ -345,9 +343,11 @@ static void deg_debug_graphviz_node_fillcolor(const DebugContext &ctx, #endif static void deg_debug_graphviz_relation_color(const DebugContext &ctx, - const DepsRelation *UNUSED(rel)) + const DepsRelation *rel) { - const char *defaultcolor = "black"; + const char *color_default = "black"; + const char *color_error = "red4"; + const char *color = color_default; #if 0 /* disabled for now, edge colors are hardly distinguishable */ int color = deg_debug_relation_type_color_index(rel->type); if (color < 0) { @@ -357,7 +357,10 @@ static void deg_debug_graphviz_relation_color(const DebugContext &ctx, deg_debug_fprintf(ctx, "\"%s\"", deg_debug_colors_dark[color % deg_debug_max_colors]); } #else - deg_debug_fprintf(ctx, "%s", defaultcolor); + if (rel->flag & DEPSREL_FLAG_CYCLIC) + color = color_error; + + deg_debug_fprintf(ctx, "%s", color); #endif } @@ -439,6 +442,7 @@ static void deg_debug_graphviz_node_cluster_begin(const DebugContext &ctx, deg_debug_fprintf(ctx, "label=<%s>;" NL, name.c_str()); deg_debug_fprintf(ctx, "fontname=\"%s\";" NL, deg_debug_graphviz_fontname); deg_debug_fprintf(ctx, "fontsize=%f;" NL, deg_debug_graphviz_node_label_size); + deg_debug_fprintf(ctx, "margin=\"%d\";" NL, 16); deg_debug_fprintf(ctx, "style="); deg_debug_graphviz_node_style(ctx, node); deg_debug_fprintf(ctx, ";" NL); deg_debug_fprintf(ctx, "color="); deg_debug_graphviz_node_color(ctx, node); deg_debug_fprintf(ctx, ";" NL); deg_debug_fprintf(ctx, "fillcolor="); deg_debug_graphviz_node_fillcolor(ctx, node); deg_debug_fprintf(ctx, ";" NL); @@ -592,6 +596,8 @@ static void deg_debug_graphviz_node_relations(const DebugContext &ctx, { DEPSNODE_RELATIONS_ITER_BEGIN(node->inlinks, rel) { + float penwidth = 2.0f; + const DepsNode *tail = rel->to; /* same as node */ const DepsNode *head = rel->from; deg_debug_fprintf(ctx, "// %s -> %s\n", @@ -602,9 +608,20 @@ static void deg_debug_graphviz_node_relations(const DebugContext &ctx, deg_debug_fprintf(ctx, "\"node_%p\"", tail); deg_debug_fprintf(ctx, "["); + /* XXX labels on relations are not very helpful: + * - they tend to appear too far away to be associated with the edge lines + * - names are mostly redundant, reflecting simply their from/to nodes + * - no behavior or typing of relations themselves to justify labels + */ +#if 0 deg_debug_fprintf(ctx, "label=\"%s\"", rel->name); deg_debug_fprintf(ctx, ",fontname=\"%s\"", deg_debug_graphviz_fontname); +#else + /* Note: without label an id seem necessary to avoid bugs in graphviz/dot */ + deg_debug_fprintf(ctx, "id=\"%s\"", rel->name); +#endif deg_debug_fprintf(ctx, ",color="); deg_debug_graphviz_relation_color(ctx, rel); + deg_debug_fprintf(ctx, ",penwidth=\"%f\"", penwidth); /* NOTE: edge from node to own cluster is not possible and gives graphviz * warning, avoid this here by just linking directly to the invisible * placeholder node diff --git a/source/blender/depsgraph/intern/depsgraph_eval.cc b/source/blender/depsgraph/intern/depsgraph_eval.cc index 0a1563e7704..e8065766332 100644 --- a/source/blender/depsgraph/intern/depsgraph_eval.cc +++ b/source/blender/depsgraph/intern/depsgraph_eval.cc @@ -392,3 +392,8 @@ void DEG_evaluate_on_framechange(EvaluationContext *eval_ctx, /* Perform recalculation updates. */ DEG_evaluate_on_refresh_ex(eval_ctx, graph, layers); } + +bool DEG_needs_eval(Depsgraph *graph) +{ + return graph->entry_tags.size() != 0; +} diff --git a/source/blender/editors/animation/anim_filter.c b/source/blender/editors/animation/anim_filter.c index 8853422df8f..bdf5291dcc7 100644 --- a/source/blender/editors/animation/anim_filter.c +++ b/source/blender/editors/animation/anim_filter.c @@ -2016,7 +2016,7 @@ typedef struct tAnimFilterModifiersContext { /* dependency walker callback for modifier dependencies */ -static void animfilter_modifier_idpoin_cb(void *afm_ptr, Object *ob, ID **idpoin) +static void animfilter_modifier_idpoin_cb(void *afm_ptr, Object *ob, ID **idpoin, int UNUSED(cd_flag)) { tAnimFilterModifiersContext *afm = (tAnimFilterModifiersContext *)afm_ptr; ID *owner_id = &ob->id; diff --git a/source/blender/editors/animation/keyframes_general.c b/source/blender/editors/animation/keyframes_general.c index 3642c07b758..f0d9c48eb5e 100644 --- a/source/blender/editors/animation/keyframes_general.c +++ b/source/blender/editors/animation/keyframes_general.c @@ -955,6 +955,7 @@ short paste_animedit_keys(bAnimContext *ac, ListBase *anim_data, aci = animcopybuf.first; paste_animedit_keys_fcurve(fcu, aci, offset, merge_mode, false); + ale->update |= ANIM_UPDATE_DEFAULT; } else { /* from selected channels diff --git a/source/blender/editors/armature/armature_select.c b/source/blender/editors/armature/armature_select.c index f4575105426..dbbdae280f2 100644 --- a/source/blender/editors/armature/armature_select.c +++ b/source/blender/editors/armature/armature_select.c @@ -929,7 +929,7 @@ static int armature_select_hierarchy_exec(bContext *C, wmOperator *op) ob = obedit; arm = (bArmature *)ob->data; - ebone_active = arm->act_edbone; + ebone_active = arm->act_edbone; if (ebone_active == NULL) { return OPERATOR_CANCELLED; } diff --git a/source/blender/editors/armature/armature_utils.c b/source/blender/editors/armature/armature_utils.c index 09284860ec4..61ed7fdc41b 100644 --- a/source/blender/editors/armature/armature_utils.c +++ b/source/blender/editors/armature/armature_utils.c @@ -477,48 +477,78 @@ EditBone *make_boneList(ListBase *edbo, ListBase *bones, EditBone *parent, Bone return eBoneAct; } -/* nasty stuff for converting roll in editbones into bones */ -/* also sets restposition in armature (arm_mat) */ -static void fix_bonelist_roll(ListBase *bonelist, ListBase *editbonelist) +/* This function: + * - sets local head/tail rest locations using parent bone's arm_mat. + * - calls BKE_armature_where_is_bone() which uses parent's transform (arm_mat) to define this bone's transform. + * - fixes (converts) EditBone roll into Bone roll. + * - calls again BKE_armature_where_is_bone(), since roll fiddling may have changed things for our bone... + * Note that order is crucial here, we can only handle child if all its parents in chain have already been handled + * (this is ensured by recursive process). */ +static void armature_finalize_restpose(ListBase *bonelist, ListBase *editbonelist) { Bone *curBone; EditBone *ebone; - float premat[3][3]; - float postmat[3][3]; - float difmat[3][3]; - float imat[3][3]; - + for (curBone = bonelist->first; curBone; curBone = curBone->next) { - /* sets local matrix and arm_mat (restpos) */ - BKE_armature_where_is_bone(curBone, curBone->parent); - + /* Set bone's local head/tail. + * Note that it's important to use final parent's restpose (arm_mat) here, instead of setting those values + * from editbone's matrix (see T46010). */ + if (curBone->parent) { + float parmat_inv[4][4]; + + invert_m4_m4(parmat_inv, curBone->parent->arm_mat); + + /* Get the new head and tail */ + sub_v3_v3v3(curBone->head, curBone->arm_head, curBone->parent->arm_tail); + sub_v3_v3v3(curBone->tail, curBone->arm_tail, curBone->parent->arm_tail); + + mul_mat3_m4_v3(parmat_inv, curBone->head); + mul_mat3_m4_v3(parmat_inv, curBone->tail); + } + else { + copy_v3_v3(curBone->head, curBone->arm_head); + copy_v3_v3(curBone->tail, curBone->arm_tail); + } + + /* Set local matrix and arm_mat (restpose). + * Do not recurse into children here, armature_finalize_restpose() is already recursive. */ + BKE_armature_where_is_bone(curBone, curBone->parent, false); + /* Find the associated editbone */ - for (ebone = editbonelist->first; ebone; ebone = ebone->next) - if (ebone->temp.bone == curBone) - break; - - if (ebone) { - /* Get the ebone premat */ - ED_armature_ebone_to_mat3(ebone, premat); - - /* Get the bone postmat */ - copy_m3_m4(postmat, curBone->arm_mat); - - invert_m3_m3(imat, premat); - mul_m3_m3m3(difmat, imat, postmat); + for (ebone = editbonelist->first; ebone; ebone = ebone->next) { + if (ebone->temp.bone == curBone) { + float premat[3][3]; + float postmat[3][3]; + float difmat[3][3]; + float imat[3][3]; + + /* Get the ebone premat and its inverse. */ + ED_armature_ebone_to_mat3(ebone, premat); + invert_m3_m3(imat, premat); + + /* Get the bone postmat. */ + copy_m3_m4(postmat, curBone->arm_mat); + + mul_m3_m3m3(difmat, imat, postmat); + #if 0 - printf("Bone %s\n", curBone->name); - print_m4("premat", premat); - print_m4("postmat", postmat); - print_m4("difmat", difmat); - printf("Roll = %f\n", RAD2DEGF(-atan2(difmat[2][0], difmat[2][2]))); + printf("Bone %s\n", curBone->name); + print_m4("premat", premat); + print_m4("postmat", postmat); + print_m4("difmat", difmat); + printf("Roll = %f\n", RAD2DEGF(-atan2(difmat[2][0], difmat[2][2]))); #endif - curBone->roll = -atan2f(difmat[2][0], difmat[2][2]); - - /* and set restposition again */ - BKE_armature_where_is_bone(curBone, curBone->parent); + + curBone->roll = -atan2f(difmat[2][0], difmat[2][2]); + + /* and set restposition again */ + BKE_armature_where_is_bone(curBone, curBone->parent, false); + break; + } } - fix_bonelist_roll(&curBone->childbase, editbonelist); + + /* Recurse into children... */ + armature_finalize_restpose(&curBone->childbase, editbonelist); } } @@ -535,9 +565,9 @@ void ED_armature_from_edit(bArmature *arm) /* remove zero sized bones, this gives unstable restposes */ for (eBone = arm->edbo->first; eBone; eBone = neBone) { - float len = len_v3v3(eBone->head, eBone->tail); + float len_sq = len_squared_v3v3(eBone->head, eBone->tail); neBone = eBone->next; - if (len <= 0.000001f) { /* FLT_EPSILON is too large? */ + if (len_sq <= SQUARE(0.000001f)) { /* FLT_EPSILON is too large? */ EditBone *fBone; /* Find any bones that refer to this bone */ @@ -587,48 +617,29 @@ void ED_armature_from_edit(bArmature *arm) newBone->prop = IDP_CopyProperty(eBone->prop); } - /* Fix parenting in a separate pass to ensure ebone->bone connections - * are valid at this point */ + /* Fix parenting in a separate pass to ensure ebone->bone connections are valid at this point. + * Do not set bone->head/tail here anymore, using EditBone data for that is not OK since our later fiddling + * with parent's arm_mat (for roll conversion) may have some small but visible impact on locations (T46010). */ for (eBone = arm->edbo->first; eBone; eBone = eBone->next) { newBone = eBone->temp.bone; if (eBone->parent) { newBone->parent = eBone->parent->temp.bone; BLI_addtail(&newBone->parent->childbase, newBone); - - { - float M_parentRest[3][3]; - float iM_parentRest[3][3]; - - /* Get the parent's matrix (rotation only) */ - ED_armature_ebone_to_mat3(eBone->parent, M_parentRest); - - /* Invert the parent matrix */ - invert_m3_m3(iM_parentRest, M_parentRest); - - /* Get the new head and tail */ - sub_v3_v3v3(newBone->head, eBone->head, eBone->parent->tail); - sub_v3_v3v3(newBone->tail, eBone->tail, eBone->parent->tail); - - mul_m3_v3(iM_parentRest, newBone->head); - mul_m3_v3(iM_parentRest, newBone->tail); - } } /* ...otherwise add this bone to the armature's bonebase */ else { - copy_v3_v3(newBone->head, eBone->head); - copy_v3_v3(newBone->tail, eBone->tail); BLI_addtail(&arm->bonebase, newBone); } } - /* Make a pass through the new armature to fix rolling */ - /* also builds restposition again (like BKE_armature_where_is) */ - fix_bonelist_roll(&arm->bonebase, arm->edbo); + /* Finalize definition of restpose data (roll, bone_mat, arm_mat, head/tail...). */ + armature_finalize_restpose(&arm->bonebase, arm->edbo); /* so all users of this armature should get rebuilt */ for (obt = G.main->object.first; obt; obt = obt->id.next) { - if (obt->data == arm) + if (obt->data == arm) { BKE_pose_rebuild(obt, arm); + } } DAG_id_tag_update(&arm->id, 0); diff --git a/source/blender/editors/armature/editarmature_sketch.c b/source/blender/editors/armature/editarmature_sketch.c index c0098a3726a..e4c3f73dd94 100644 --- a/source/blender/editors/armature/editarmature_sketch.c +++ b/source/blender/editors/armature/editarmature_sketch.c @@ -436,7 +436,7 @@ static float sk_clampPointSize(SK_Point *pt, float size) static void sk_drawPoint(GLUquadric *quad, SK_Point *pt, float size) { - glTranslatef(pt->p[0], pt->p[1], pt->p[2]); + glTranslate3fv(pt->p); gluSphere(quad, sk_clampPointSize(pt, size), 8, 8); } @@ -455,7 +455,7 @@ static void sk_drawEdge(GLUquadric *quad, SK_Point *pt0, SK_Point *pt1, float si angle = angle_normalized_v3v3(vec2, vec1); - glRotatef(angle * (float)(180.0 / M_PI) + 180.0f, axis[0], axis[1], axis[2]); + glRotate3fv(angle * (float)(180.0 / M_PI) + 180.0f, axis); gluCylinder(quad, sk_clampPointSize(pt1, size), sk_clampPointSize(pt0, size), length, 8, 8); } @@ -475,7 +475,7 @@ static void sk_drawNormal(GLUquadric *quad, SK_Point *pt, float size, float heig angle = angle_normalized_v3v3(vec2, pt->no); - glRotatef(angle * (float)(180.0 / M_PI), axis[0], axis[1], axis[2]); + glRotate3fv(angle * (float)(180.0 / M_PI), axis); glColor3f(0, 1, 1); gluCylinder(quad, sk_clampPointSize(pt, size), 0, sk_clampPointSize(pt, height), 10, 2); @@ -2112,7 +2112,7 @@ static void sk_drawSketch(Scene *scene, View3D *UNUSED(v3d), SK_Sketch *sketch, glColor3fv(colors[index]); glPushMatrix(); - glTranslatef(p->p[0], p->p[1], p->p[2]); + glTranslate3fv(p->p); gluSphere(quad, 0.02, 8, 8); glPopMatrix(); } diff --git a/source/blender/editors/curve/editcurve_select.c b/source/blender/editors/curve/editcurve_select.c index cbb533a0440..34ac3b8bb97 100644 --- a/source/blender/editors/curve/editcurve_select.c +++ b/source/blender/editors/curve/editcurve_select.c @@ -999,20 +999,22 @@ void CURVE_OT_select_less(wmOperatorType *ot) /********************** select random *********************/ -static void curve_select_random(ListBase *editnurb, float randfac, bool select) +static void curve_select_random(ListBase *editnurb, float randfac, int seed, bool select) { Nurb *nu; BezTriple *bezt; BPoint *bp; int a; + RNG *rng = BLI_rng_new_srandom(seed); + for (nu = editnurb->first; nu; nu = nu->next) { if (nu->type == CU_BEZIER) { bezt = nu->bezt; a = nu->pntsu; while (a--) { if (!bezt->hide) { - if (BLI_frand() < randfac) { + if (BLI_rng_get_float(rng) < randfac) { select_beztriple(bezt, select, SELECT, VISIBLE); } } @@ -1025,7 +1027,7 @@ static void curve_select_random(ListBase *editnurb, float randfac, bool select) while (a--) { if (!bp->hide) { - if (BLI_frand() < randfac) { + if (BLI_rng_get_float(rng) < randfac) { select_bpoint(bp, select, SELECT, VISIBLE); } } @@ -1033,6 +1035,8 @@ static void curve_select_random(ListBase *editnurb, float randfac, bool select) } } } + + BLI_rng_free(rng); } static int curve_select_random_exec(bContext *C, wmOperator *op) @@ -1041,8 +1045,9 @@ static int curve_select_random_exec(bContext *C, wmOperator *op) ListBase *editnurb = object_editcurve_get(obedit); const bool select = (RNA_enum_get(op->ptr, "action") == SEL_SELECT); const float randfac = RNA_float_get(op->ptr, "percent") / 100.0f; + const int seed = RNA_int_get(op->ptr, "seed"); - curve_select_random(editnurb, randfac, select); + curve_select_random(editnurb, randfac, seed, select); BKE_curve_nurb_vert_active_validate(obedit->data); WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); @@ -1065,9 +1070,7 @@ void CURVE_OT_select_random(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; /* properties */ - RNA_def_float_percentage(ot->srna, "percent", 50.f, 0.0f, 100.0f, - "Percent", "Percentage of elements to select randomly", 0.0f, 100.0f); - WM_operator_properties_select_action_simple(ot, SEL_SELECT); + WM_operator_properties_select_random(ot); } /********************* every nth number of point *******************/ @@ -1725,4 +1728,4 @@ void CURVE_OT_shortest_path_pick(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } -/** \} */
\ No newline at end of file +/** \} */ diff --git a/source/blender/editors/gpencil/drawgpencil.c b/source/blender/editors/gpencil/drawgpencil.c index ff8984ae329..6b71c0ac053 100644 --- a/source/blender/editors/gpencil/drawgpencil.c +++ b/source/blender/editors/gpencil/drawgpencil.c @@ -398,7 +398,7 @@ static void gp_draw_stroke_point(bGPDspoint *points, short thickness, short dfla gluQuadricDrawStyle(qobj, GLU_FILL); /* need to translate drawing position, but must reset after too! */ - glTranslatef(co[0], co[1], 0.0); + glTranslate2fv(co); gluDisk(qobj, 0.0, thickness, 32, 1); glTranslatef(-co[0], -co[1], 0.0); diff --git a/source/blender/editors/gpencil/gpencil_paint.c b/source/blender/editors/gpencil/gpencil_paint.c index 184482eeacb..df88da073ca 100644 --- a/source/blender/editors/gpencil/gpencil_paint.c +++ b/source/blender/editors/gpencil/gpencil_paint.c @@ -756,7 +756,7 @@ static short gp_stroke_eraser_splitdel(bGPDframe *gpf, bGPDstroke *gps, int i) else if (i == gps->totpoints - 2) { /* allocate new points array, and assign most of the old stroke there */ gps->totpoints--; - gps->points = MEM_callocN(sizeof(bGPDspoint) * gps->totpoints, "gp_stroke_points"); + gps->points = MEM_mallocN(sizeof(bGPDspoint) * gps->totpoints, "gp_stroke_points"); memcpy(gps->points, pt_tmp, sizeof(bGPDspoint) * gps->totpoints); /* free temp buffer */ @@ -770,7 +770,7 @@ static short gp_stroke_eraser_splitdel(bGPDframe *gpf, bGPDstroke *gps, int i) else if (i == 0) { /* allocate new points array, and assign most of the old stroke there */ gps->totpoints--; - gps->points = MEM_callocN(sizeof(bGPDspoint) * gps->totpoints, "gp_stroke_points"); + gps->points = MEM_mallocN(sizeof(bGPDspoint) * gps->totpoints, "gp_stroke_points"); memcpy(gps->points, pt_tmp + 1, sizeof(bGPDspoint) * gps->totpoints); /* We must adjust timings! @@ -807,7 +807,7 @@ static short gp_stroke_eraser_splitdel(bGPDframe *gpf, bGPDstroke *gps, int i) BLI_insertlinkafter(&gpf->strokes, gps, gsn); gsn->totpoints = gps->totpoints - i; - gsn->points = MEM_callocN(sizeof(bGPDspoint) * gsn->totpoints, "gp_stroke_points"); + gsn->points = MEM_mallocN(sizeof(bGPDspoint) * gsn->totpoints, "gp_stroke_points"); memcpy(gsn->points, pt_tmp + i, sizeof(bGPDspoint) * gsn->totpoints); /* We must adjust timings of this new stroke! @@ -831,8 +831,8 @@ static short gp_stroke_eraser_splitdel(bGPDframe *gpf, bGPDstroke *gps, int i) /* adjust existing stroke */ gps->totpoints = i; - gps->points = MEM_callocN(sizeof(bGPDspoint) * gps->totpoints, "gp_stroke_points"); - memcpy(gps->points, pt_tmp, sizeof(bGPDspoint) * i); + gps->points = MEM_mallocN(sizeof(bGPDspoint) * gps->totpoints, "gp_stroke_points"); + memcpy(gps->points, pt_tmp, sizeof(bGPDspoint) * gps->totpoints); /* free temp buffer */ MEM_freeN(pt_tmp); diff --git a/source/blender/editors/include/BIF_gl.h b/source/blender/editors/include/BIF_gl.h index 49c808e4f01..58da0b5d695 100644 --- a/source/blender/editors/include/BIF_gl.h +++ b/source/blender/editors/include/BIF_gl.h @@ -34,6 +34,7 @@ #define __BIF_GL_H__ #include "GPU_glew.h" +#include "BLI_utildefines.h" /* * these should be phased out. cpack should be replaced in @@ -85,5 +86,24 @@ void cpack(unsigned int x); #define GLA_PIXEL_OFS 0.375f + +BLI_INLINE void glTranslate3iv(const int vec[3]) { glTranslatef(UNPACK3_EX((const float), vec, )); } +BLI_INLINE void glTranslate2iv(const int vec[2]) { glTranslatef(UNPACK2_EX((const float), vec, ), 0.0f); } +BLI_INLINE void glTranslate3fv(const float vec[3]) { glTranslatef(UNPACK3(vec)); } +BLI_INLINE void glTranslate2fv(const float vec[2]) { glTranslatef(UNPACK2(vec), 0.0f); } +BLI_INLINE void glTranslate3dv(const double vec[3]) { glTranslated(UNPACK3(vec)); } +BLI_INLINE void glTranslate2dv(const double vec[2]) { glTranslated(UNPACK2(vec), 0.0f); } + +BLI_INLINE void glScale3iv(const int vec[3]) { glTranslatef(UNPACK3_EX((const float), vec, )); } +BLI_INLINE void glScale2iv(const int vec[2]) { glTranslatef(UNPACK2_EX((const float), vec, ), 0.0f); } +BLI_INLINE void glScale3fv(const float vec[3]) { glScalef(UNPACK3(vec)); } +BLI_INLINE void glScale2fv(const float vec[2]) { glScalef(UNPACK2(vec), 0.0); } +BLI_INLINE void glScale3dv(const double vec[3]) { glScaled(UNPACK3(vec)); } +BLI_INLINE void glScale2dv(const double vec[2]) { glScaled(UNPACK2(vec), 0.0); } + +/* v2 versions don't make much sense for rotation */ +BLI_INLINE void glRotate3fv(const float angle, const float vec[3]) { glRotatef(angle, UNPACK3(vec)); } +BLI_INLINE void glRotate3dv(const double angle, const double vec[3]) { glRotated(angle, UNPACK3(vec)); } + #endif /* #ifdef __BIF_GL_H__ */ diff --git a/source/blender/editors/include/ED_image.h b/source/blender/editors/include/ED_image.h index f49d4b508c6..4c4cec2ee29 100644 --- a/source/blender/editors/include/ED_image.h +++ b/source/blender/editors/include/ED_image.h @@ -59,8 +59,8 @@ void ED_space_image_get_uv_aspect(struct SpaceImage *sima, float *aspx, float *a void ED_space_image_scopes_update(const struct bContext *C, struct SpaceImage *sima, struct ImBuf *ibuf, bool use_view_settings); -void ED_space_image_paint_update(struct wmWindowManager *wm, struct ToolSettings *settings); -void ED_space_image_uv_sculpt_update(struct wmWindowManager *wm, struct ToolSettings *settings); +void ED_space_image_paint_update(struct wmWindowManager *wm, struct Scene *scene); +void ED_space_image_uv_sculpt_update(struct wmWindowManager *wm, struct Scene *scene); void ED_image_get_uv_aspect(struct Image *ima, struct ImageUser *iuser, float *aspx, float *aspy); void ED_image_mouse_pos(struct SpaceImage *sima, struct ARegion *ar, const int mval[2], float co[2]); diff --git a/source/blender/editors/include/ED_render.h b/source/blender/editors/include/ED_render.h index 1898b9cb5d1..707d7c6c693 100644 --- a/source/blender/editors/include/ED_render.h +++ b/source/blender/editors/include/ED_render.h @@ -49,6 +49,7 @@ void ED_render_id_flush_update(struct Main *bmain, struct ID *id); void ED_render_engine_changed(struct Main *bmain); void ED_render_engine_area_exit(struct Main *bmain, struct ScrArea *sa); void ED_render_scene_update(struct Main *bmain, struct Scene *scene, int updated); +void ED_render_scene_update_pre(struct Main *bmain, struct Scene *scene, bool time); void ED_viewport_render_kill_jobs(struct wmWindowManager *wm, struct Main *bmain, bool free_database); struct Scene *ED_render_job_get_scene(const struct bContext *C); diff --git a/source/blender/editors/include/ED_screen.h b/source/blender/editors/include/ED_screen.h index 6c9150cbb74..2a7d79c9d1c 100644 --- a/source/blender/editors/include/ED_screen.h +++ b/source/blender/editors/include/ED_screen.h @@ -69,7 +69,7 @@ void ED_region_header_init(struct ARegion *ar); void ED_region_header(const struct bContext *C, struct ARegion *ar); void ED_region_toggle_hidden(struct bContext *C, struct ARegion *ar); void ED_region_info_draw(struct ARegion *ar, const char *text, float fill_color[4], const bool full_redraw); -void ED_region_image_metadata_draw(int x, int y, struct ImBuf *ibuf, rctf frame, float zoomx, float zoomy); +void ED_region_image_metadata_draw(int x, int y, struct ImBuf *ibuf, const rctf *frame, float zoomx, float zoomy); void ED_region_grid_draw(struct ARegion *ar, float zoomx, float zoomy); void ED_region_draw_backdrop_view3d(const struct bContext *C, struct Object *camera, const float alpha, const float width, const float height, const float x, const float y, diff --git a/source/blender/editors/include/ED_transform.h b/source/blender/editors/include/ED_transform.h index 080820e67a1..17db1cb8548 100644 --- a/source/blender/editors/include/ED_transform.h +++ b/source/blender/editors/include/ED_transform.h @@ -135,7 +135,7 @@ void BIF_createTransformOrientation(struct bContext *C, struct ReportList *repor void BIF_selectTransformOrientation(struct bContext *C, struct TransformOrientation *ts); void BIF_selectTransformOrientationValue(struct bContext *C, int orientation); -void ED_getTransformOrientationMatrix(const struct bContext *C, float orientation_mat[3][3], const bool activeOnly); +void ED_getTransformOrientationMatrix(const struct bContext *C, float orientation_mat[3][3], const short around); int BIF_countTransformOrientation(const struct bContext *C); diff --git a/source/blender/editors/include/ED_view3d.h b/source/blender/editors/include/ED_view3d.h index 84e09910c85..97696c8fd47 100644 --- a/source/blender/editors/include/ED_view3d.h +++ b/source/blender/editors/include/ED_view3d.h @@ -329,15 +329,20 @@ bool ED_view3d_context_activate(struct bContext *C); void ED_view3d_draw_offscreen_init(struct Scene *scene, struct View3D *v3d); void ED_view3d_draw_offscreen( struct Scene *scene, struct View3D *v3d, struct ARegion *ar, int winx, int winy, float viewmat[4][4], - float winmat[4][4], bool do_bgpic, bool do_sky, bool is_persp, - struct GPUOffScreen *ofs, + float winmat[4][4], bool do_bgpic, bool do_sky, bool is_persp, const char *viewname, struct GPUFX *fx, struct GPUFXSettings *fx_settings, - const char *viewname); - -struct ImBuf *ED_view3d_draw_offscreen_imbuf(struct Scene *scene, struct View3D *v3d, struct ARegion *ar, int sizex, int sizey, unsigned int flag, - bool draw_background, int alpha_mode, const char *viewname, char err_out[256]); -struct ImBuf *ED_view3d_draw_offscreen_imbuf_simple(struct Scene *scene, struct Object *camera, int width, int height, unsigned int flag, int drawtype, - bool use_solid_tex, bool use_gpencil, bool draw_background, int alpha_mode, const char *viewname, char err_out[256]); + struct GPUOffScreen *ofs); + +struct ImBuf *ED_view3d_draw_offscreen_imbuf( + struct Scene *scene, struct View3D *v3d, struct ARegion *ar, int sizex, int sizey, + unsigned int flag, bool draw_background, + int alpha_mode, int samples, const char *viewname, + struct GPUOffScreen *ofs, char err_out[256]); +struct ImBuf *ED_view3d_draw_offscreen_imbuf_simple( + struct Scene *scene, struct 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, const char *viewname, + struct GPUOffScreen *ofs, char err_out[256]); struct Base *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); diff --git a/source/blender/editors/include/UI_icons.h b/source/blender/editors/include/UI_icons.h index 32f45b222aa..286235e95eb 100644 --- a/source/blender/editors/include/UI_icons.h +++ b/source/blender/editors/include/UI_icons.h @@ -374,8 +374,8 @@ DEF_ICON(MESH_MONKEY) DEF_ICON(MESH_CYLINDER) DEF_ICON(MESH_TORUS) DEF_ICON(MESH_CONE) +DEF_ICON(MESH_CAPSULE) #ifndef DEF_ICON_BLANK_SKIP - DEF_ICON(BLANK610) DEF_ICON(BLANK611) #endif DEF_ICON(LAMP_POINT) @@ -702,14 +702,12 @@ DEF_ICON(MANIPUL) DEF_ICON(SNAP_OFF) DEF_ICON(SNAP_ON) DEF_ICON(SNAP_NORMAL) -DEF_ICON(SNAP_INCREMENT) +DEF_ICON(SNAP_GRID) DEF_ICON(SNAP_VERTEX) DEF_ICON(SNAP_EDGE) DEF_ICON(SNAP_FACE) DEF_ICON(SNAP_VOLUME) -#ifndef DEF_ICON_BLANK_SKIP - DEF_ICON(BLANK220) -#endif +DEF_ICON(SNAP_INCREMENT) DEF_ICON(STICKY_UVS_LOC) DEF_ICON(STICKY_UVS_DISABLE) DEF_ICON(STICKY_UVS_VERT) diff --git a/source/blender/editors/include/UI_interface.h b/source/blender/editors/include/UI_interface.h index 3fb41069449..8125ab4297e 100644 --- a/source/blender/editors/include/UI_interface.h +++ b/source/blender/editors/include/UI_interface.h @@ -1050,6 +1050,8 @@ void UI_butstore_unregister(uiButStore *bs_handle, uiBut **but_p); /* Float precision helpers */ #define UI_PRECISION_FLOAT_MAX 7 +/* For float buttons the 'step' (or a1), is scaled */ +#define UI_PRECISION_FLOAT_SCALE 0.01f /* Typical UI text */ #define UI_FSTYLE_WIDGET (const uiFontStyle *)&(UI_style_get()->widget) diff --git a/source/blender/editors/include/UI_view2d.h b/source/blender/editors/include/UI_view2d.h index 43a55845d49..7335233a215 100644 --- a/source/blender/editors/include/UI_view2d.h +++ b/source/blender/editors/include/UI_view2d.h @@ -155,7 +155,7 @@ void UI_view2d_curRect_reset(struct View2D *v2d); void UI_view2d_sync(struct bScreen *screen, struct ScrArea *sa, struct View2D *v2dcur, int flag); void UI_view2d_totRect_set(struct View2D *v2d, int width, int height); -void UI_view2d_totRect_set_resize(struct View2D *v2d, int width, int height, int resize); +void UI_view2d_totRect_set_resize(struct View2D *v2d, int width, int height, bool resize); /* per tab offsets, returns 1 if tab changed */ bool UI_view2d_tab_set(struct View2D *v2d, int tab); diff --git a/source/blender/editors/interface/interface.c b/source/blender/editors/interface/interface.c index 4c42d5bac99..0ee4a30d005 100644 --- a/source/blender/editors/interface/interface.c +++ b/source/blender/editors/interface/interface.c @@ -375,9 +375,11 @@ static void ui_block_bounds_calc_popup( wmWindow *window, uiBlock *block, eBlockBoundsCalc bounds_calc, const int xy[2]) { - int startx, starty, endx, endy, width, height, oldwidth, oldheight; + int width, height, oldwidth, oldheight; int oldbounds, xmax, ymax; const int margin = UI_SCREEN_MARGIN; + rcti rect, rect_bounds; + int ofs_dummy[2]; oldbounds = block->bounds; @@ -412,27 +414,18 @@ static void ui_block_bounds_calc_popup( /* offset block based on mouse position, user offset is scaled * along in case we resized the block in ui_block_bounds_calc_text */ - startx = xy[0] + block->rect.xmin + (block->mx * width) / oldwidth; - starty = xy[1] + block->rect.ymin + (block->my * height) / oldheight; + rect.xmin = xy[0] + block->rect.xmin + (block->mx * width) / oldwidth; + rect.ymin = xy[1] + block->rect.ymin + (block->my * height) / oldheight; + rect.xmax = rect.xmin + width; + rect.ymax = rect.ymin + height; - if (startx < margin) - startx = margin; - if (starty < margin) - starty = margin; + rect_bounds.xmin = margin; + rect_bounds.ymin = margin; + rect_bounds.xmax = xmax - margin; + rect_bounds.ymax = ymax - UI_POPUP_MENU_TOP; - endx = startx + width; - endy = starty + height; - - if (endx > xmax) { - endx = xmax - margin; - startx = endx - width; - } - if (endy > ymax - margin) { - endy = ymax - margin; - starty = endy - height; - } - - ui_block_translate(block, startx - block->rect.xmin, starty - block->rect.ymin); + BLI_rcti_clamp(&rect, &rect_bounds, ofs_dummy); + ui_block_translate(block, rect.xmin - block->rect.xmin, rect.ymin - block->rect.ymin); /* now recompute bounds and safety */ ui_block_bounds_calc(block); @@ -1849,6 +1842,16 @@ bool ui_but_is_rna_valid(uiBut *but) } } +/** + * Checks if the button supports ctrl+mousewheel cycling + */ +bool ui_but_supports_cycling(const uiBut *but) +{ + return ((ELEM(but->type, UI_BTYPE_ROW, UI_BTYPE_NUM, UI_BTYPE_NUM_SLIDER, UI_BTYPE_LISTBOX)) || + (but->type == UI_BTYPE_MENU && ui_but_menu_step_poll(but)) || + (but->type == UI_BTYPE_COLOR && but->a1 != -1)); +} + double ui_but_value_get(uiBut *but) { PropertyRNA *prop; @@ -2121,14 +2124,32 @@ static void ui_get_but_string_unit(uiBut *but, char *str, int len_max, double va static float ui_get_but_step_unit(uiBut *but, float step_default) { int unit_type = RNA_SUBTYPE_UNIT_VALUE(UI_but_unit_type_get(but)); - double step; - - step = bUnit_ClosestScalar(ui_get_but_scale_unit(but, step_default), but->block->unit->system, unit_type); + const double step_orig = step_default * UI_PRECISION_FLOAT_SCALE; + /* Scaling up 'step_origg ' here is a bit arbitrary, its just giving better scales from user POV */ + const double scale_step = ui_get_but_scale_unit(but, step_orig * 10); + const double step = bUnit_ClosestScalar(scale_step, but->block->unit->system, unit_type); /* -1 is an error value */ if (step != -1.0) { + const double scale_unit = ui_get_but_scale_unit(but, 1.0); + const double step_unit = bUnit_ClosestScalar(scale_unit, but->block->unit->system, unit_type); + double step_final; + BLI_assert(step > 0.0); - return (float)(step / ui_get_but_scale_unit(but, 1.0)); + + step_final = (step / scale_unit) / (double)UI_PRECISION_FLOAT_SCALE; + + if (step == step_unit) { + /* Logic here is to scale by the original 'step_orig' + * only when the unit step matches the scaled step. + * + * This is needed for units that don't have a wide range of scales (degrees for eg.). + * Without this we can't select between a single degree, or a 10th of a degree. + */ + step_final *= step_orig; + } + + return (float)step_final; } else { return step_default; @@ -2172,8 +2193,14 @@ void ui_but_string_get_ex(uiBut *but, char *str, const size_t maxlen, const int str[0] = '\0'; } else if (buf && buf != str) { + BLI_assert(maxlen <= buf_len + 1); /* string was too long, we have to truncate */ - memcpy(str, buf, MIN2(maxlen, (size_t)(buf_len + 1))); + if (ui_but_is_utf8(but)) { + BLI_strncpy_utf8(str, buf, maxlen); + } + else { + BLI_strncpy(str, buf, maxlen); + } MEM_freeN((void *)buf); } } @@ -3170,6 +3197,20 @@ void ui_block_cm_to_scene_linear_v3(uiBlock *block, float pixel[3]) IMB_colormanagement_display_to_scene_linear_v3(pixel, display); } +void ui_block_cm_to_display_space_range(uiBlock *block, float *min, float *max) +{ + struct ColorManagedDisplay *display = ui_block_cm_display_get(block); + float pixel[3]; + + copy_v3_fl(pixel, *min); + IMB_colormanagement_scene_linear_to_display_v3(pixel, display); + *min = min_fff(UNPACK3(pixel)); + + copy_v3_fl(pixel, *max); + IMB_colormanagement_scene_linear_to_display_v3(pixel, display); + *max = max_fff(UNPACK3(pixel)); +} + static uiSubBut *ui_def_subbut( uiBut *but, const int type, uiSubButAlign alignment, diff --git a/source/blender/editors/interface/interface_draw.c b/source/blender/editors/interface/interface_draw.c index 0193c1b3a7c..968b3ea1934 100644 --- a/source/blender/editors/interface/interface_draw.c +++ b/source/blender/editors/interface/interface_draw.c @@ -675,8 +675,8 @@ void ui_draw_but_HISTOGRAM(ARegion *ar, uiBut *but, uiWidgetColors *UNUSED(wcol) glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - - glColor4f(0.f, 0.f, 0.f, 0.3f); + + UI_ThemeColor4(TH_PREVIEW_BACK); 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); @@ -762,8 +762,8 @@ void ui_draw_but_WAVEFORM(ARegion *ar, uiBut *but, uiWidgetColors *UNUSED(wcol), glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - - glColor4f(0.f, 0.f, 0.f, 0.3f); + + UI_ThemeColor4(TH_PREVIEW_BACK); 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); @@ -981,8 +981,8 @@ void ui_draw_but_VECTORSCOPE(ARegion *ar, uiBut *but, uiWidgetColors *UNUSED(wco glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - - glColor4f(0.f, 0.f, 0.f, 0.3f); + + UI_ThemeColor4(TH_PREVIEW_BACK); 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); diff --git a/source/blender/editors/interface/interface_handlers.c b/source/blender/editors/interface/interface_handlers.c index 5d2b6e3c9c6..b2688619e7a 100644 --- a/source/blender/editors/interface/interface_handlers.c +++ b/source/blender/editors/interface/interface_handlers.c @@ -138,6 +138,8 @@ static bool ui_mouse_motion_keynav_test(struct uiKeyNavLock *keynav, const wmEve #define MENU_TOWARDS_MARGIN 20 /* margin in pixels */ #define MENU_TOWARDS_WIGGLE_ROOM 64 /* tolerance in pixels */ +/* drag-lock distance threshold in pixels */ +#define BUTTON_DRAGLOCK_THRESH 3 typedef enum uiButtonActivateType { BUTTON_ACTIVATE_OVER, @@ -530,6 +532,30 @@ static bool ui_but_is_cursor_warp(uiBut *but) return false; } +/** + * Ignore mouse movements within some horizontal pixel threshold before starting to drag + */ +static bool ui_but_dragedit_update_mval(uiHandleButtonData *data, int mx) +{ + if (mx == data->draglastx) + return false; + + if (data->draglock) { + if (ABS(mx - data->dragstartx) <= BUTTON_DRAGLOCK_THRESH) { + return false; + } +#ifdef USE_DRAG_MULTINUM + if (ELEM(data->multi_data.init, BUTTON_MULTI_INIT_UNSET, BUTTON_MULTI_INIT_SETUP)) { + return false; + } +#endif + data->draglock = false; + data->dragstartx = mx; /* ignore mouse movement within drag-lock */ + } + + return true; +} + static float ui_mouse_scale_warp_factor(const bool shift) { return shift ? 0.05f : 1.0f; @@ -3949,8 +3975,12 @@ static float ui_numedit_apply_snapf( /* snapping by 10's for float buttons is quite annoying (location, scale...), * but allow for rotations */ if (softrange >= 21.0f) { + UnitSettings *unit = but->block->unit; int unit_type = UI_but_unit_type_get(but); - if (!ELEM(unit_type, PROP_UNIT_ROTATION)) { + if ((unit_type == PROP_UNIT_ROTATION) && (unit->system_rotation != USER_UNIT_ROT_RADIANS)) { + /* pass (degrees)*/ + } + else { softrange = 20.0f; } } @@ -4006,23 +4036,10 @@ static bool ui_numedit_but_NUM( int lvalue, temp; bool changed = false; const bool is_float = ui_but_is_float(but); - - if (mx == data->draglastx) - return changed; - - /* drag-lock - prevent unwanted scroll adjustments */ - /* change value (now 3) to adjust threshold in pixels */ - if (data->draglock) { - if (abs(mx - data->dragstartx) <= 3) - return changed; -#ifdef USE_DRAG_MULTINUM - if (ELEM(data->multi_data.init, BUTTON_MULTI_INIT_UNSET, BUTTON_MULTI_INIT_SETUP)) { - return changed; - } -#endif - data->draglock = false; - data->dragstartx = mx; /* ignore mouse movement within drag-lock */ + /* prevent unwanted drag adjustments */ + if (ui_but_dragedit_update_mval(data, mx) == false) { + return changed; } softmin = but->softmin; @@ -4319,6 +4336,13 @@ static bool ui_numedit_but_SLI( /* note, 'offs' is really from the widget drawing rounded corners see 'widget_numslider' */ float offs; + /* prevent unwanted drag adjustments */ + if ((but->type != UI_BTYPE_SCROLL) && + (ui_but_dragedit_update_mval(data, mx) == false)) + { + return changed; + } + softmin = but->softmin; softmax = but->softmax; softrange = softmax - softmin; @@ -4498,6 +4522,10 @@ static int ui_do_but_SLI(bContext *C, uiBlock *block, uiBut *but, uiHandleButton } } else { +#ifdef USE_CONT_MOUSE_CORRECT + /* reset! */ + copy_v2_fl(data->ungrab_mval, FLT_MAX); +#endif click = 1; } } @@ -5187,11 +5215,16 @@ static bool ui_numedit_but_HSVCUBE( hsv[2] = y; break; case UI_GRAD_V_ALT: + { /* vertical 'value' strip */ - + float min = but->softmin, max = but->softmax; + if (use_display_colorspace) { + ui_block_cm_to_display_space_range(but->block, &min, &max); + } /* exception only for value strip - use the range set in but->min/max */ - hsv[2] = y * (but->softmax - but->softmin) + but->softmin; + hsv[2] = y * (max - min) + min; break; + } default: BLI_assert(0); break; @@ -5690,7 +5723,9 @@ static int ui_do_but_COLORBAND(bContext *C, uiBlock *block, uiBut *but, uiHandle { ColorBand *coba; CBData *cbd; - int mx, my, a, xco, mindist = 12; + /* ignore zoom-level for mindist */ + int mindist = (50 * UI_DPI_FAC) * block->aspect; + int mx, my, a, xco; mx = event->x; my = event->y; @@ -6664,30 +6699,44 @@ static bool ui_but_menu(bContext *C, uiBut *but) int w = uiLayoutGetWidth(layout); wmKeyMap *km; wmKeyMapItem *kmi = NULL; - int kmi_id = WM_key_event_operator_id(C, but->optype->idname, but->opcontext, prop, true, &km); + /* We want to know if this op has a shortcut, be it hotkey or not. */ + int kmi_id = WM_key_event_operator_id(C, but->optype->idname, but->opcontext, prop, false, &km); if (kmi_id) kmi = WM_keymap_item_find_id(km, kmi_id); - /* keyboard shortcuts */ - if ((kmi) && ISKEYBOARD(kmi->type)) { + /* We do have a shortcut, but only keyboard ones are editbale that way... */ + if (kmi) { + if (ISKEYBOARD(kmi->type)) { +#if 0 /* would rather use a block but, but gets weirdly positioned... */ + uiDefBlockBut(block, menu_change_shortcut, but, "Change Shortcut", + 0, 0, uiLayoutGetWidth(layout), UI_UNIT_Y, ""); +#endif - /* would rather use a block but, but gets weirdly positioned... */ - //uiDefBlockBut(block, menu_change_shortcut, but, "Change Shortcut", 0, 0, uiLayoutGetWidth(layout), UI_UNIT_Y, ""); - - but2 = uiDefIconTextBut(block, UI_BTYPE_BUT, 0, 0, CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Change Shortcut"), - 0, 0, w, UI_UNIT_Y, NULL, 0, 0, 0, 0, ""); - UI_but_func_set(but2, popup_change_shortcut_func, but, NULL); + but2 = uiDefIconTextBut(block, UI_BTYPE_BUT, 0, ICON_NONE, + CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Change Shortcut"), + 0, 0, w, UI_UNIT_Y, NULL, 0, 0, 0, 0, ""); + UI_but_func_set(but2, popup_change_shortcut_func, but, NULL); - but2 = uiDefIconTextBut(block, UI_BTYPE_BUT, 0, 0, CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Remove Shortcut"), - 0, 0, w, UI_UNIT_Y, NULL, 0, 0, 0, 0, ""); - UI_but_func_set(but2, remove_shortcut_func, but, NULL); + but2 = uiDefIconTextBut(block, UI_BTYPE_BUT, 0, ICON_NONE, + CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Remove Shortcut"), + 0, 0, w, UI_UNIT_Y, NULL, 0, 0, 0, 0, ""); + UI_but_func_set(but2, remove_shortcut_func, but, NULL); + } + else { + but2 = uiDefIconTextBut(block, UI_BTYPE_BUT, 0, ICON_NONE, IFACE_("Non-Keyboard Shortcut"), + 0, 0, w, UI_UNIT_Y, NULL, 0, 0, 0, 0, + TIP_("Only keyboard shortcuts can be edited that way, " + "please use User Preferences otherwise")); + UI_but_flag_enable(but2, UI_BUT_DISABLED); + } is_first_item = false; } /* only show 'add' if there's a suitable key map for it to go in */ else if (WM_keymap_guess_opname(C, but->optype->idname)) { - but2 = uiDefIconTextBut(block, UI_BTYPE_BUT, 0, 0, CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Add Shortcut"), + but2 = uiDefIconTextBut(block, UI_BTYPE_BUT, 0, ICON_NONE, + CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Add Shortcut"), 0, 0, w, UI_UNIT_Y, NULL, 0, 0, 0, 0, ""); UI_but_func_set(but2, popup_add_shortcut_func, but, NULL); @@ -7442,7 +7491,7 @@ static uiSubBut *ui_subbut_find_mouse_over(const ARegion *ar, const uiBut *but, } -static uiBut *ui_list_find_mouse_over(ARegion *ar, int x, int y) +static uiBut *ui_list_find_mouse_over_ex(ARegion *ar, int x, int y) { uiBlock *block; uiBut *but; @@ -7466,6 +7515,11 @@ static uiBut *ui_list_find_mouse_over(ARegion *ar, int x, int y) return NULL; } +static uiBut *ui_list_find_mouse_over(ARegion *ar, const wmEvent *event) +{ + return ui_list_find_mouse_over_ex(ar, event->x, event->y); +} + /* ****************** button state handling **************************/ static bool button_modal_state(uiHandleButtonState state) @@ -8353,21 +8407,15 @@ static int ui_handle_button_event(bContext *C, const wmEvent *event, uiBut *but) return retval; } -static int ui_handle_list_event(bContext *C, const wmEvent *event, ARegion *ar) +static int ui_handle_list_event(bContext *C, const wmEvent *event, ARegion *ar, uiBut *listbox) { - uiBut *but; uiList *ui_list; uiListDyn *dyn_data; int retval = WM_UI_HANDLER_CONTINUE; int type = event->type, val = event->val; int mx, my; - but = ui_list_find_mouse_over(ar, event->x, event->y); - if (!but) { - return retval; - } - - ui_list = but->custom_data; + ui_list = listbox->custom_data; if (!ui_list || !ui_list->dyn_data) { return retval; } @@ -8375,7 +8423,7 @@ static int ui_handle_list_event(bContext *C, const wmEvent *event, ARegion *ar) mx = event->x; my = event->y; - ui_window_to_block(ar, but->block, &mx, &my); + ui_window_to_block(ar, listbox->block, &mx, &my); /* convert pan to scrollwheel */ if (type == MOUSEPAN) { @@ -8391,7 +8439,7 @@ static int ui_handle_list_event(bContext *C, const wmEvent *event, ARegion *ar) if (ELEM(type, UPARROWKEY, DOWNARROWKEY) || ((ELEM(type, WHEELUPMOUSE, WHEELDOWNMOUSE) && event->ctrl))) { - const int value_orig = RNA_property_int_get(&but->rnapoin, but->rnaprop); + const int value_orig = RNA_property_int_get(&listbox->rnapoin, listbox->rnaprop); int value, min, max, inc; /* activate up/down the list */ @@ -8444,14 +8492,14 @@ static int ui_handle_list_event(bContext *C, const wmEvent *event, ARegion *ar) CLAMP(value, 0, dyn_data->items_len - 1); - RNA_property_int_range(&but->rnapoin, but->rnaprop, &min, &max); + RNA_property_int_range(&listbox->rnapoin, listbox->rnaprop, &min, &max); CLAMP(value, min, max); if (value != value_orig) { - RNA_property_int_set(&but->rnapoin, but->rnaprop, value); - RNA_property_update(C, &but->rnapoin, but->rnaprop); + RNA_property_int_set(&listbox->rnapoin, listbox->rnaprop, value); + RNA_property_update(C, &listbox->rnapoin, listbox->rnaprop); - ui_apply_but_undo(but); + ui_apply_but_undo(listbox); ui_list->flag |= UILST_SCROLL_TO_ACTIVE_ITEM; ED_region_tag_redraw(ar); @@ -8871,7 +8919,7 @@ static int ui_handle_menu_event( /* check if mouse is inside block */ inside = BLI_rctf_isect_pt(&block->rect, mx, my); - inside_title = inside && ((my + UI_MENU_TITLE_HEIGHT) > block->rect.ymax); + inside_title = inside && ((my + (UI_UNIT_Y * 1.5f)) > block->rect.ymax); /* if there's an active modal button, don't check events or outside, except for search menu */ but = ui_but_find_active_in_region(ar); @@ -9776,7 +9824,7 @@ static int ui_tab_region_handler(bContext *C, const wmEvent *event, ARegion *ar) static int ui_region_handler(bContext *C, const wmEvent *event, void *UNUSED(userdata)) { ARegion *ar; - uiBut *but; + uiBut *but, *listbox; int retval; /* here we handle buttons at the region level, non-modal */ @@ -9789,14 +9837,15 @@ static int ui_region_handler(bContext *C, const wmEvent *event, void *UNUSED(use /* either handle events for already activated button or try to activate */ but = ui_but_find_active_in_region(ar); + listbox = ui_list_find_mouse_over(ar, event); - retval = ui_handler_panel_region(C, event, ar); + retval = ui_handler_panel_region(C, event, ar, listbox ? listbox : but); if (retval == WM_UI_HANDLER_CONTINUE) retval = ui_tab_region_handler(C, event, ar); - if (retval == WM_UI_HANDLER_CONTINUE) - retval = ui_handle_list_event(C, event, ar); + if (retval == WM_UI_HANDLER_CONTINUE && listbox) + retval = ui_handle_list_event(C, event, ar, listbox); if (retval == WM_UI_HANDLER_CONTINUE) { if (but) diff --git a/source/blender/editors/interface/interface_intern.h b/source/blender/editors/interface/interface_intern.h index ac946606a9a..811b3583c5d 100644 --- a/source/blender/editors/interface/interface_intern.h +++ b/source/blender/editors/interface/interface_intern.h @@ -521,6 +521,7 @@ extern bool ui_but_is_unit(const uiBut *but) ATTR_WARN_UNUSED_RESULT; extern bool ui_but_is_compatible(const uiBut *but_a, const uiBut *but_b) ATTR_WARN_UNUSED_RESULT; extern bool ui_but_is_rna_valid(uiBut *but) ATTR_WARN_UNUSED_RESULT; extern bool ui_but_is_utf8(const uiBut *but) ATTR_WARN_UNUSED_RESULT; +extern bool ui_but_supports_cycling(const uiBut *but) ATTR_WARN_UNUSED_RESULT; extern int ui_but_is_pushed_ex(uiBut *but, double *value) ATTR_WARN_UNUSED_RESULT; extern int ui_but_is_pushed(uiBut *but) ATTR_WARN_UNUSED_RESULT; @@ -533,6 +534,7 @@ extern void ui_block_align_calc(uiBlock *block); extern struct ColorManagedDisplay *ui_block_cm_display_get(uiBlock *block); void ui_block_cm_to_display_space_v3(uiBlock *block, float pixel[3]); void ui_block_cm_to_scene_linear_v3(uiBlock *block, float pixel[3]); +void ui_block_cm_to_display_space_range(uiBlock *block, float *min, float *max); /* interface_regions.c */ @@ -641,11 +643,14 @@ uiPopupBlockHandle *ui_popup_menu_create( void ui_popup_block_free(struct bContext *C, uiPopupBlockHandle *handle); -int ui_but_menu_step(uiBut *but, int step); +int ui_but_menu_step(uiBut *but, int step); +bool ui_but_menu_step_poll(const uiBut *but); /* interface_panel.c */ -extern int ui_handler_panel_region(struct bContext *C, const struct wmEvent *event, struct ARegion *ar); +extern int ui_handler_panel_region( + struct bContext *C, const struct wmEvent *event, + struct ARegion *ar, const uiBut *active_but); extern void ui_draw_aligned_panel(struct uiStyle *style, uiBlock *block, const rcti *rect, const bool show_pin); /* interface_draw.c */ @@ -716,6 +721,8 @@ void ui_draw_preview_item(struct uiFontStyle *fstyle, rcti *rect, const char *na #define UI_TEXT_MARGIN_X 0.4f #define UI_POPUP_MARGIN (UI_DPI_FAC * 12) +/* margin at top of screen for popups */ +#define UI_POPUP_MENU_TOP (int)(8 * UI_DPI_FAC) /* interface_style.c */ void uiStyleInit(void); diff --git a/source/blender/editors/interface/interface_layout.c b/source/blender/editors/interface/interface_layout.c index 99a44f265ec..593138869a8 100644 --- a/source/blender/editors/interface/interface_layout.c +++ b/source/blender/editors/interface/interface_layout.c @@ -3455,6 +3455,10 @@ void uiLayoutOperatorButs( /* XXX, could give some nicer feedback or not show redo panel at all? */ uiItemL(layout, IFACE_("* Redo Unsupported *"), ICON_NONE); } + else { + /* useful for macros where only one of the steps can't be re-done */ + UI_block_lock_clear(uiLayoutGetBlock(layout)); + } /* menu */ if (op->type->flag & OPTYPE_PRESET) { diff --git a/source/blender/editors/interface/interface_panel.c b/source/blender/editors/interface/interface_panel.c index 076412d475f..d9f4689748f 100644 --- a/source/blender/editors/interface/interface_panel.c +++ b/source/blender/editors/interface/interface_panel.c @@ -1942,7 +1942,7 @@ void UI_panel_category_draw_all(ARegion *ar, const char *category_id_active) /* XXX should become modal keymap */ /* AKey is opening/closing panels, independent of button state now */ -int ui_handler_panel_region(bContext *C, const wmEvent *event, ARegion *ar) +int ui_handler_panel_region(bContext *C, const wmEvent *event, ARegion *ar, const uiBut *active_but) { uiBlock *block; Panel *pa; @@ -1970,20 +1970,26 @@ int ui_handler_panel_region(bContext *C, const wmEvent *event, ARegion *ar) /* first check if the mouse is in the tab region */ if (event->ctrl || (event->mval[0] < ((PanelCategoryDyn *)ar->panels_category.first)->rect.xmax)) { - const char *category = UI_panel_category_active_get(ar, false); - if (LIKELY(category)) { - PanelCategoryDyn *pc_dyn = UI_panel_category_find(ar, category); - if (LIKELY(pc_dyn)) { - pc_dyn = (event->type == WHEELDOWNMOUSE) ? pc_dyn->next : pc_dyn->prev; - if (pc_dyn) { - /* intentionally don't reset scroll in this case, - * this allows for quick browsing between tabs */ - UI_panel_category_active_set(ar, pc_dyn->idname); - ED_region_tag_redraw(ar); + if (active_but && ui_but_supports_cycling(active_but)) { + /* skip - exception to make cycling buttons + * using ctrl+mousewheel work in tabbed regions */ + } + else { + const char *category = UI_panel_category_active_get(ar, false); + if (LIKELY(category)) { + PanelCategoryDyn *pc_dyn = UI_panel_category_find(ar, category); + if (LIKELY(pc_dyn)) { + pc_dyn = (event->type == WHEELDOWNMOUSE) ? pc_dyn->next : pc_dyn->prev; + if (pc_dyn) { + /* intentionally don't reset scroll in this case, + * this allows for quick browsing between tabs */ + UI_panel_category_active_set(ar, pc_dyn->idname); + ED_region_tag_redraw(ar); + } } } + retval = WM_UI_HANDLER_BREAK; } - retval = WM_UI_HANDLER_BREAK; } } } diff --git a/source/blender/editors/interface/interface_regions.c b/source/blender/editors/interface/interface_regions.c index 24e6e17a89e..bfaf03cdce0 100644 --- a/source/blender/editors/interface/interface_regions.c +++ b/source/blender/editors/interface/interface_regions.c @@ -70,7 +70,6 @@ #include "interface_intern.h" -#define MENU_TOP (int)(8 * UI_DPI_FAC) #define MENU_PADDING (int)(0.2f * UI_UNIT_Y) #define MENU_BORDER (int)(0.3f * U.widget_unit) @@ -107,15 +106,22 @@ static int rna_property_enum_step(const bContext *C, PointerRNA *ptr, PropertyRN return value; } -int ui_but_menu_step(uiBut *but, int direction) +bool ui_but_menu_step_poll(const uiBut *but) { + BLI_assert(but->type == UI_BTYPE_MENU); + /* currenly only RNA buttons */ - if ((but->rnaprop == NULL) || (RNA_property_type(but->rnaprop) != PROP_ENUM)) { - printf("%s: cannot cycle button '%s'\n", __func__, but->str); - return 0; + return (but->rnaprop && RNA_property_type(but->rnaprop) == PROP_ENUM); +} + +int ui_but_menu_step(uiBut *but, int direction) +{ + if (ui_but_menu_step_poll(but)) { + return rna_property_enum_step(but->block->evil_C, &but->rnapoin, but->rnaprop, direction); } - return rna_property_enum_step(but->block->evil_C, &but->rnapoin, but->rnaprop, direction); + printf("%s: cannot cycle button '%s'\n", __func__, but->str); + return 0; } /******************** Creating Temporary regions ******************/ @@ -148,13 +154,14 @@ static void ui_region_temp_remove(bContext *C, bScreen *sc, ARegion *ar) #define UI_TIP_PAD_FAC 1.3f #define UI_TIP_PADDING (int)(UI_TIP_PAD_FAC * UI_UNIT_Y) +#define UI_TIP_MAXWIDTH 600 #define MAX_TOOLTIP_LINES 8 typedef struct uiTooltipData { rcti bbox; uiFontStyle fstyle; - char lines[MAX_TOOLTIP_LINES][512]; - char header[512], active_info[512]; + char lines[MAX_TOOLTIP_LINES][2048]; + char header[2048], active_info[2048]; struct { enum { UI_TIP_STYLE_NORMAL = 0, @@ -171,6 +178,14 @@ typedef struct uiTooltipData { } color_id : 4; int is_pad : 1; } format[MAX_TOOLTIP_LINES]; + + struct { + unsigned int x_pos; /* x cursor position at the end of the last line */ + unsigned int lines; /* number of lines, 1 or more with word-wrap */ + } line_geom[MAX_TOOLTIP_LINES]; + + int wrap_width; + int totline; int toth, lineh; } uiTooltipData; @@ -250,38 +265,48 @@ static void ui_tooltip_region_draw_cb(const bContext *UNUSED(C), ARegion *ar) rgb_tint(alert_color, 0.0f, 0.8f, tone_bg, 0.1f); /* red */ /* draw text */ + BLF_wordwrap(data->fstyle.uifont_id, data->wrap_width); + BLF_wordwrap(blf_mono_font, data->wrap_width); bbox.xmin += 0.5f * pad_px; /* add padding to the text */ - bbox.ymax -= 0.5f * (BLI_rcti_size_y(&bbox) - data->toth); - bbox.ymin = bbox.ymax - data->lineh; + bbox.ymax -= 0.25f * pad_px; for (i = 0; i < data->totline; i++) { + bbox.ymin = bbox.ymax - (data->lineh * data->line_geom[i].lines); if (data->format[i].style == UI_TIP_STYLE_HEADER) { /* draw header and active data (is done here to be able to change color) */ uiFontStyle fstyle_header = data->fstyle; - float xofs; + float xofs, yofs; /* override text-style */ fstyle_header.shadow = 1; fstyle_header.shadowcolor = rgb_to_grayscale(tip_colors[UI_TIP_LC_MAIN]); fstyle_header.shadx = fstyle_header.shady = 0; fstyle_header.shadowalpha = 1.0f; + fstyle_header.word_wrap = true; UI_fontstyle_set(&fstyle_header); glColor3fv(tip_colors[UI_TIP_LC_MAIN]); UI_fontstyle_draw(&fstyle_header, &bbox, data->header); - xofs = BLF_width(fstyle_header.uifont_id, data->header, sizeof(data->header)); + /* offset to the end of the last line */ + xofs = data->line_geom[i].x_pos; + yofs = data->lineh * (data->line_geom[i].lines - 1); bbox.xmin += xofs; + bbox.ymax -= yofs; glColor3fv(tip_colors[UI_TIP_LC_ACTIVE]); - UI_fontstyle_draw(&data->fstyle, &bbox, data->active_info); + fstyle_header.shadow = 0; + UI_fontstyle_draw(&fstyle_header, &bbox, data->active_info); + /* undo offset */ bbox.xmin -= xofs; + bbox.ymax += yofs; } 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' */ @@ -290,22 +315,26 @@ static void ui_tooltip_region_draw_cb(const bContext *UNUSED(C), ARegion *ar) UI_fontstyle_draw(&fstyle_mono, &bbox, data->lines[i]); } else { + uiFontStyle fstyle_normal = data->fstyle; BLI_assert(data->format[i].style == UI_TIP_STYLE_NORMAL); + fstyle_normal.word_wrap = true; + /* draw remaining data */ - UI_fontstyle_set(&data->fstyle); + UI_fontstyle_set(&fstyle_normal); glColor3fv(tip_colors[data->format[i].color_id]); - UI_fontstyle_draw(&data->fstyle, &bbox, data->lines[i]); + UI_fontstyle_draw(&fstyle_normal, &bbox, data->lines[i]); } + + bbox.ymax -= data->lineh * data->line_geom[i].lines; + if ((i + 1 != data->totline) && data->format[i + 1].is_pad) { - bbox.ymax -= data->lineh * UI_TIP_PAD_FAC; - bbox.ymin -= data->lineh * UI_TIP_PAD_FAC; - } - else { - bbox.ymax -= data->lineh; - bbox.ymin -= data->lineh; + bbox.ymax -= data->lineh * (UI_TIP_PAD_FAC - 1); } } + BLF_disable(data->fstyle.uifont_id, BLF_WORD_WRAP); + BLF_disable(blf_mono_font, BLF_WORD_WRAP); + if (multisample_enabled) glEnable(GL_MULTISAMPLE_ARB); } @@ -331,10 +360,11 @@ ARegion *ui_tooltip_create(bContext *C, ARegion *butregion, uiBut *but) char buf[512]; /* aspect values that shrink text are likely unreadable */ const float aspect = min_ff(1.0f, but->block->aspect); - float fonth, fontw; - int winx, ofsx, ofsy, w = 0, h, i; + int fonth, fontw; + int winx, ofsx, ofsy, h, i; rctf rect_fl; rcti rect_i; + int font_flag = 0; uiStringInfo but_tip = {BUT_GET_TIP, NULL}; uiStringInfo enum_label = {BUT_GET_RNAENUM_LABEL, NULL}; @@ -513,9 +543,10 @@ ARegion *ui_tooltip_create(bContext *C, ARegion *butregion, uiBut *but) } if (data_path) { + const char *data_delim = (data_path[0] == '[') ? "" : "."; BLI_snprintf(data->lines[data->totline], sizeof(data->lines[0]), - "%s.%s", /* no need to translate */ - id_path, data_path); + "%s%s%s", /* no need to translate */ + id_path, data_delim, data_path); MEM_freeN(data_path); } else if (prop) { @@ -570,6 +601,17 @@ ARegion *ui_tooltip_create(bContext *C, ARegion *butregion, uiBut *but) UI_fontstyle_set(&data->fstyle); + data->wrap_width = min_ii(UI_TIP_MAXWIDTH * U.pixelsize / aspect, WM_window_pixels_x(win) - (UI_TIP_PADDING * 2)); + + font_flag |= BLF_WORD_WRAP; + if (data->fstyle.kerning == 1) { + font_flag |= BLF_KERNING_DEFAULT; + } + BLF_enable(data->fstyle.uifont_id, font_flag); + BLF_enable(blf_mono_font, font_flag); + BLF_wordwrap(data->fstyle.uifont_id, data->wrap_width); + BLF_wordwrap(blf_mono_font, data->wrap_width); + /* these defines tweaked depending on font */ #define TIP_BORDER_X (16.0f / aspect) #define TIP_BORDER_Y (6.0f / aspect) @@ -577,33 +619,43 @@ ARegion *ui_tooltip_create(bContext *C, ARegion *butregion, uiBut *but) h = BLF_height_max(data->fstyle.uifont_id); for (i = 0, fontw = 0, fonth = 0; i < data->totline; i++) { + struct ResultBLF info; + int w, x_pos = 0; + if (data->format[i].style == UI_TIP_STYLE_HEADER) { - w = BLF_width(data->fstyle.uifont_id, data->header, sizeof(data->header)); - if (enum_label.strinfo) - w += BLF_width(data->fstyle.uifont_id, data->active_info, sizeof(data->active_info)); + w = BLF_width_ex(data->fstyle.uifont_id, data->header, sizeof(data->header), &info); + if (enum_label.strinfo) { + x_pos = info.width + (U.widget_unit / 2); + w = max_ii(w, x_pos + BLF_width(data->fstyle.uifont_id, data->active_info, sizeof(data->active_info))); + } } else if (data->format[i].style == UI_TIP_STYLE_MONO) { BLF_size(blf_mono_font, data->fstyle.points * U.pixelsize, U.dpi); - w = BLF_width(blf_mono_font, data->lines[i], sizeof(data->lines[i])); + w = BLF_width_ex(blf_mono_font, data->lines[i], sizeof(data->lines[i]), &info); } else { BLI_assert(data->format[i].style == UI_TIP_STYLE_NORMAL); - w = BLF_width(data->fstyle.uifont_id, data->lines[i], sizeof(data->lines[i])); + + w = BLF_width_ex(data->fstyle.uifont_id, data->lines[i], sizeof(data->lines[i]), &info); } - fontw = max_ff(fontw, (float)w); + fontw = max_ii(fontw, w); + fonth += h * info.lines; if ((i + 1 != data->totline) && data->format[i + 1].is_pad) { - fonth += h * UI_TIP_PAD_FAC; - } - else { - fonth += h; + fonth += h * (UI_TIP_PAD_FAC - 1); } + + data->line_geom[i].lines = info.lines; + data->line_geom[i].x_pos = x_pos; } //fontw *= aspect; + BLF_disable(data->fstyle.uifont_id, font_flag); + BLF_disable(blf_mono_font, font_flag); + ar->regiondata = data; data->toth = fonth; @@ -769,7 +821,7 @@ bool UI_search_item_add(uiSearchItems *items, const char *name, void *poin, int int UI_searchbox_size_y(void) { - return SEARCH_ITEMS * UI_UNIT_Y + 2 * MENU_TOP; + return SEARCH_ITEMS * UI_UNIT_Y + 2 * UI_POPUP_MENU_TOP; } int UI_searchbox_size_x(void) @@ -845,13 +897,13 @@ static void ui_searchbox_butrect(rcti *r_rect, uiSearchboxData *data, int itemnr } /* list view */ else { - int buth = (BLI_rcti_size_y(&data->bbox) - 2 * MENU_TOP) / SEARCH_ITEMS; + int buth = (BLI_rcti_size_y(&data->bbox) - 2 * UI_POPUP_MENU_TOP) / SEARCH_ITEMS; *r_rect = data->bbox; r_rect->xmin = data->bbox.xmin + 3.0f; r_rect->xmax = data->bbox.xmax - 3.0f; - r_rect->ymax = data->bbox.ymax - MENU_TOP - itemnr * buth; + r_rect->ymax = data->bbox.ymax - UI_POPUP_MENU_TOP - itemnr * buth; r_rect->ymin = r_rect->ymax - buth; } @@ -1591,8 +1643,8 @@ static void ui_popup_block_clip(wmWindow *window, uiBlock *block) if (block->rect.ymin < width) block->rect.ymin = width; - if (block->rect.ymax > winy - MENU_TOP) - block->rect.ymax = winy - MENU_TOP; + if (block->rect.ymax > winy - UI_POPUP_MENU_TOP) + block->rect.ymax = winy - UI_POPUP_MENU_TOP; /* ensure menu items draw inside left/right boundary */ for (bt = block->buttons.first; bt; bt = bt->next) { @@ -1779,7 +1831,7 @@ uiBlock *ui_popup_block_refresh( ar->winrct.xmin = block->rect.xmin - margin; ar->winrct.xmax = block->rect.xmax + margin; ar->winrct.ymin = block->rect.ymin - margin; - ar->winrct.ymax = block->rect.ymax + MENU_TOP; + ar->winrct.ymax = block->rect.ymax + UI_POPUP_MENU_TOP; ui_block_translate(block, -ar->winrct.xmin, -ar->winrct.ymin); } diff --git a/source/blender/editors/interface/interface_style.c b/source/blender/editors/interface/interface_style.c index 8dca148ffe6..25a187c43ad 100644 --- a/source/blender/editors/interface/interface_style.c +++ b/source/blender/editors/interface/interface_style.c @@ -152,13 +152,34 @@ void UI_fontstyle_draw_ex( const uiFontStyle *fs, const rcti *rect, const char *str, size_t len, float *r_xofs, float *r_yofs) { - float height; int xofs = 0, yofs; + int font_flag = BLF_CLIPPING; UI_fontstyle_set(fs); - height = BLF_ascender(fs->uifont_id); - yofs = ceil(0.5f * (BLI_rcti_size_y(rect) - height)); + /* set the flag */ + if (fs->shadow) { + font_flag |= BLF_SHADOW; + BLF_shadow(fs->uifont_id, fs->shadow, fs->shadowcolor, fs->shadowcolor, fs->shadowcolor, fs->shadowalpha); + BLF_shadow_offset(fs->uifont_id, fs->shadx, fs->shady); + } + if (fs->kerning == 1) { + font_flag |= BLF_KERNING_DEFAULT; + } + if (fs->word_wrap == 1) { + font_flag |= BLF_WORD_WRAP; + } + + BLF_enable(fs->uifont_id, font_flag); + + if (fs->word_wrap == 1) { + /* draw from boundbox top */ + yofs = BLI_rcti_size_y(rect) - BLF_height_max(fs->uifont_id); + } + else { + /* draw from boundbox center */ + yofs = ceil(0.5f * (BLI_rcti_size_y(rect) - BLF_ascender(fs->uifont_id))); + } if (fs->align == UI_STYLE_TEXT_CENTER) { xofs = floor(0.5f * (BLI_rcti_size_x(rect) - BLF_width(fs->uifont_id, str, len))); @@ -173,24 +194,11 @@ 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_enable(fs->uifont_id, BLF_CLIPPING); BLF_position(fs->uifont_id, rect->xmin + xofs, rect->ymin + yofs, 0.0f); - if (fs->shadow) { - BLF_enable(fs->uifont_id, BLF_SHADOW); - BLF_shadow(fs->uifont_id, fs->shadow, fs->shadowcolor, fs->shadowcolor, fs->shadowcolor, fs->shadowalpha); - BLF_shadow_offset(fs->uifont_id, fs->shadx, fs->shady); - } - - if (fs->kerning == 1) - BLF_enable(fs->uifont_id, BLF_KERNING_DEFAULT); - BLF_draw(fs->uifont_id, str, len); - BLF_disable(fs->uifont_id, BLF_CLIPPING); - if (fs->shadow) - BLF_disable(fs->uifont_id, BLF_SHADOW); - if (fs->kerning == 1) - BLF_disable(fs->uifont_id, BLF_KERNING_DEFAULT); + + BLF_disable(fs->uifont_id, font_flag); *r_xofs = xofs; *r_yofs = yofs; diff --git a/source/blender/editors/interface/interface_templates.c b/source/blender/editors/interface/interface_templates.c index f4618d8e5ff..e69fbf7fb8f 100644 --- a/source/blender/editors/interface/interface_templates.c +++ b/source/blender/editors/interface/interface_templates.c @@ -3486,7 +3486,8 @@ void uiTemplateReportsBanner(uiLayout *layout, bContext *C) ui_abs = uiLayoutAbsolute(layout, false); block = uiLayoutGetBlock(ui_abs); - width = BLF_width(style->widget.uifont_id, report->message, report->len); + UI_fontstyle_set(&style->widgetlabel); + width = BLF_width(style->widgetlabel.uifont_id, report->message, report->len); width = min_ii((int)(rti->widthfac * width), width); width = max_ii(width, 10); diff --git a/source/blender/editors/interface/interface_widgets.c b/source/blender/editors/interface/interface_widgets.c index a7592276256..008f129904b 100644 --- a/source/blender/editors/interface/interface_widgets.c +++ b/source/blender/editors/interface/interface_widgets.c @@ -206,7 +206,7 @@ void ui_draw_anti_tria(float x1, float y1, float x2, float y2, float x3, float y /* for each AA step */ for (j = 0; j < WIDGET_AA_JITTER; j++) { - glTranslatef(jit[j][0], jit[j][1], 0.0f); + glTranslate2fv(jit[j]); glDrawArrays(GL_TRIANGLES, 0, 3); glTranslatef(-jit[j][0], -jit[j][1], 0.0f); } @@ -229,7 +229,7 @@ void ui_draw_anti_roundbox(int mode, float minx, float miny, float maxx, float m glColor4fv(color); for (j = 0; j < WIDGET_AA_JITTER; j++) { - glTranslatef(jit[j][0], jit[j][1], 0.0f); + glTranslate2fv(jit[j]); UI_draw_roundbox_gl_mode(mode, minx, miny, maxx, maxy, rad); glTranslatef(-jit[j][0], -jit[j][1], 0.0f); } @@ -816,7 +816,7 @@ static void widgetbase_draw(uiWidgetBase *wtb, uiWidgetColors *wcol) for (j = 0; j < WIDGET_AA_JITTER; j++) { unsigned char emboss[4]; - glTranslatef(jit[j][0], jit[j][1], 0.0f); + glTranslate2fv(jit[j]); /* outline */ glColor4ubv(tcol); @@ -850,7 +850,7 @@ static void widgetbase_draw(uiWidgetBase *wtb, uiWidgetColors *wcol) /* for each AA step */ for (j = 0; j < WIDGET_AA_JITTER; j++) { - glTranslatef(jit[j][0], jit[j][1], 0.0f); + glTranslate2fv(jit[j]); if (wtb->tria1.tot) { glColor4ubv(tcol); @@ -2910,8 +2910,11 @@ static void ui_draw_but_HSV_v(uiBut *but, const rcti *rect) /* map v from property range to [0,1] */ if (but->a1 == UI_GRAD_V_ALT) { - float range = but->softmax - but->softmin; - v = (v - but->softmin) / range; + float min = but->softmin, max = but->softmax; + if (color_profile) { + ui_block_cm_to_display_space_range(but->block, &min, &max); + } + v = (v - min) / (max - min); } widget_init(&wtb); diff --git a/source/blender/editors/interface/resources.c b/source/blender/editors/interface/resources.c index 02f4eb171a4..c19cef6fadc 100644 --- a/source/blender/editors/interface/resources.c +++ b/source/blender/editors/interface/resources.c @@ -1083,7 +1083,7 @@ void ui_theme_init_default(void) rgba_char_args_set(btheme->tima.face, 255, 255, 255, 10); rgba_char_args_set(btheme->tima.face_select, 255, 133, 0, 60); rgba_char_args_set(btheme->tima.editmesh_active, 255, 255, 255, 128); - rgba_char_args_set_fl(btheme->tima.preview_back, 0.45, 0.45, 0.45, 1.0); + rgba_char_args_set_fl(btheme->tima.preview_back, 0.0, 0.0, 0.0, 0.3); rgba_char_args_set_fl(btheme->tima.preview_stitch_face, 0.5, 0.5, 0.0, 0.2); rgba_char_args_set_fl(btheme->tima.preview_stitch_edge, 1.0, 0.0, 1.0, 0.2); rgba_char_args_set_fl(btheme->tima.preview_stitch_vert, 0.0, 0.0, 1.0, 0.2); @@ -2492,10 +2492,10 @@ void init_userdef_do_versions(void) ThemeSpace *ts; for (ts = UI_THEMESPACE_START(btheme); ts != UI_THEMESPACE_END(btheme); ts++) { - rgba_char_args_set(ts->tabs.tab_active, 114, 114, 114, 255); - rgba_char_args_set(ts->tabs.tab_inactive, 83, 83, 83, 255); - rgba_char_args_set(ts->tabs.tab_back, 64, 64, 64, 255); - rgba_char_args_set(ts->tabs.tab_outline, 60, 60, 60, 255); + rgba_char_args_set(ts->tab_active, 114, 114, 114, 255); + rgba_char_args_set(ts->tab_inactive, 83, 83, 83, 255); + rgba_char_args_set(ts->tab_back, 64, 64, 64, 255); + rgba_char_args_set(ts->tab_outline, 60, 60, 60, 255); } } } @@ -2633,7 +2633,14 @@ void init_userdef_do_versions(void) U.node_margin = 80; } - if (!USER_VERSION_ATLEAST(275, 6)) { + if (!USER_VERSION_ATLEAST(276, 1)) { + bTheme *btheme; + for (btheme = U.themes.first; btheme; btheme = btheme->next) { + rgba_char_args_set_fl(btheme->tima.preview_back, 0.0f, 0.0f, 0.0f, 0.3f); + } + } + + if (!USER_VERSION_ATLEAST(276, 2)) { bTheme *btheme; ThemeSpace *ts; @@ -2662,7 +2669,7 @@ void init_userdef_do_versions(void) } } - if (!USER_VERSION_ATLEAST(275, 6)) { + if (!USER_VERSION_ATLEAST(276, 2)) { bTheme *btheme; ThemeSpace *ts; @@ -2682,7 +2689,7 @@ void init_userdef_do_versions(void) } } - if (!USER_VERSION_ATLEAST(275, 5)) { + if (!USER_VERSION_ATLEAST(276, 2)) { bTheme *btheme; for (btheme = U.themes.first; btheme; btheme = btheme->next) { rgba_char_args_set_fl(btheme->tui.xaxis, 1.0f, 0.27f, 0.27f, 1.0f); /* red */ diff --git a/source/blender/editors/interface/view2d.c b/source/blender/editors/interface/view2d.c index 2c56ef0aecb..d966cedc133 100644 --- a/source/blender/editors/interface/view2d.c +++ b/source/blender/editors/interface/view2d.c @@ -63,7 +63,7 @@ #include "interface_intern.h" -static void ui_view2d_curRect_validate_resize(View2D *v2d, int resize, int mask_scrollers); +static void ui_view2d_curRect_validate_resize(View2D *v2d, bool resize, bool mask_scrollers); /* *********************************************************************** */ @@ -116,7 +116,7 @@ static int view2d_scroll_mapped(int scroll) } /* called each time cur changes, to dynamically update masks */ -static void view2d_masks(View2D *v2d, int check_scrollers) +static void view2d_masks(View2D *v2d, bool check_scrollers) { int scroll; @@ -372,7 +372,7 @@ void UI_view2d_region_reinit(View2D *v2d, short type, int winx, int winy) * 'cur' is not allowed to be: larger than max, smaller than min, or outside of 'tot' */ // XXX pre2.5 -> this used to be called test_view2d() -static void ui_view2d_curRect_validate_resize(View2D *v2d, int resize, int mask_scrollers) +static void ui_view2d_curRect_validate_resize(View2D *v2d, bool resize, bool mask_scrollers) { float totwidth, totheight, curwidth, curheight, width, height; float winx, winy; @@ -476,7 +476,7 @@ static void ui_view2d_curRect_validate_resize(View2D *v2d, int resize, int mask_ /* check if we should restore aspect ratio (if view size changed) */ if (v2d->keepzoom & V2D_KEEPASPECT) { bool do_x = false, do_y = false, do_cur /* , do_win */ /* UNUSED */; - float /* curRatio, */ /* UNUSED */ winRatio; + float curRatio, winRatio; /* when a window edge changes, the aspect ratio can't be used to * find which is the best new 'cur' rect. thats why it stores 'old' @@ -484,7 +484,7 @@ static void ui_view2d_curRect_validate_resize(View2D *v2d, int resize, int mask_ if (winx != v2d->oldwinx) do_x = true; if (winy != v2d->oldwiny) do_y = true; - /* curRatio = height / width; */ /* UNUSED */ + curRatio = height / width; winRatio = winy / winx; /* both sizes change (area/region maximized) */ @@ -494,7 +494,7 @@ static void ui_view2d_curRect_validate_resize(View2D *v2d, int resize, int mask_ if (fabsf(winx - v2d->oldwinx) > fabsf(winy - v2d->oldwiny)) do_y = false; else do_x = false; } - else if (winRatio > 1.0f) { + else if (winRatio > curRatio) { do_x = false; } else { @@ -903,7 +903,7 @@ void UI_view2d_curRect_reset(View2D *v2d) /* ------------------ */ /* Change the size of the maximum viewable area (i.e. 'tot' rect) */ -void UI_view2d_totRect_set_resize(View2D *v2d, int width, int height, int resize) +void UI_view2d_totRect_set_resize(View2D *v2d, int width, int height, bool resize) { // int scroll = view2d_scroll_mapped(v2d->scroll); diff --git a/source/blender/editors/interface/view2d_ops.c b/source/blender/editors/interface/view2d_ops.c index 726678cd4e8..2ebdf467ceb 100644 --- a/source/blender/editors/interface/view2d_ops.c +++ b/source/blender/editors/interface/view2d_ops.c @@ -616,15 +616,20 @@ static int view_zoom_poll(bContext *C) /* check if there's a region in context to work with */ if (ar == NULL) - return 0; + return false; + + /* Do not show that in 3DView context. */ + if (CTX_wm_region_view3d(C)) + return false; + v2d = &ar->v2d; /* check that 2d-view is zoomable */ if ((v2d->keepzoom & V2D_LOCKZOOM_X) && (v2d->keepzoom & V2D_LOCKZOOM_Y)) - return 0; + return false; /* view is zoomable */ - return 1; + return true; } /* apply transform to view (i.e. adjust 'cur' rect) */ diff --git a/source/blender/editors/mask/mask_add.c b/source/blender/editors/mask/mask_add.c index 2dae9561d4e..822bb429f9e 100644 --- a/source/blender/editors/mask/mask_add.c +++ b/source/blender/editors/mask/mask_add.c @@ -74,7 +74,7 @@ bool ED_mask_find_nearest_diff_point(const bContext *C, MaskSplinePoint *point = NULL; float dist_best_sq = FLT_MAX, co[2]; int width, height; - float u; + float u = 0.0f; float scalex, scaley; ED_mask_get_size(sa, &width, &height); diff --git a/source/blender/editors/mask/mask_ops.c b/source/blender/editors/mask/mask_ops.c index 929c4f74b2f..bf8630ff843 100644 --- a/source/blender/editors/mask/mask_ops.c +++ b/source/blender/editors/mask/mask_ops.c @@ -516,7 +516,7 @@ static bool spline_under_mouse_get(const bContext *C, MaskLayer *mask_layer; int width, height; float pixel_co[2]; - float closest_dist_squared; + float closest_dist_squared = 0.0f; MaskLayer *closest_layer = NULL; MaskSpline *closest_spline = NULL; bool undistort = false; @@ -2209,7 +2209,7 @@ static int mask_duplicate_exec(bContext *C, wmOperator *UNUSED(op)) } if (end >= start) { int tot_point; - int tot_point_shape_start; + int tot_point_shape_start = 0; MaskSpline *new_spline = BKE_mask_spline_add(mask_layer); MaskSplinePoint *new_point; int b; diff --git a/source/blender/editors/mesh/editmesh_knife.c b/source/blender/editors/mesh/editmesh_knife.c index 787b79f0d6e..621155bc696 100644 --- a/source/blender/editors/mesh/editmesh_knife.c +++ b/source/blender/editors/mesh/editmesh_knife.c @@ -209,6 +209,8 @@ typedef struct KnifeTool_OpData { bool is_ortho; float ortho_extent; + float ortho_extent_center[3]; + float clipsta, clipend; enum { @@ -226,14 +228,8 @@ typedef struct KnifeTool_OpData { /* use to check if we're currently dragging an angle snapped line */ bool is_angle_snapping; - - enum { - ANGLE_FREE, - ANGLE_0, - ANGLE_45, - ANGLE_90, - ANGLE_135 - } angle_snapping; + bool angle_snapping; + float angle; const float (*cagecos)[3]; } KnifeTool_OpData; @@ -941,98 +937,66 @@ static void knife_finish_cut(KnifeTool_OpData *kcd) static void knifetool_draw_angle_snapping(const KnifeTool_OpData *kcd) { - bglMats mats; - double u[3], u1[2], u2[2], v1[3], v2[3], dx, dy; - double wminx, wminy, wmaxx, wmaxy; - - /* make u the window coords of prevcage */ - view3d_get_transformation(kcd->ar, kcd->vc.rv3d, kcd->ob, &mats); - gluProject(kcd->prev.cage[0], kcd->prev.cage[1], kcd->prev.cage[2], - mats.modelview, mats.projection, mats.viewport, - &u[0], &u[1], &u[2]); - - /* make u1, u2 the points on window going through u at snap angle */ - wminx = kcd->ar->winrct.xmin; - wmaxx = kcd->ar->winrct.xmin + kcd->ar->winx; - wminy = kcd->ar->winrct.ymin; - wmaxy = kcd->ar->winrct.ymin + kcd->ar->winy; - - switch (kcd->angle_snapping) { - case ANGLE_0: - u1[0] = wminx; - u2[0] = wmaxx; - u1[1] = u2[1] = u[1]; - break; - case ANGLE_90: - u1[0] = u2[0] = u[0]; - u1[1] = wminy; - u2[1] = wmaxy; - break; - case ANGLE_45: - /* clip against left or bottom */ - dx = u[0] - wminx; - dy = u[1] - wminy; - if (dy > dx) { - u1[0] = wminx; - u1[1] = u[1] - dx; - } - else { - u1[0] = u[0] - dy; - u1[1] = wminy; - } - /* clip against right or top */ - dx = wmaxx - u[0]; - dy = wmaxy - u[1]; - if (dy > dx) { - u2[0] = wmaxx; - u2[1] = u[1] + dx; - } - else { - u2[0] = u[0] + dy; - u2[1] = wmaxy; - } - break; - case ANGLE_135: - /* clip against right or bottom */ - dx = wmaxx - u[0]; - dy = u[1] - wminy; - if (dy > dx) { - u1[0] = wmaxx; - u1[1] = u[1] - dx; - } - else { - u1[0] = u[0] + dy; - u1[1] = wminy; - } - /* clip against left or top */ - dx = u[0] - wminx; - dy = wmaxy - u[1]; - if (dy > dx) { - u2[0] = wminx; - u2[1] = u[1] + dx; - } - else { - u2[0] = u[0] - dy; - u2[1] = wmaxy; + float v1[3], v2[3]; + float planes[4][4]; + + planes_from_projmat( + (float (*)[4])kcd->projmat, + planes[2], planes[0], planes[3], planes[1], NULL, NULL); + + /* ray-cast all planes */ + { + float ray_dir[3]; + float ray_hit_best[2][3] = {{UNPACK3(kcd->prev.cage)}, {UNPACK3(kcd->curr.cage)}}; + float lambda_best[2] = {-FLT_MAX, FLT_MAX}; + int i; + + /* we (sometimes) need the lines to be at the same depth before projecting */ +#if 0 + sub_v3_v3v3(ray_dir, kcd->curr.cage, kcd->prev.cage); +#else + { + float curr_cage_adjust[3]; + float co_depth[3]; + + copy_v3_v3(co_depth, kcd->prev.cage); + mul_m4_v3(kcd->ob->obmat, co_depth); + ED_view3d_win_to_3d(kcd->ar, co_depth, kcd->curr.mval, curr_cage_adjust); + mul_m4_v3(kcd->ob->imat, curr_cage_adjust); + + sub_v3_v3v3(ray_dir, curr_cage_adjust, kcd->prev.cage); + } +#endif + + for (i = 0; i < 4; i++) { + float ray_hit[3]; + float lambda_test; + if (isect_ray_plane_v3(kcd->prev.cage, ray_dir, planes[i], &lambda_test, false)) { + madd_v3_v3v3fl(ray_hit, kcd->prev.cage, ray_dir, lambda_test); + if (lambda_test < 0.0f) { + if (lambda_test > lambda_best[0]) { + copy_v3_v3(ray_hit_best[0], ray_hit); + lambda_best[0] = lambda_test; + } + } + else { + if (lambda_test < lambda_best[1]) { + copy_v3_v3(ray_hit_best[1], ray_hit); + lambda_best[1] = lambda_test; + } + } } - break; - default: - return; - } + } - /* unproject u1 and u2 back into object space */ - gluUnProject(u1[0], u1[1], 0.0, - mats.modelview, mats.projection, mats.viewport, - &v1[0], &v1[1], &v1[2]); - gluUnProject(u2[0], u2[1], 0.0, - mats.modelview, mats.projection, mats.viewport, - &v2[0], &v2[1], &v2[2]); + copy_v3_v3(v1, ray_hit_best[0]); + copy_v3_v3(v2, ray_hit_best[1]); + } UI_ThemeColor(TH_TRANSFORM); glLineWidth(2.0); glBegin(GL_LINES); - glVertex3dv(v1); - glVertex3dv(v2); + glVertex3fv(v1); + glVertex3fv(v2); glEnd(); } @@ -1065,7 +1029,7 @@ static void knifetool_draw(const bContext *C, ARegion *UNUSED(ar), void *arg) glMultMatrixf(kcd->ob->obmat); if (kcd->mode == MODE_DRAGGING) { - if (kcd->angle_snapping != ANGLE_FREE) + if (kcd->is_angle_snapping) knifetool_draw_angle_snapping(kcd); glColor3ubv(kcd->colors.line); @@ -1281,20 +1245,29 @@ static bool knife_ray_intersect_face( return false; } -/* Calculate maximum excursion from (0,0,0) of mesh */ +/** + * Calculate the center and maximum excursion of mesh. + */ static void calc_ortho_extent(KnifeTool_OpData *kcd) { BMIter iter; BMVert *v; BMesh *bm = kcd->em->bm; - float max_xyz = 0.0f; - int i; + float min[3], max[3]; - BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) { - for (i = 0; i < 3; i++) - max_xyz = max_ff(max_xyz, fabsf(v->co[i])); + INIT_MINMAX(min, max); + + if (kcd->cagecos) { + minmax_v3v3_v3_array(min, max, kcd->cagecos, bm->totvert); + } + else { + BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) { + minmax_v3v3_v3(min, max, v->co); + } } - kcd->ortho_extent = max_xyz; + + kcd->ortho_extent = len_v3v3(min, max) / 2; + mid_v3_v3v3(kcd->ortho_extent_center, min, max); } static BMElem *bm_elem_from_knife_vert(KnifeVert *kfv, KnifeEdge **r_kfe) @@ -1482,14 +1455,20 @@ static bool point_is_visible( /* Clip the line (v1, v2) to planes perpendicular to it and distances d from * the closest point on the line to the origin */ -static void clip_to_ortho_planes(float v1[3], float v2[3], float d) +static void clip_to_ortho_planes(float v1[3], float v2[3], const float center[3], const float d) { - float closest[3]; - const float origin[3] = {0.0f, 0.0f, 0.0f}; + float closest[3], dir[3]; + + sub_v3_v3v3(dir, v1, v2); + normalize_v3(dir); + + /* could be v1 or v2 */ + sub_v3_v3(v1, center); + project_plane_v3_v3v3(closest, v1, dir); + add_v3_v3(closest, center); - closest_to_line_v3(closest, origin, v1, v2); - dist_ensure_v3_v3fl(v1, closest, d); - dist_ensure_v3_v3fl(v2, closest, d); + madd_v3_v3v3fl(v1, closest, dir, d); + madd_v3_v3v3fl(v2, closest, dir, -d); } static void set_linehit_depth(KnifeTool_OpData *kcd, KnifeLineHit *lh) @@ -1573,8 +1552,8 @@ static void knife_find_line_hits(KnifeTool_OpData *kcd) if (kcd->is_ortho && (kcd->vc.rv3d->persp != RV3D_CAMOB)) { if (kcd->ortho_extent == 0.0f) calc_ortho_extent(kcd); - clip_to_ortho_planes(v1, v3, kcd->ortho_extent + 10.0f); - clip_to_ortho_planes(v2, v4, kcd->ortho_extent + 10.0f); + clip_to_ortho_planes(v1, v3, kcd->ortho_extent_center, kcd->ortho_extent + 10.0f); + clip_to_ortho_planes(v2, v4, kcd->ortho_extent_center, kcd->ortho_extent + 10.0f); } /* First use bvh tree to find faces, knife edges, and knife verts that might @@ -2124,42 +2103,41 @@ static KnifeVert *knife_find_closest_vert(KnifeTool_OpData *kcd, float p[3], flo return NULL; } +/** + * Snaps a 2d vector to an angle, relative to \a v_ref. + */ +static float snap_v2_angle(float r[2], const float v[2], const float v_ref[2], float angle_snap) +{ + float m2[2][2]; + float v_unit[2]; + float angle, angle_delta; + + BLI_ASSERT_UNIT_V2(v_ref); + + normalize_v2_v2(v_unit, v); + angle = angle_signed_v2v2(v_unit, v_ref); + angle_delta = (roundf(angle / angle_snap) * angle_snap) - angle; + rotate_m2(m2, angle_delta); + + mul_v2_m2v2(r, m2, v); + return angle + angle_delta; +} + /* update both kcd->curr.mval and kcd->mval to snap to required angle */ static bool knife_snap_angle(KnifeTool_OpData *kcd) { - float dx, dy; - float w, abs_tan; + const float dvec_ref[2] = {0.0f, 1.0f}; + float dvec[2], dvec_snap[2]; + float snap_step = DEG2RADF(45); - dx = kcd->curr.mval[0] - kcd->prev.mval[0]; - dy = kcd->curr.mval[1] - kcd->prev.mval[1]; - if (dx == 0.0f && dy == 0.0f) + sub_v2_v2v2(dvec, kcd->curr.mval, kcd->prev.mval); + if (is_zero_v2(dvec)) { return false; - - if (dx == 0.0f) { - kcd->angle_snapping = ANGLE_90; - kcd->curr.mval[0] = kcd->prev.mval[0]; } - w = dy / dx; - abs_tan = fabsf(w); - if (abs_tan <= 0.4142f) { /* tan(22.5 degrees) = 0.4142 */ - kcd->angle_snapping = ANGLE_0; - kcd->curr.mval[1] = kcd->prev.mval[1]; - } - else if (abs_tan < 2.4142f) { /* tan(67.5 degrees) = 2.4142 */ - if (w > 0) { - kcd->angle_snapping = ANGLE_45; - kcd->curr.mval[1] = kcd->prev.mval[1] + dx; - } - else { - kcd->angle_snapping = ANGLE_135; - kcd->curr.mval[1] = kcd->prev.mval[1] - dx; - } - } - else { - kcd->angle_snapping = ANGLE_90; - kcd->curr.mval[0] = kcd->prev.mval[0]; - } + kcd->angle = snap_v2_angle(dvec_snap, dvec, dvec_ref, snap_step); + + add_v2_v2v2(kcd->curr.mval, kcd->prev.mval, dvec_snap); copy_v2_v2(kcd->mval, kcd->curr.mval); @@ -2175,7 +2153,7 @@ static int knife_update_active(KnifeTool_OpData *kcd) /* view matrix may have changed, reproject */ knife_project_v2(kcd, kcd->prev.cage, kcd->prev.mval); - if (kcd->angle_snapping != ANGLE_FREE && kcd->mode == MODE_DRAGGING) { + if (kcd->angle_snapping && (kcd->mode == MODE_DRAGGING)) { kcd->is_angle_snapping = knife_snap_angle(kcd); } else { diff --git a/source/blender/editors/mesh/editmesh_loopcut.c b/source/blender/editors/mesh/editmesh_loopcut.c index 50257d250dc..593e27ff69d 100644 --- a/source/blender/editors/mesh/editmesh_loopcut.c +++ b/source/blender/editors/mesh/editmesh_loopcut.c @@ -401,7 +401,7 @@ static void ringsel_finish(bContext *C, wmOperator *op) { RingSelOpData *lcd = op->customdata; const int cuts = RNA_int_get(op->ptr, "number_cuts"); - const float smoothness = 0.292f * RNA_float_get(op->ptr, "smoothness"); + const float smoothness = RNA_float_get(op->ptr, "smoothness"); const int smooth_falloff = RNA_enum_get(op->ptr, "falloff"); #ifdef BMW_EDGERING_NGON const bool use_only_quads = false; @@ -430,8 +430,9 @@ static void ringsel_finish(bContext *C, wmOperator *op) cuts, seltype, SUBD_CORNER_PATH, 0, true, use_only_quads, 0); - /* when used in a macro tessface is already re-recalculated */ - EDBM_update_generic(em, (is_macro == false), true); + /* when used in a macro the tessfaces will be recalculated anyway, + * this is needed here because modifiers depend on updated tessellation, see T45920 */ + EDBM_update_generic(em, true, true); if (is_single) { /* de-select endpoints */ diff --git a/source/blender/editors/mesh/editmesh_select.c b/source/blender/editors/mesh/editmesh_select.c index eac5e3fece0..1169c91bf66 100644 --- a/source/blender/editors/mesh/editmesh_select.c +++ b/source/blender/editors/mesh/editmesh_select.c @@ -2013,7 +2013,7 @@ void EDBM_selectmode_set(BMEditMesh *em) /** * Expand & Contract the Selection - * (used when chaning modes and Ctrl key held) + * (used when changing modes and Ctrl key held) * * Flush the selection up: * - vert -> edge @@ -2389,6 +2389,15 @@ static bool select_linked_delimit_test( return false; } +static void select_linked_delimit_validate(BMesh *bm, int *delimit) +{ + if ((*delimit) & BMO_DELIM_UV) { + if (!CustomData_has_layer(&bm->ldata, CD_MLOOPUV)) { + (*delimit) &= ~BMO_DELIM_UV; + } + } +} + static void select_linked_delimit_begin(BMesh *bm, short selectmode, int delimit) { struct DelimitData delimit_data = {0}; @@ -2441,7 +2450,9 @@ static int edbm_select_linked_exec(bContext *C, wmOperator *op) BMIter iter; BMWalker walker; - const int delimit = RNA_enum_get(op->ptr, "delimit"); + int delimit = RNA_enum_get(op->ptr, "delimit"); + + select_linked_delimit_validate(bm, &delimit); if (delimit) { select_linked_delimit_begin(em->bm, em->selectmode, delimit); @@ -2607,6 +2618,8 @@ static void edbm_select_linked_pick_ex( BMesh *bm = em->bm; BMWalker walker; + select_linked_delimit_validate(bm, &delimit); + if (delimit) { select_linked_delimit_begin(bm, em->selectmode, delimit); } @@ -3538,13 +3551,16 @@ static int edbm_select_random_exec(bContext *C, wmOperator *op) BMEditMesh *em = BKE_editmesh_from_object(obedit); const bool select = (RNA_enum_get(op->ptr, "action") == SEL_SELECT); const float randfac = RNA_float_get(op->ptr, "percent") / 100.0f; + const int seed = RNA_int_get(op->ptr, "seed"); BMIter iter; + RNG *rng = BLI_rng_new_srandom(seed); + if (em->selectmode & SCE_SELECT_VERTEX) { BMVert *eve; BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) { - if (!BM_elem_flag_test(eve, BM_ELEM_HIDDEN) && BLI_frand() < randfac) { + if (!BM_elem_flag_test(eve, BM_ELEM_HIDDEN) && BLI_rng_get_float(rng) < randfac) { BM_vert_select_set(em->bm, eve, select); } } @@ -3552,7 +3568,7 @@ static int edbm_select_random_exec(bContext *C, wmOperator *op) else if (em->selectmode & SCE_SELECT_EDGE) { BMEdge *eed; BM_ITER_MESH (eed, &iter, em->bm, BM_EDGES_OF_MESH) { - if (!BM_elem_flag_test(eed, BM_ELEM_HIDDEN) && BLI_frand() < randfac) { + if (!BM_elem_flag_test(eed, BM_ELEM_HIDDEN) && BLI_rng_get_float(rng) < randfac) { BM_edge_select_set(em->bm, eed, select); } } @@ -3560,12 +3576,14 @@ static int edbm_select_random_exec(bContext *C, wmOperator *op) else { BMFace *efa; BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - if (!BM_elem_flag_test(efa, BM_ELEM_HIDDEN) && BLI_frand() < randfac) { + if (!BM_elem_flag_test(efa, BM_ELEM_HIDDEN) && BLI_rng_get_float(rng) < randfac) { BM_face_select_set(em->bm, efa, select); } } } + BLI_rng_free(rng); + if (select) { /* was EDBM_select_flush, but it over select in edge/face mode */ EDBM_selectmode_flush(em); @@ -3594,9 +3612,7 @@ void MESH_OT_select_random(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; /* props */ - RNA_def_float_percentage(ot->srna, "percent", 50.0f, 0.0f, 100.0f, - "Percent", "Percentage of elements to select randomly", 0.0f, 100.0f); - WM_operator_properties_select_action_simple(ot, SEL_SELECT); + WM_operator_properties_select_random(ot); } static int edbm_select_ungrouped_poll(bContext *C) diff --git a/source/blender/editors/mesh/editmesh_tools.c b/source/blender/editors/mesh/editmesh_tools.c index d3937188358..67c23a9f7a1 100644 --- a/source/blender/editors/mesh/editmesh_tools.c +++ b/source/blender/editors/mesh/editmesh_tools.c @@ -85,7 +85,7 @@ static int edbm_subdivide_exec(bContext *C, wmOperator *op) Object *obedit = CTX_data_edit_object(C); BMEditMesh *em = BKE_editmesh_from_object(obedit); const int cuts = RNA_int_get(op->ptr, "number_cuts"); - float smooth = 0.292f * RNA_float_get(op->ptr, "smoothness"); + float smooth = RNA_float_get(op->ptr, "smoothness"); const float fractal = RNA_float_get(op->ptr, "fractal") / 2.5f; const float along_normal = RNA_float_get(op->ptr, "fractal_along_normal"); @@ -96,7 +96,7 @@ static int edbm_subdivide_exec(bContext *C, wmOperator *op) } BM_mesh_esubdivide(em->bm, BM_ELEM_SELECT, - smooth, SUBD_FALLOFF_INVSQUARE, false, + smooth, SUBD_FALLOFF_LIN, false, fractal, along_normal, cuts, SUBDIV_SELECT_ORIG, RNA_enum_get(op->ptr, "quadcorner"), diff --git a/source/blender/editors/mesh/editmesh_utils.c b/source/blender/editors/mesh/editmesh_utils.c index d521b2c01e5..c101b416169 100644 --- a/source/blender/editors/mesh/editmesh_utils.c +++ b/source/blender/editors/mesh/editmesh_utils.c @@ -671,7 +671,7 @@ UvVertMap *BM_uv_vert_map_create( float (*tf_uv)[2]; if (use_winding) { - tf_uv = (float (*)[2])BLI_buffer_resize_data(&tf_uv_buf, vec2f, efa->len); + tf_uv = (float (*)[2])BLI_buffer_reinit_data(&tf_uv_buf, vec2f, efa->len); } BM_ITER_ELEM_INDEX(l, &liter, efa, BM_LOOPS_OF_FACE, i) { @@ -823,7 +823,7 @@ UvElementMap *BM_uv_element_map_create( float (*tf_uv)[2]; if (use_winding) { - tf_uv = (float (*)[2])BLI_buffer_resize_data(&tf_uv_buf, vec2f, efa->len); + tf_uv = (float (*)[2])BLI_buffer_reinit_data(&tf_uv_buf, vec2f, efa->len); } BM_ITER_ELEM_INDEX (l, &liter, efa, BM_LOOPS_OF_FACE, i) { diff --git a/source/blender/editors/mesh/mesh_navmesh.c b/source/blender/editors/mesh/mesh_navmesh.c index 1c36826b882..85868da0b15 100644 --- a/source/blender/editors/mesh/mesh_navmesh.c +++ b/source/blender/editors/mesh/mesh_navmesh.c @@ -84,6 +84,7 @@ static void createVertsTrisData(bContext *C, LinkNode *obs, for (oblink = obs; oblink; oblink = oblink->next) { ob = (Object *) oblink->link; dm = mesh_create_derived_no_virtual(scene, ob, NULL, CD_MASK_MESH); + DM_ensure_tessface(dm); BLI_linklist_prepend(&dms, dm); nverts += dm->getNumVerts(dm); diff --git a/source/blender/editors/metaball/mball_edit.c b/source/blender/editors/metaball/mball_edit.c index 42eda235276..de725d391f7 100644 --- a/source/blender/editors/metaball/mball_edit.c +++ b/source/blender/editors/metaball/mball_edit.c @@ -372,17 +372,22 @@ static int select_random_metaelems_exec(bContext *C, wmOperator *op) MetaBall *mb = (MetaBall *)obedit->data; MetaElem *ml; const bool select = (RNA_enum_get(op->ptr, "action") == SEL_SELECT); - float percent = RNA_float_get(op->ptr, "percent") / 100.0f; + const float randfac = RNA_float_get(op->ptr, "percent") / 100.0f; + const int seed = RNA_int_get(op->ptr, "seed"); + RNG *rng = BLI_rng_new_srandom(seed); + for (ml = mb->editelems->first; ml; ml = ml->next) { - if (BLI_frand() < percent) { + if (BLI_rng_get_float(rng) < randfac) { if (select) ml->flag |= SELECT; else ml->flag &= ~SELECT; } } - + + BLI_rng_free(rng); + WM_event_add_notifier(C, NC_GEOM | ND_SELECT, mb); return OPERATOR_FINISHED; @@ -404,9 +409,7 @@ void MBALL_OT_select_random_metaelems(struct wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; /* properties */ - RNA_def_float_percentage(ot->srna, "percent", 50.f, 0.0f, 100.0f, - "Percent", "Percentage of elements to select randomly", 0.0f, 100.0f); - WM_operator_properties_select_action_simple(ot, SEL_SELECT); + WM_operator_properties_select_random(ot); } /***************************** Duplicate operator *****************************/ diff --git a/source/blender/editors/object/object_add.c b/source/blender/editors/object/object_add.c index 615fbb527b3..269700c3aef 100644 --- a/source/blender/editors/object/object_add.c +++ b/source/blender/editors/object/object_add.c @@ -1195,89 +1195,16 @@ void OBJECT_OT_delete(wmOperatorType *ot) /**************************** Copy Utilities ******************************/ /* after copying objects, copied data should get new pointers */ -static void copy_object_set_idnew(bContext *C, int dupflag) +static void copy_object_set_idnew(bContext *C) { Main *bmain = CTX_data_main(C); - Material *ma, *mao; - ID *id; - int a; - /* XXX check object pointers */ CTX_DATA_BEGIN (C, Object *, ob, selected_editable_objects) { - BKE_object_relink(ob); + BKE_libblock_relink(&ob->id); } CTX_DATA_END; - /* materials */ - if (dupflag & USER_DUP_MAT) { - mao = bmain->mat.first; - while (mao) { - if (mao->id.newid) { - ma = (Material *)mao->id.newid; - - if (dupflag & USER_DUP_TEX) { - for (a = 0; a < MAX_MTEX; a++) { - if (ma->mtex[a]) { - id = (ID *)ma->mtex[a]->tex; - if (id) { - ID_NEW_US(ma->mtex[a]->tex) - else - ma->mtex[a]->tex = BKE_texture_copy(ma->mtex[a]->tex); - id->us--; - } - } - } - } -#if 0 // XXX old animation system - id = (ID *)ma->ipo; - if (id) { - ID_NEW_US(ma->ipo) - else - ma->ipo = copy_ipo(ma->ipo); - id->us--; - } -#endif // XXX old animation system - } - mao = mao->id.next; - } - } - -#if 0 // XXX old animation system - /* lamps */ - if (dupflag & USER_DUP_IPO) { - Lamp *la = bmain->lamp.first; - while (la) { - if (la->id.newid) { - Lamp *lan = (Lamp *)la->id.newid; - id = (ID *)lan->ipo; - if (id) { - ID_NEW_US(lan->ipo) - else - lan->ipo = copy_ipo(lan->ipo); - id->us--; - } - } - la = la->id.next; - } - } - - /* ipos */ - ipo = bmain->ipo.first; - while (ipo) { - if (ipo->id.lib == NULL && ipo->id.newid) { - Ipo *ipon = (Ipo *)ipo->id.newid; - IpoCurve *icu; - for (icu = ipon->curve.first; icu; icu = icu->next) { - if (icu->driver) { - ID_NEW(icu->driver->ob); - } - } - } - ipo = ipo->id.next; - } -#endif // XXX old animation system - set_sca_new_poins(); BKE_main_id_clear_newpoins(bmain); @@ -1468,7 +1395,7 @@ static void make_object_duplilist_real(bContext *C, Scene *scene, Base *base, if (parent_gh) BLI_ghash_free(parent_gh, NULL, NULL); - copy_object_set_idnew(C, 0); + copy_object_set_idnew(C); free_object_duplilist(lb); @@ -2023,9 +1950,6 @@ static Base *object_add_duplicate_internal(Main *bmain, Scene *scene, Base *base ID_NEW_US2(obn->data) else { obn->data = BKE_mesh_copy(obn->data); - if (obn->fluidsimSettings) { - obn->fluidsimSettings->orgMesh = (Mesh *)obn->data; - } didit = 1; } id->us--; @@ -2190,7 +2114,7 @@ Base *ED_object_add_duplicate(Main *bmain, Scene *scene, Base *base, int dupflag ob = basen->object; /* link own references to the newly duplicated data [#26816] */ - BKE_object_relink(ob); + BKE_libblock_relink(&ob->id); set_sca_new_poins_ob(ob); /* DAG_relations_tag_update(bmain); */ /* caller must do */ @@ -2235,7 +2159,7 @@ static int duplicate_exec(bContext *C, wmOperator *op) } CTX_DATA_END; - copy_object_set_idnew(C, dupflag); + copy_object_set_idnew(C); DAG_relations_tag_update(bmain); @@ -2320,7 +2244,7 @@ static int add_named_exec(bContext *C, wmOperator *op) ED_base_object_select(basen, BA_SELECT); ED_base_object_activate(C, basen); - copy_object_set_idnew(C, dupflag); + copy_object_set_idnew(C); DAG_relations_tag_update(bmain); diff --git a/source/blender/editors/object/object_bake.c b/source/blender/editors/object/object_bake.c index bd847fcd712..ecaa05ace99 100644 --- a/source/blender/editors/object/object_bake.c +++ b/source/blender/editors/object/object_bake.c @@ -215,7 +215,7 @@ static DerivedMesh *multiresbake_create_loresdm(Scene *scene, Object *ob, int *l tmp_mmd.simple = true; } - DM_set_only_copy(cddm, CD_MASK_BAREMESH | CD_MASK_MFACE | CD_MASK_MTFACE); + DM_set_only_copy(cddm, CD_MASK_BAREMESH); tmp_mmd.lvl = *lvl; tmp_mmd.sculptlvl = *lvl; @@ -283,23 +283,6 @@ static void clear_single_image(Image *image, ClearFlag flag) } } -static void clear_images(MTFace *mtface, int totface, ClearFlag flag) -{ - int a; - - for (a = 0; a < totface; a++) { - mtface[a].tpage->id.flag &= ~LIB_DOIT; - } - - for (a = 0; a < totface; a++) { - clear_single_image(mtface[a].tpage, flag); - } - - for (a = 0; a < totface; a++) { - mtface[a].tpage->id.flag &= ~LIB_DOIT; - } -} - static void clear_images_poly(MTexPoly *mtpoly, int totpoly, ClearFlag flag) { int a; @@ -342,7 +325,6 @@ static int multiresbake_image_exec_locked(bContext *C, wmOperator *op) clear_flag = CLEAR_DISPLACEMENT; } - clear_images(me->mtface, me->totface, clear_flag); clear_images_poly(me->mtpoly, me->totpoly, clear_flag); } CTX_DATA_END; @@ -440,7 +422,7 @@ static void multiresbake_startjob(void *bkv, short *stop, short *do_update, floa if (bkj->bake_clear) { /* clear images */ for (data = bkj->data.first; data; data = data->next) { DerivedMesh *dm = data->lores_dm; - MTFace *mtface = CustomData_get_layer(&dm->faceData, CD_MTFACE); + MTexPoly *mtexpoly = CustomData_get_layer(&dm->polyData, CD_MTEXPOLY); ClearFlag clear_flag = 0; if (bkj->mode == RE_BAKE_NORMALS) { @@ -450,7 +432,7 @@ static void multiresbake_startjob(void *bkv, short *stop, short *do_update, floa clear_flag = CLEAR_DISPLACEMENT; } - clear_images(mtface, dm->getNumTessFaces(dm), clear_flag); + clear_images_poly(mtexpoly, dm->getNumPolys(dm), clear_flag); } } diff --git a/source/blender/editors/object/object_bake_api.c b/source/blender/editors/object/object_bake_api.c index b382fbafcfd..9090bffcbfc 100644 --- a/source/blender/editors/object/object_bake_api.c +++ b/source/blender/editors/object/object_bake_api.c @@ -563,7 +563,7 @@ static int bake( Object *ob_cage = NULL; BakeHighPolyData *highpoly = NULL; - int tot_highpoly; + int tot_highpoly = 0; char restrict_flag_low = ob_low->restrictflag; char restrict_flag_cage = 0; @@ -689,7 +689,6 @@ static int bake( /* get the mesh as it arrives in the renderer */ me_low = BKE_mesh_new_from_object(bmain, scene, ob_low, 1, 2, 0, 0); BKE_mesh_split_faces(me_low); - BKE_mesh_tessface_ensure(me_low); /* populate the pixel array with the face data */ if ((is_selected_to_active && (ob_cage == NULL) && is_cage) == false) @@ -706,8 +705,7 @@ static int bake( if (ob_cage) { me_cage = BKE_mesh_new_from_object(bmain, scene, ob_cage, 1, 2, 0, 0); BKE_mesh_split_faces(me_cage); - BKE_mesh_tessface_ensure(me_cage); - if (me_low->totface != me_cage->totface) { + if ((me_low->totpoly != me_cage->totpoly) || (me_low->totloop != me_cage->totloop)) { BKE_report(reports, RPT_ERROR, "Invalid cage object, the cage mesh must have the same number " "of faces as the active object"); @@ -740,7 +738,6 @@ static int bake( /* get the cage mesh as it arrives in the renderer */ me_cage = BKE_mesh_new_from_object(bmain, scene, ob_low, 1, 2, 0, 0); BKE_mesh_split_faces(me_cage); - BKE_mesh_tessface_ensure(me_cage); RE_bake_pixels_populate(me_cage, pixel_array_low, num_pixels, &bake_images, uv_layer); } @@ -769,7 +766,6 @@ static int bake( highpoly[i].me = BKE_mesh_new_from_object(bmain, scene, highpoly[i].ob, 1, 2, 0, 0); highpoly[i].ob->restrictflag &= ~OB_RESTRICT_RENDER; BKE_mesh_split_faces(highpoly[i].me); - BKE_mesh_tessface_ensure(highpoly[i].me); /* lowpoly to highpoly transformation matrix */ copy_m4_m4(highpoly[i].obmat, highpoly[i].ob->obmat); @@ -873,7 +869,6 @@ cage_cleanup: me_nores = BKE_mesh_new_from_object(bmain, scene, ob_low, 1, 2, 0, 0); BKE_mesh_split_faces(me_nores); - BKE_mesh_tessface_ensure(me_nores); RE_bake_pixels_populate(me_nores, pixel_array_low, num_pixels, &bake_images, uv_layer); RE_bake_normal_world_to_tangent(pixel_array_low, num_pixels, depth, result, me_nores, normal_swizzle, ob_low->obmat); diff --git a/source/blender/editors/object/object_data_transfer.c b/source/blender/editors/object/object_data_transfer.c index 90c3f0026ac..95e1204e122 100644 --- a/source/blender/editors/object/object_data_transfer.c +++ b/source/blender/editors/object/object_data_transfer.c @@ -183,7 +183,8 @@ static EnumPropertyItem *dt_layers_select_src_itemf( } /* Note: DT_layers_select_dst_items enum is from rna_modifier.c */ -static EnumPropertyItem *dt_layers_select_dst_itemf(bContext *C, PointerRNA *ptr, PropertyRNA *UNUSED(prop), bool *r_free) +static EnumPropertyItem *dt_layers_select_dst_itemf( + bContext *C, PointerRNA *ptr, PropertyRNA *UNUSED(prop), bool *r_free) { EnumPropertyItem *item = NULL; int totitem = 0; @@ -208,6 +209,26 @@ static EnumPropertyItem *dt_layers_select_dst_itemf(bContext *C, PointerRNA *ptr return item; } +static EnumPropertyItem *dt_layers_select_itemf(bContext *C, PointerRNA *ptr, PropertyRNA *prop, bool *r_free) +{ + const bool reverse_transfer = RNA_boolean_get(ptr, "use_reverse_transfer"); + + if (STREQ(RNA_property_identifier(prop), "layers_select_dst")) { + if (reverse_transfer) { + return dt_layers_select_src_itemf(C, ptr, prop, r_free); + } + else { + return dt_layers_select_dst_itemf(C, ptr, prop, r_free); + } + } + else if (reverse_transfer) { + return dt_layers_select_dst_itemf(C, ptr, prop, r_free); + } + else { + return dt_layers_select_src_itemf(C, ptr, prop, r_free); + } +} + /* Note: DT_mix_mode_items enum is from rna_modifier.c */ static EnumPropertyItem *dt_mix_mode_itemf(bContext *C, PointerRNA *ptr, PropertyRNA *UNUSED(prop), bool *r_free) { @@ -530,7 +551,7 @@ void OBJECT_OT_data_transfer(wmOperatorType *ot) /* Properties.*/ prop = RNA_def_boolean(ot->srna, "use_reverse_transfer", false, "Reverse Transfer", "Transfer from selected objects to active one"); - RNA_def_property_flag(prop, PROP_HIDDEN); + RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE); RNA_def_boolean(ot->srna, "use_freeze", false, "Freeze Operator", "Prevent changes to settings to re-run the operator, " @@ -574,11 +595,11 @@ void OBJECT_OT_data_transfer(wmOperatorType *ot) /* How to handle multi-layers types of data. */ prop = RNA_def_enum(ot->srna, "layers_select_src", DT_layers_select_src_items, DT_LAYERS_ACTIVE_SRC, "Source Layers Selection", "Which layers to transfer, in case of multi-layers types"); - RNA_def_property_enum_funcs_runtime(prop, NULL, NULL, dt_layers_select_src_itemf); + RNA_def_property_enum_funcs_runtime(prop, NULL, NULL, dt_layers_select_itemf); prop = RNA_def_enum(ot->srna, "layers_select_dst", DT_layers_select_dst_items, DT_LAYERS_ACTIVE_DST, "Destination Layers Matching", "How to match source and destination layers"); - RNA_def_property_enum_funcs_runtime(prop, NULL, NULL, dt_layers_select_dst_itemf); + RNA_def_property_enum_funcs_runtime(prop, NULL, NULL, dt_layers_select_itemf); prop = RNA_def_enum(ot->srna, "mix_mode", DT_mix_mode_items, CDT_MIX_TRANSFER, "Mix Mode", "How to affect destination elements with source values"); diff --git a/source/blender/editors/object/object_edit.c b/source/blender/editors/object/object_edit.c index 5b39a76c2a5..05a55a8996b 100644 --- a/source/blender/editors/object/object_edit.c +++ b/source/blender/editors/object/object_edit.c @@ -576,7 +576,7 @@ static int editmode_toggle_exec(bContext *C, wmOperator *op) { const int mode_flag = OB_MODE_EDIT; const bool is_mode_set = (CTX_data_edit_object(C) != NULL); - ToolSettings *toolsettings = CTX_data_tool_settings(C); + Scene *scene = CTX_data_scene(C); if (!is_mode_set) { Object *ob = CTX_data_active_object(C); @@ -590,7 +590,7 @@ static int editmode_toggle_exec(bContext *C, wmOperator *op) else ED_object_editmode_exit(C, EM_FREEDATA | EM_FREEUNDO | EM_WAITCURSOR); /* had EM_DO_UNDO but op flag calls undo too [#24685] */ - ED_space_image_uv_sculpt_update(CTX_wm_manager(C), toolsettings); + ED_space_image_uv_sculpt_update(CTX_wm_manager(C), scene); return OPERATOR_FINISHED; } diff --git a/source/blender/editors/object/object_lattice.c b/source/blender/editors/object/object_lattice.c index 76d9facf701..410b15581df 100644 --- a/source/blender/editors/object/object_lattice.c +++ b/source/blender/editors/object/object_lattice.c @@ -192,9 +192,13 @@ static int lattice_select_random_exec(bContext *C, wmOperator *op) { Object *obedit = CTX_data_edit_object(C); Lattice *lt = ((Lattice *)obedit->data)->editlatt->latt; + const float randfac = RNA_float_get(op->ptr, "percent") / 100.0f; + const int seed = RNA_int_get(op->ptr, "seed"); const bool select = (RNA_enum_get(op->ptr, "action") == SEL_SELECT); + RNG *rng = BLI_rng_new_srandom(seed); + int tot; BPoint *bp; @@ -202,7 +206,7 @@ static int lattice_select_random_exec(bContext *C, wmOperator *op) bp = lt->def; while (tot--) { if (!bp->hide) { - if (BLI_frand() < randfac) { + if (BLI_rng_get_float(rng) < randfac) { bpoint_select_set(bp, select); } } @@ -213,6 +217,8 @@ static int lattice_select_random_exec(bContext *C, wmOperator *op) lt->actbp = LT_ACTBP_NONE; } + BLI_rng_free(rng); + WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); return OPERATOR_FINISHED; @@ -233,9 +239,7 @@ void LATTICE_OT_select_random(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; /* props */ - RNA_def_float_percentage(ot->srna, "percent", 50.f, 0.0f, 100.0f, - "Percent", "Percentage of elements to select randomly", 0.f, 100.0f); - WM_operator_properties_select_action_simple(ot, SEL_SELECT); + WM_operator_properties_select_random(ot); } diff --git a/source/blender/editors/object/object_relations.c b/source/blender/editors/object/object_relations.c index e21f58d8a38..3d030f1a770 100644 --- a/source/blender/editors/object/object_relations.c +++ b/source/blender/editors/object/object_relations.c @@ -1794,7 +1794,7 @@ static void single_object_users(Main *bmain, Scene *scene, View3D *v3d, const in /* object and group pointers */ for (base = FIRSTBASE; base; base = base->next) { - BKE_object_relink(base->object); + BKE_libblock_relink(&base->object->id); } set_sca_new_poins(); diff --git a/source/blender/editors/object/object_select.c b/source/blender/editors/object/object_select.c index 83334e4e6a3..2f2eece8018 100644 --- a/source/blender/editors/object/object_select.c +++ b/source/blender/editors/object/object_select.c @@ -854,47 +854,47 @@ static int object_select_grouped_exec(bContext *C, wmOperator *op) switch (type) { case OBJECT_GRPSEL_CHILDREN_RECURSIVE: - changed = select_grouped_children(C, ob, true); + changed |= select_grouped_children(C, ob, true); break; case OBJECT_GRPSEL_CHILDREN: - changed = select_grouped_children(C, ob, false); + changed |= select_grouped_children(C, ob, false); break; case OBJECT_GRPSEL_PARENT: - changed = select_grouped_parent(C); + changed |= select_grouped_parent(C); break; case OBJECT_GRPSEL_SIBLINGS: - changed = select_grouped_siblings(C, ob); + changed |= select_grouped_siblings(C, ob); break; case OBJECT_GRPSEL_TYPE: - changed = select_grouped_type(C, ob); + changed |= select_grouped_type(C, ob); break; case OBJECT_GRPSEL_LAYER: - changed = select_grouped_layer(C, ob); + changed |= select_grouped_layer(C, ob); break; case OBJECT_GRPSEL_GROUP: - changed = select_grouped_group(C, ob); + changed |= select_grouped_group(C, ob); break; case OBJECT_GRPSEL_HOOK: - changed = select_grouped_object_hooks(C, ob); + changed |= select_grouped_object_hooks(C, ob); break; case OBJECT_GRPSEL_PASS: - changed = select_grouped_index_object(C, ob); + changed |= select_grouped_index_object(C, ob); break; case OBJECT_GRPSEL_COLOR: - changed = select_grouped_color(C, ob); + changed |= select_grouped_color(C, ob); break; case OBJECT_GRPSEL_PROPERTIES: - changed = select_grouped_gameprops(C, ob); + changed |= select_grouped_gameprops(C, ob); break; case OBJECT_GRPSEL_KEYINGSET: - changed = select_grouped_keyingset(C, ob, op->reports); + changed |= select_grouped_keyingset(C, ob, op->reports); break; case OBJECT_GRPSEL_LAMP_TYPE: if (ob->type != OB_LAMP) { BKE_report(op->reports, RPT_ERROR, "Active object must be a lamp"); break; } - changed = select_grouped_lamptype(C, ob); + changed |= select_grouped_lamptype(C, ob); break; default: break; @@ -1179,19 +1179,22 @@ void OBJECT_OT_select_mirror(wmOperatorType *ot) static int object_select_random_exec(bContext *C, wmOperator *op) { - float percent; + const float randfac = RNA_float_get(op->ptr, "percent") / 100.0f; + const int seed = RNA_int_get(op->ptr, "seed"); const bool select = (RNA_enum_get(op->ptr, "action") == SEL_SELECT); - percent = RNA_float_get(op->ptr, "percent") / 100.0f; - + RNG *rng = BLI_rng_new_srandom(seed); + CTX_DATA_BEGIN (C, Base *, base, selectable_bases) { - if (BLI_frand() < percent) { + if (BLI_rng_get_float(rng) < randfac) { ED_base_object_select(base, select); } } CTX_DATA_END; - + + BLI_rng_free(rng); + WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, CTX_data_scene(C)); return OPERATOR_FINISHED; @@ -1213,6 +1216,5 @@ void OBJECT_OT_select_random(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; /* properties */ - RNA_def_float_percentage(ot->srna, "percent", 50.f, 0.0f, 100.0f, "Percent", "Percentage of objects to select randomly", 0.f, 100.0f); - WM_operator_properties_select_action_simple(ot, SEL_SELECT); + WM_operator_properties_select_random(ot); } diff --git a/source/blender/editors/object/object_transform.c b/source/blender/editors/object/object_transform.c index 340b662c0ef..ac1f13ee59c 100644 --- a/source/blender/editors/object/object_transform.c +++ b/source/blender/editors/object/object_transform.c @@ -382,7 +382,7 @@ static int apply_objects_internal(bContext *C, ReportList *reports, bool apply_l /* first check if we can execute */ CTX_DATA_BEGIN (C, Object *, ob, selected_editable_objects) { - if (ELEM(ob->type, OB_MESH, OB_ARMATURE, OB_LATTICE, OB_MBALL, OB_CURVE, OB_SURF)) { + if (ELEM(ob->type, OB_MESH, OB_ARMATURE, OB_LATTICE, OB_MBALL, OB_CURVE, OB_SURF, OB_FONT)) { ID *obdata = ob->data; if (ID_REAL_USERS(obdata) > 1) { BKE_reportf(reports, RPT_ERROR, @@ -418,6 +418,15 @@ static int apply_objects_internal(bContext *C, ReportList *reports, bool apply_l changed = false; } } + + if (ob->type == OB_FONT) { + if (apply_rot || apply_loc) { + BKE_reportf(reports, RPT_ERROR, + "Font's can only have scale applied: \"%s\"", + ob->id.name + 2); + changed = false; + } + } } CTX_DATA_END; @@ -496,6 +505,22 @@ static int apply_objects_internal(bContext *C, ReportList *reports, bool apply_l scale = mat3_to_scale(rsmat); BKE_curve_transform_ex(cu, mat, true, scale); } + else if (ob->type == OB_FONT) { + Curve *cu = ob->data; + int i; + + scale = mat3_to_scale(rsmat); + + for (i = 0; i < cu->totbox; i++) { + TextBox *tb = &cu->tb[i]; + tb->x *= scale; + tb->y *= scale; + tb->w *= scale; + tb->h *= scale; + } + + cu->fsize *= scale; + } else if (ob->type == OB_CAMERA) { MovieClip *clip = BKE_object_movieclip_get(scene, ob, false); diff --git a/source/blender/editors/object/object_vgroup.c b/source/blender/editors/object/object_vgroup.c index d52031ecc03..352c90e805a 100644 --- a/source/blender/editors/object/object_vgroup.c +++ b/source/blender/editors/object/object_vgroup.c @@ -246,7 +246,7 @@ bool ED_vgroup_parray_alloc(ID *id, MDeformVert ***dvert_arr, int *dvert_tot, co /** * For use with tools that use ED_vgroup_parray_alloc with \a use_vert_sel == true. - * This finds the unselected mirror deform verts and copys the weights to them from the selected. + * This finds the unselected mirror deform verts and copies the weights to them from the selected. * * \note \a dvert_array has mirrored weights filled in, incase cleanup operations are needed on both. */ @@ -1213,8 +1213,8 @@ static void getVerticalAndHorizontalChange(const float norm[3], float d, const f plane_from_point_normal_v3(plane, coord, norm); - closest_to_plane_v3(projA, plane, start); - closest_to_plane_v3(projB, plane, end); + closest_to_plane_normalized_v3(projA, plane, start); + closest_to_plane_normalized_v3(projB, plane, end); /* (vertical and horizontal refer to the plane's y and xz respectively) * vertical distance */ dists[index] = dot_v3v3(norm, end) + d; diff --git a/source/blender/editors/physics/particle_edit.c b/source/blender/editors/physics/particle_edit.c index 892545a8efd..32cd1f7a1ce 100644 --- a/source/blender/editors/physics/particle_edit.c +++ b/source/blender/editors/physics/particle_edit.c @@ -1634,7 +1634,10 @@ static int select_random_exec(bContext *C, wmOperator *op) int p; int k; - const float randf = RNA_float_get (op->ptr, "percent") / 100.0f; + const float randfac = RNA_float_get (op->ptr, "percent") / 100.0f; + const int seed = RNA_int_get(op->ptr, "seed"); + const bool select = (RNA_enum_get(op->ptr, "action") == SEL_SELECT); + RNG *rng; type = RNA_enum_get(op->ptr, "type"); @@ -1644,10 +1647,12 @@ static int select_random_exec(bContext *C, wmOperator *op) ob = CTX_data_active_object(C); edit = PE_get_current(scene, ob); + rng = BLI_rng_new_srandom(seed); + switch (type) { case RAN_HAIR: LOOP_VISIBLE_POINTS { - int flag = (BLI_frand() < randf) ? SEL_SELECT : SEL_DESELECT; + int flag = ((BLI_rng_get_float(rng) < randfac) == select) ? SEL_SELECT : SEL_DESELECT; LOOP_KEYS { select_action_apply (point, key, flag); } @@ -1656,13 +1661,15 @@ static int select_random_exec(bContext *C, wmOperator *op) case RAN_POINTS: LOOP_VISIBLE_POINTS { LOOP_VISIBLE_KEYS { - int flag = (BLI_frand() < randf) ? SEL_SELECT : SEL_DESELECT; + int flag = ((BLI_rng_get_float(rng) < randfac) == select) ? SEL_SELECT : SEL_DESELECT; select_action_apply (point, key, flag); } } break; } + BLI_rng_free(rng); + PE_update_selection(data.scene, data.ob, 1); WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE|NA_SELECTED, data.ob); @@ -1684,9 +1691,7 @@ void PARTICLE_OT_select_random(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO; /* properties */ - RNA_def_float_percentage (ot->srna, "percent", 50.0f, 0.0f, 100.0f, "Percent", - "Percentage (mean) of elements in randomly selected set", - 0.0f, 100.0f); + WM_operator_properties_select_random(ot); ot->prop = RNA_def_enum (ot->srna, "type", select_random_type_items, RAN_HAIR, "Type", "Select either hair or points"); } diff --git a/source/blender/editors/physics/particle_object.c b/source/blender/editors/physics/particle_object.c index 327ce060df9..337e7e99929 100644 --- a/source/blender/editors/physics/particle_object.c +++ b/source/blender/editors/physics/particle_object.c @@ -1095,6 +1095,7 @@ static bool copy_particle_systems_to_object(Scene *scene, Object *ob_from, Parti break; default: /* should not happen */ + from_mat = to_mat = NULL; BLI_assert(false); break; } diff --git a/source/blender/editors/render/render_intern.h b/source/blender/editors/render/render_intern.h index 54429f9f066..26f313cb3fe 100644 --- a/source/blender/editors/render/render_intern.h +++ b/source/blender/editors/render/render_intern.h @@ -93,7 +93,7 @@ void render_view3d_update(struct RenderEngine *engine, const struct bContext *C) void render_view3d_draw(struct RenderEngine *engine, const struct bContext *C); /* render_view.c */ -struct ScrArea *render_view_open(struct bContext *C, int mx, int my); +struct ScrArea *render_view_open(struct bContext *C, int mx, int my, struct ReportList *reports); void RENDER_OT_view_show(struct wmOperatorType *ot); void RENDER_OT_view_cancel(struct wmOperatorType *ot); diff --git a/source/blender/editors/render/render_internal.c b/source/blender/editors/render/render_internal.c index 75ee6d17307..164b8fa1c9a 100644 --- a/source/blender/editors/render/render_internal.c +++ b/source/blender/editors/render/render_internal.c @@ -190,7 +190,7 @@ static void image_buffer_rect_update(RenderJob *rj, RenderResult *rr, ImBuf *ibu * - sergey - */ /* TODO(sergey): Need to check has_combined here? */ - if (iuser->passtype == SCE_PASS_COMBINED) { + if (iuser->pass == 0) { RenderView *rv; size_t view_id = BKE_scene_multiview_view_id_get(&scene->r, viewname); rv = RE_RenderViewGetById(rr, view_id); @@ -525,6 +525,7 @@ static void render_image_update_pass_and_layer(RenderJob *rj, RenderResult *rr, } } + iuser->pass = sima->iuser.pass; iuser->layer = sima->iuser.layer; RE_ReleaseResult(rj->re); @@ -876,7 +877,7 @@ static int screen_render_invoke(bContext *C, wmOperator *op, const wmEvent *even // store spare /* ensure at least 1 area shows result */ - sa = render_view_open(C, event->x, event->y); + sa = render_view_open(C, event->x, event->y, op->reports); jobflag = WM_JOB_EXCL_RENDER | WM_JOB_PRIORITY | WM_JOB_PROGRESS; @@ -898,7 +899,6 @@ static int screen_render_invoke(bContext *C, wmOperator *op, const wmEvent *even rj->write_still = is_write_still && !is_animation; rj->iuser.scene = scene; rj->iuser.ok = 1; - rj->iuser.passtype = SCE_PASS_COMBINED; rj->reports = op->reports; rj->orig_layer = 0; rj->last_layer = 0; diff --git a/source/blender/editors/render/render_opengl.c b/source/blender/editors/render/render_opengl.c index c718dfa9229..51c4e8bc16e 100644 --- a/source/blender/editors/render/render_opengl.c +++ b/source/blender/editors/render/render_opengl.c @@ -96,6 +96,7 @@ typedef struct OGLRender { ImageUser iuser; GPUOffScreen *ofs; + int ofs_samples; GPUFX *fx; int sizex, sizey; int write_still; @@ -228,13 +229,8 @@ static void screen_opengl_views_setup(OGLRender *oglrender) } BLI_lock_thread(LOCK_DRAW_IMAGE); - if (is_multiview && BKE_scene_multiview_is_stereo3d(rd)) { - oglrender->ima->flag |= IMA_IS_STEREO; - } - else { - oglrender->ima->flag &= ~IMA_IS_STEREO; + if (!(is_multiview && BKE_scene_multiview_is_stereo3d(rd))) oglrender->iuser.flag &= ~IMA_SHOW_STEREO; - } BLI_unlock_thread(LOCK_DRAW_IMAGE); /* will only work for non multiview correctly */ @@ -279,6 +275,9 @@ static void screen_opengl_render_doit(OGLRender *oglrender, RenderResult *rr) &context); context.view_id = BKE_scene_multiview_view_id_get(&scene->r, viewname); + context.gpu_offscreen = oglrender->ofs; + context.gpu_samples = oglrender->ofs_samples; + ibuf = BKE_sequencer_give_ibuf(&context, CFRA, chanshown); if (ibuf) { @@ -375,63 +374,23 @@ static void screen_opengl_render_doit(OGLRender *oglrender, RenderResult *rr) rect = MEM_mallocN(sizex * sizey * sizeof(unsigned char) * 4, "offscreen rect"); - if ((scene->r.mode & R_OSA) == 0) { - ED_view3d_draw_offscreen( - scene, v3d, ar, sizex, sizey, NULL, winmat, - draw_bgpic, draw_sky, is_persp, - oglrender->ofs, oglrender->fx, &fx_settings, viewname); - GPU_offscreen_read_pixels(oglrender->ofs, GL_UNSIGNED_BYTE, rect); - } - else { - /* simple accumulation, less hassle then FSAA FBO's */ - static float jit_ofs[32][2]; - float winmat_jitter[4][4]; - int *accum_buffer = MEM_mallocN(sizex * sizey * sizeof(int) * 4, "accum1"); - int i, j; - - BLI_jitter_init(jit_ofs, scene->r.osa); - - /* first sample buffer, also initializes 'rv3d->persmat' */ - ED_view3d_draw_offscreen( - scene, v3d, ar, sizex, sizey, NULL, winmat, - draw_bgpic, draw_sky, is_persp, - oglrender->ofs, oglrender->fx, &fx_settings, viewname); - GPU_offscreen_read_pixels(oglrender->ofs, GL_UNSIGNED_BYTE, rect); - - for (i = 0; i < sizex * sizey * 4; i++) - accum_buffer[i] = rect[i]; - - /* skip the first sample */ - for (j = 1; j < scene->r.osa; 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_bgpic, draw_sky, is_persp, - oglrender->ofs, oglrender->fx, &fx_settings, viewname); - GPU_offscreen_read_pixels(oglrender->ofs, GL_UNSIGNED_BYTE, rect); - - for (i = 0; i < sizex * sizey * 4; i++) - accum_buffer[i] += rect[i]; - } - - for (i = 0; i < sizex * sizey * 4; i++) - rect[i] = accum_buffer[i] / scene->r.osa; - - MEM_freeN(accum_buffer); - } + ED_view3d_draw_offscreen( + scene, v3d, ar, sizex, sizey, NULL, winmat, + draw_bgpic, draw_sky, is_persp, viewname, + oglrender->fx, &fx_settings, + oglrender->ofs); + GPU_offscreen_read_pixels(oglrender->ofs, GL_UNSIGNED_BYTE, rect); GPU_offscreen_unbind(oglrender->ofs, true); /* unbind */ } else { /* shouldnt suddenly give errors mid-render but possible */ char err_out[256] = "unknown"; - ImBuf *ibuf_view = ED_view3d_draw_offscreen_imbuf_simple(scene, scene->camera, oglrender->sizex, oglrender->sizey, - IB_rect, OB_SOLID, false, true, true, - (draw_sky) ? R_ADDSKY : R_ALPHAPREMUL, viewname, err_out); + ImBuf *ibuf_view = ED_view3d_draw_offscreen_imbuf_simple( + scene, scene->camera, oglrender->sizex, oglrender->sizey, + IB_rect, OB_SOLID, false, true, true, + (draw_sky) ? R_ADDSKY : R_ALPHAPREMUL, oglrender->ofs_samples, viewname, + oglrender->ofs, err_out); camera = scene->camera; if (ibuf_view) { @@ -541,6 +500,7 @@ static bool screen_opengl_render_init(bContext *C, wmOperator *op) GPUOffScreen *ofs; OGLRender *oglrender; int sizex, sizey; + const int samples = (scene->r.mode & R_OSA) ? scene->r.osa : 0; bool is_view_context = RNA_boolean_get(op->ptr, "view_context"); const bool is_animation = RNA_boolean_get(op->ptr, "animation"); const bool is_sequencer = RNA_boolean_get(op->ptr, "sequencer"); @@ -585,7 +545,7 @@ static bool screen_opengl_render_init(bContext *C, wmOperator *op) sizey = (scene->r.size * scene->r.ysch) / 100; /* corrects render size with actual size, not every card supports non-power-of-two dimensions */ - ofs = GPU_offscreen_create(sizex, sizey, err_out); + ofs = GPU_offscreen_create(sizex, sizey, samples, err_out); if (!ofs) { BKE_reportf(op->reports, RPT_ERROR, "Failed to create OpenGL off-screen buffer, %s", err_out); @@ -597,6 +557,7 @@ static bool screen_opengl_render_init(bContext *C, wmOperator *op) op->customdata = oglrender; oglrender->ofs = ofs; + oglrender->ofs_samples = samples; oglrender->sizex = sizex; oglrender->sizey = sizey; oglrender->bmain = CTX_data_main(C); @@ -706,7 +667,7 @@ static void screen_opengl_render_cancel(bContext *C, wmOperator *op) } /* share between invoke and exec */ -static int screen_opengl_render_anim_initialize(bContext *C, wmOperator *op) +static bool screen_opengl_render_anim_initialize(bContext *C, wmOperator *op) { /* initialize animation */ OGLRender *oglrender; @@ -722,9 +683,16 @@ static int screen_opengl_render_anim_initialize(bContext *C, wmOperator *op) size_t i, width, height; BKE_scene_multiview_videos_dimensions_get(&scene->r, oglrender->sizex, oglrender->sizey, &width, &height); - oglrender->movie_ctx_arr = MEM_mallocN(sizeof(void *) * oglrender->totvideos, "Movies"); oglrender->mh = BKE_movie_handle_get(scene->r.im_format.imtype); + if (oglrender->mh == NULL) { + BKE_report(oglrender->reports, RPT_ERROR, "Movie format unsupported"); + screen_opengl_render_end(C, oglrender); + return false; + } + + oglrender->movie_ctx_arr = MEM_mallocN(sizeof(void *) * oglrender->totvideos, "Movies"); + for (i = 0; i < oglrender->totvideos; i++) { const char *suffix = BKE_scene_multiview_view_id_suffix_get(&scene->r, i); @@ -733,7 +701,7 @@ static int screen_opengl_render_anim_initialize(bContext *C, wmOperator *op) oglrender->sizey, oglrender->reports, PRVRANGEON != 0, suffix)) { screen_opengl_render_end(C, oglrender); - return 0; + return false; } } } @@ -742,7 +710,7 @@ static int screen_opengl_render_anim_initialize(bContext *C, wmOperator *op) oglrender->nfra = PSFRA; scene->r.cfra = PSFRA; - return 1; + return true; } static bool screen_opengl_render_anim_step(bContext *C, wmOperator *op) @@ -904,7 +872,7 @@ static int screen_opengl_render_invoke(bContext *C, wmOperator *op, const wmEven } oglrender = op->customdata; - render_view_open(C, event->x, event->y); + render_view_open(C, event->x, event->y, op->reports); /* view may be changed above (R_OUTPUT_WINDOW) */ oglrender->win = CTX_wm_window(C); diff --git a/source/blender/editors/render/render_update.c b/source/blender/editors/render/render_update.c index dedcbb144aa..f11a8177bf8 100644 --- a/source/blender/editors/render/render_update.c +++ b/source/blender/editors/render/render_update.c @@ -52,6 +52,7 @@ #include "BKE_material.h" #include "BKE_node.h" #include "BKE_paint.h" +#include "BKE_scene.h" #include "GPU_material.h" #include "GPU_buffers.h" @@ -142,6 +143,23 @@ void ED_render_scene_update(Main *bmain, Scene *scene, int updated) recursive_check = false; } +void ED_render_scene_update_pre(Main *bmain, Scene *scene, bool time) +{ + /* Blender internal might access to the data which is gonna to be freed + * by the scene update functions. This applies for example to simulation + * data like smoke and fire. + */ + if (time && !BKE_scene_use_new_shading_nodes(scene)) { + bScreen *sc; + ScrArea *sa; + for (sc = bmain->screen.first; sc; sc = sc->id.next) { + for (sa = sc->areabase.first; sa; sa = sa->next) { + ED_render_engine_area_exit(bmain, sa); + } + } + } +} + void ED_render_engine_area_exit(Main *bmain, ScrArea *sa) { /* clear all render engines in this area */ diff --git a/source/blender/editors/render/render_view.c b/source/blender/editors/render/render_view.c index f6690296890..4e36303d829 100644 --- a/source/blender/editors/render/render_view.c +++ b/source/blender/editors/render/render_view.c @@ -38,6 +38,7 @@ #include "BKE_image.h" #include "BKE_global.h" #include "BKE_screen.h" +#include "BKE_report.h" #include "WM_api.h" #include "WM_types.h" @@ -125,7 +126,7 @@ static ScrArea *find_area_image_empty(bContext *C) /********************** open image editor for render *************************/ /* new window uses x,y to set position */ -ScrArea *render_view_open(bContext *C, int mx, int my) +ScrArea *render_view_open(bContext *C, int mx, int my, ReportList *reports) { wmWindow *win = CTX_wm_window(C); Scene *scene = CTX_data_scene(C); @@ -155,7 +156,10 @@ ScrArea *render_view_open(bContext *C, int mx, int my) rect.ymax = rect.ymin + sizey; /* changes context! */ - WM_window_open_temp(C, &rect, WM_WINDOW_RENDER); + if (WM_window_open_temp(C, &rect, WM_WINDOW_RENDER) == NULL) { + BKE_report(reports, RPT_ERROR, "Failed to open window!"); + return NULL; + } sa = CTX_wm_area(C); } @@ -292,7 +296,7 @@ void RENDER_OT_view_cancel(struct wmOperatorType *ot) /************************* show render viewer *****************/ -static int render_view_show_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *event) +static int render_view_show_invoke(bContext *C, wmOperator *op, const wmEvent *event) { wmWindow *wincur = CTX_wm_window(C); @@ -341,7 +345,7 @@ static int render_view_show_invoke(bContext *C, wmOperator *UNUSED(op), const wm } } else { - render_view_open(C, event->x, event->y); + render_view_open(C, event->x, event->y, op->reports); } } diff --git a/source/blender/editors/screen/area.c b/source/blender/editors/screen/area.c index 03df6b17acd..3e0bbd47eda 100644 --- a/source/blender/editors/screen/area.c +++ b/source/blender/editors/screen/area.c @@ -2116,9 +2116,9 @@ static const char *meta_data_list[] = { "File", "Strip", - "Note", "Date", "RenderTime", + "Note", "Marker", "Time", "Frame", @@ -2139,7 +2139,15 @@ static void metadata_draw_imbuf(ImBuf *ibuf, const rctf *rect, int fontid, const short i; int len; const float height = BLF_height_max(fontid); - const float vertical_offset = height + (0.1f * U.widget_unit); + const float margin = height / 8; + const float vertical_offset = (height + margin); + + /* values taking margins into account */ + const float descender = BLF_descender(fontid); + const float xmin = (rect->xmin + margin); + const float xmax = (rect->xmax - margin); + const float ymin = (rect->ymin + margin) - descender; + const float ymax = (rect->ymax - margin) - descender; if (is_top) { for (i = 0; i < 4; i++) { @@ -2148,8 +2156,7 @@ static void metadata_draw_imbuf(ImBuf *ibuf, const rctf *rect, int fontid, const bool do_newline = false; len = BLI_snprintf_rlen(temp_str, MAX_METADATA_STR, "%s: ", meta_data_list[0]); if (metadata_is_valid(ibuf, temp_str, 0, len)) { - BLF_position(fontid, rect->xmin + (0.2f * U.widget_unit), - rect->ymax - vertical_offset, 0.0f); + BLF_position(fontid, xmin, ymax - vertical_offset, 0.0f); BLF_draw(fontid, temp_str, BLF_DRAW_STR_DUMMY_MAX); do_newline = true; } @@ -2157,30 +2164,40 @@ static void metadata_draw_imbuf(ImBuf *ibuf, const rctf *rect, int fontid, const len = BLI_snprintf_rlen(temp_str, MAX_METADATA_STR, "%s: ", meta_data_list[1]); if (metadata_is_valid(ibuf, temp_str, 1, len)) { line_width = BLF_width(fontid, temp_str, BLF_DRAW_STR_DUMMY_MAX); - BLF_position(fontid, rect->xmax - line_width - (0.2f * U.widget_unit), - rect->ymax - vertical_offset, 0.0f); + BLF_position(fontid, xmax - line_width, ymax - vertical_offset, 0.0f); BLF_draw(fontid, temp_str, BLF_DRAW_STR_DUMMY_MAX); do_newline = true; } if (do_newline) ofs_y += vertical_offset; - } - else if (i == 1) { + } /* Strip */ + else if (i == 1 || i == 2) { len = BLI_snprintf_rlen(temp_str, MAX_METADATA_STR, "%s: ", meta_data_list[i + 1]); if (metadata_is_valid(ibuf, temp_str, i + 1, len)) { - BLF_position(fontid, rect->xmin + (0.2f * U.widget_unit), - rect->ymax - vertical_offset - ofs_y, 0.0f); + BLF_position(fontid, xmin, ymax - vertical_offset - ofs_y, 0.0f); BLF_draw(fontid, temp_str, BLF_DRAW_STR_DUMMY_MAX); ofs_y += vertical_offset; } + } /* Note (wrapped) */ + else if (i == 3) { + len = BLI_snprintf_rlen(temp_str, MAX_METADATA_STR, "%s: ", meta_data_list[i + 1]); + if (metadata_is_valid(ibuf, temp_str, i + 1, len)) { + struct ResultBLF info; + BLF_enable(fontid, BLF_WORD_WRAP); + BLF_wordwrap(fontid, ibuf->x - (margin * 2)); + BLF_position(fontid, xmin, ymax - vertical_offset - ofs_y, 0.0f); + BLF_draw_ex(fontid, temp_str, BLF_DRAW_STR_DUMMY_MAX, &info); + BLF_wordwrap(fontid, 0); + BLF_disable(fontid, BLF_WORD_WRAP); + ofs_y += vertical_offset * info.lines; + } } else { len = BLI_snprintf_rlen(temp_str, MAX_METADATA_STR, "%s: ", meta_data_list[i + 1]); if (metadata_is_valid(ibuf, temp_str, i + 1, len)) { line_width = BLF_width(fontid, temp_str, BLF_DRAW_STR_DUMMY_MAX); - BLF_position(fontid, rect->xmax - line_width - (0.2f * U.widget_unit), - rect->ymax - vertical_offset - ofs_y, 0.0f); + BLF_position(fontid, xmax - line_width, ymax - vertical_offset - ofs_y, 0.0f); BLF_draw(fontid, temp_str, BLF_DRAW_STR_DUMMY_MAX); ofs_y += vertical_offset; } @@ -2192,8 +2209,7 @@ static void metadata_draw_imbuf(ImBuf *ibuf, const rctf *rect, int fontid, const for (i = 5; i < 10; i++) { len = BLI_snprintf_rlen(temp_str, MAX_METADATA_STR, "%s: ", meta_data_list[i]); if (metadata_is_valid(ibuf, temp_str, i, len)) { - BLF_position(fontid, rect->xmin + (0.2f * U.widget_unit) + ofs_x, - rect->ymin + (0.3f * U.widget_unit), 0.0f); + BLF_position(fontid, xmin + ofs_x, ymin, 0.0f); BLF_draw(fontid, temp_str, BLF_DRAW_STR_DUMMY_MAX); ofs_x += BLF_width(fontid, temp_str, BLF_DRAW_STR_DUMMY_MAX) + UI_UNIT_X; @@ -2204,9 +2220,10 @@ static void metadata_draw_imbuf(ImBuf *ibuf, const rctf *rect, int fontid, const static float metadata_box_height_get(ImBuf *ibuf, int fontid, const bool is_top) { + const float height = BLF_height_max(fontid); + const float margin = (height / 8); char str[MAX_METADATA_STR] = ""; short i, count = 0; - const float height = BLF_height_max(fontid) + 0.1f * U.widget_unit; if (is_top) { if (metadata_is_valid(ibuf, str, 0, 0) || metadata_is_valid(ibuf, str, 1, 0)) { @@ -2214,7 +2231,23 @@ static float metadata_box_height_get(ImBuf *ibuf, int fontid, const bool is_top) } for (i = 2; i < 5; i++) { if (metadata_is_valid(ibuf, str, i, 0)) { - count++; + if (i == 4) { + struct { + struct ResultBLF info; + rctf rect; + } wrap; + + BLF_enable(fontid, BLF_WORD_WRAP); + BLF_wordwrap(fontid, ibuf->x - (margin * 2)); + BLF_boundbox_ex(fontid, str, sizeof(str), &wrap.rect, &wrap.info); + BLF_wordwrap(fontid, 0); + BLF_disable(fontid, BLF_WORD_WRAP); + + count += wrap.info.lines; + } + else { + count++; + } } } } @@ -2227,7 +2260,7 @@ static float metadata_box_height_get(ImBuf *ibuf, int fontid, const bool is_top) } if (count) { - return (height * count + (0.1f * U.widget_unit)); + return (height + margin) * count; } return 0; @@ -2235,7 +2268,7 @@ static float metadata_box_height_get(ImBuf *ibuf, int fontid, const bool is_top) #undef MAX_METADATA_STR -void ED_region_image_metadata_draw(int x, int y, ImBuf *ibuf, rctf frame, float zoomx, float zoomy) +void ED_region_image_metadata_draw(int x, int y, ImBuf *ibuf, const rctf *frame, float zoomx, float zoomy) { float box_y; rctf rect; @@ -2251,7 +2284,7 @@ void ED_region_image_metadata_draw(int x, int y, ImBuf *ibuf, rctf frame, float glTranslatef(x, y, 0.0f); glScalef(zoomx, zoomy, 1.0f); - BLF_size(blf_mono_font, style->widgetlabel.points * 1.5f, U.dpi); + BLF_size(blf_mono_font, style->widgetlabel.points * 1.5f * U.pixelsize, U.dpi); /* *** upper box*** */ @@ -2262,7 +2295,7 @@ void ED_region_image_metadata_draw(int x, int y, ImBuf *ibuf, rctf frame, float UI_ThemeColor(TH_METADATA_BG); /* set up rect */ - BLI_rctf_init(&rect, frame.xmin, frame.xmax, frame.ymax, frame.ymax + box_y); + 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); @@ -2284,7 +2317,7 @@ void ED_region_image_metadata_draw(int x, int y, ImBuf *ibuf, rctf frame, float UI_ThemeColor(TH_METADATA_BG); /* set up box rect */ - BLI_rctf_init(&rect, frame.xmin, frame.xmax, frame.ymin - box_y, frame.ymin); + 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); @@ -2373,7 +2406,7 @@ void ED_region_draw_backdrop_view3d(const bContext *C, struct Object *camera, co BKE_scene_update_for_newframe(bmain->eval_ctx, bmain, scene, scene->lay); ibuf = ED_view3d_draw_offscreen_imbuf_simple(scene, camera, width, height, IB_rect, OB_SOLID, false, false, false, - R_ADDSKY, NULL, err_out); + R_ADDSKY, 0, NULL, NULL, err_out); if (ibuf == NULL) return; diff --git a/source/blender/editors/screen/screen_edit.c b/source/blender/editors/screen/screen_edit.c index f4c4af9d031..f46486601af 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_image.h" #include "BKE_global.h" #include "BKE_library.h" #include "BKE_main.h" @@ -1554,8 +1555,8 @@ bool ED_screen_set(bContext *C, bScreen *sc) } /* Always do visible update since it's possible new screen will - * have different layers visible in 3D viewpots. This is possible - * because of view3d.lock_camera_and_layers option. + * have different layers visible in 3D view-ports. + * This is possible because of view3d.lock_camera_and_layers option. */ DAG_on_visible_update(bmain, false); } @@ -1783,6 +1784,8 @@ ScrArea *ED_screen_full_newspace(bContext *C, ScrArea *sa, int type) */ void ED_screen_full_prevspace(bContext *C, ScrArea *sa, const bool was_prev_temp) { + BLI_assert(sa->full); + if (sa->flag & AREA_FLAG_STACKED_FULLSCREEN) { /* stacked fullscreen -> only go back to previous screen and don't toggle out of fullscreen */ ED_area_prevspace(C, sa); @@ -2185,7 +2188,7 @@ bool ED_screen_stereo3d_required(bScreen *screen) /* images should always show in stereo, even if * the file doesn't have views enabled */ sima = sa->spacedata.first; - if (sima->image && (sima->image->flag & IMA_IS_STEREO) && + if (sima->image && BKE_image_is_stereo(sima->image) && (sima->iuser.flag & IMA_SHOW_STEREO)) { return true; diff --git a/source/blender/editors/screen/screen_ops.c b/source/blender/editors/screen/screen_ops.c index 7806c1a0eac..5222bbcc9ba 100644 --- a/source/blender/editors/screen/screen_ops.c +++ b/source/blender/editors/screen/screen_ops.c @@ -992,6 +992,11 @@ static int area_dupli_invoke(bContext *C, wmOperator *op, const wmEvent *event) rect.ymax = rect.ymin + BLI_rcti_size_y(&rect) / U.pixelsize; newwin = WM_window_open(C, &rect); + if (newwin == NULL) { + BKE_report(op->reports, RPT_ERROR, "Failed to open window!"); + goto finally; + } + *newwin->stereo3d_format = *win->stereo3d_format; /* allocs new screen and adds to newly created window, using window size */ @@ -1005,11 +1010,18 @@ static int area_dupli_invoke(bContext *C, wmOperator *op, const wmEvent *event) /* screen, areas init */ WM_event_add_notifier(C, NC_SCREEN | NA_EDITED, NULL); - + + +finally: if (event->type == EVT_ACTIONZONE_AREA) actionzone_exit(op); - return OPERATOR_FINISHED; + if (newwin) { + return OPERATOR_FINISHED; + } + else { + return OPERATOR_CANCELLED; + } } static void SCREEN_OT_area_dupli(wmOperatorType *ot) @@ -2356,7 +2368,7 @@ static void SCREEN_OT_marker_jump(wmOperatorType *ot) static bool screen_set_is_ok(bScreen *screen, bScreen *screen_prev) { return ((screen->winid == 0) && - /* in typical useage these should have a nonzero winid + /* in typical usage these should have a nonzero winid * (all temp screens should be used, or closed & freed). */ (screen->temp == false) && (screen->state == SCREENNORMAL) && @@ -2376,7 +2388,7 @@ static int screen_set_exec(bContext *C, wmOperator *op) int delta = RNA_int_get(op->ptr, "delta"); /* temp screens are for userpref or render display */ - if (screen->temp || (sa->full && sa->full->temp)) { + if (screen->temp || (sa && sa->full && sa->full->temp)) { return OPERATOR_CANCELLED; } @@ -3845,7 +3857,7 @@ static void SCREEN_OT_back_to_previous(struct wmOperatorType *ot) /* *********** show user pref window ****** */ -static int userpref_show_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *event) +static int userpref_show_invoke(bContext *C, wmOperator *op, const wmEvent *event) { wmWindow *win = CTX_wm_window(C); rcti rect; @@ -3862,9 +3874,13 @@ static int userpref_show_invoke(bContext *C, wmOperator *UNUSED(op), const wmEve rect.ymax = rect.ymin + sizey; /* changes context! */ - WM_window_open_temp(C, &rect, WM_WINDOW_USERPREFS); - - return OPERATOR_FINISHED; + if (WM_window_open_temp(C, &rect, WM_WINDOW_USERPREFS) != NULL) { + return OPERATOR_FINISHED; + } + else { + BKE_report(op->reports, RPT_ERROR, "Failed to open window!"); + return OPERATOR_CANCELLED; + } } diff --git a/source/blender/editors/screen/screendump.c b/source/blender/editors/screen/screendump.c index e23ac1710e3..a701fc9ccb7 100644 --- a/source/blender/editors/screen/screendump.c +++ b/source/blender/editors/screen/screendump.c @@ -354,6 +354,10 @@ static void screenshot_startjob(void *sjv, short *stop, short *do_update, float if (BKE_imtype_is_movie(rd.im_format.imtype)) { mh = BKE_movie_handle_get(sj->scene->r.im_format.imtype); + if (mh == NULL) { + printf("Movie format unsupported\n"); + return; + } sj->movie_ctx = mh->context_create(); sj->movie_handle = mh; diff --git a/source/blender/editors/sculpt_paint/paint_cursor.c b/source/blender/editors/sculpt_paint/paint_cursor.c index e4cad389004..e19756c6a35 100644 --- a/source/blender/editors/sculpt_paint/paint_cursor.c +++ b/source/blender/editors/sculpt_paint/paint_cursor.c @@ -644,9 +644,9 @@ static void paint_draw_tex_overlay(UnifiedPaintSettings *ups, Brush *brush, glMatrixMode(GL_MODELVIEW); glPushMatrix(); if (primary) - glTranslatef(brush->stencil_pos[0], brush->stencil_pos[1], 0); + glTranslate2fv(brush->stencil_pos); else - glTranslatef(brush->mask_stencil_pos[0], brush->mask_stencil_pos[1], 0); + glTranslate2fv(brush->mask_stencil_pos); glRotatef(RAD2DEGF(mtex->rot), 0, 0, 1); glMatrixMode(GL_TEXTURE); } @@ -725,7 +725,7 @@ static void paint_draw_cursor_overlay(UnifiedPaintSettings *ups, Brush *brush, do_pop = true; glPushMatrix(); glLoadIdentity(); - glTranslatef(center[0], center[1], 0); + glTranslate2fv(center); glScalef(ups->size_pressure_value, ups->size_pressure_value, 1); glTranslatef(-center[0], -center[1], 0); } @@ -756,7 +756,7 @@ static void paint_draw_alpha_overlay(UnifiedPaintSettings *ups, Brush *brush, ViewContext *vc, int x, int y, float zoom, PaintMode mode) { /* color means that primary brush texture is colured and secondary is used for alpha/mask control */ - bool col = ELEM(mode, PAINT_TEXTURE_PROJECTIVE, PAINT_TEXTURE_2D, PAINT_VERTEX) ? true : false; + bool col = ELEM(mode, ePaintTextureProjective, ePaintTexture2D, ePaintVertex) ? true : false; OverlayControlFlags flags = BKE_paint_get_overlay_flags(); /* save lots of GL state * TODO: check on whether all of these are needed? */ @@ -782,7 +782,7 @@ static void paint_draw_alpha_overlay(UnifiedPaintSettings *ups, Brush *brush, paint_draw_cursor_overlay(ups, brush, vc, x, y, zoom); } else { - if (!(flags & PAINT_OVERLAY_OVERRIDE_PRIMARY) && (mode != PAINT_WEIGHT)) + if (!(flags & PAINT_OVERLAY_OVERRIDE_PRIMARY) && (mode != ePaintWeight)) paint_draw_tex_overlay(ups, brush, vc, x, y, zoom, false, true); if (!(flags & PAINT_OVERLAY_OVERRIDE_CURSOR)) paint_draw_cursor_overlay(ups, brush, vc, x, y, zoom); @@ -958,7 +958,7 @@ static void paint_cursor_on_hit(UnifiedPaintSettings *ups, Brush *brush, ViewCon static bool ommit_cursor_drawing(Paint *paint, PaintMode mode, Brush *brush) { if (paint->flags & PAINT_SHOW_BRUSH) { - if (ELEM(mode, PAINT_TEXTURE_2D, PAINT_TEXTURE_PROJECTIVE) && brush->imagepaint_tool == PAINT_TOOL_FILL) { + if (ELEM(mode, ePaintTexture2D, ePaintTextureProjective) && brush->imagepaint_tool == PAINT_TOOL_FILL) { return true; } return false; @@ -1014,7 +1014,7 @@ static void paint_draw_cursor(bContext *C, int x, int y, void *UNUSED(unused)) /* TODO: as sculpt and other paint modes are unified, this * special mode of drawing will go away */ - if ((mode == PAINT_SCULPT) && vc.obact->sculpt) { + if ((mode == ePaintSculpt) && vc.obact->sculpt) { float location[3]; int pixel_radius; bool hit; @@ -1056,7 +1056,7 @@ static void paint_draw_cursor(bContext *C, int x, int y, void *UNUSED(unused)) glColor4f(outline_col[0], outline_col[1], outline_col[2], outline_alpha); /* draw brush outline */ - glTranslatef(translation[0], translation[1], 0); + glTranslate2fv(translation); /* draw an inner brush */ if (ups->stroke_active && BKE_brush_use_size_pressure(scene, brush)) { diff --git a/source/blender/editors/sculpt_paint/paint_curve.c b/source/blender/editors/sculpt_paint/paint_curve.c index ebe5268ec5c..2f27db835f5 100644 --- a/source/blender/editors/sculpt_paint/paint_curve.c +++ b/source/blender/editors/sculpt_paint/paint_curve.c @@ -134,12 +134,12 @@ static void paintcurve_undo_begin(bContext *C, wmOperator *op, PaintCurve *pc) UndoCurve *uc; switch (mode) { - case PAINT_TEXTURE_2D: - case PAINT_TEXTURE_PROJECTIVE: + case ePaintTexture2D: + case ePaintTextureProjective: undo_stack_id = UNDO_PAINT_IMAGE; break; - case PAINT_SCULPT: + case ePaintSculpt: undo_stack_id = UNDO_PAINT_MESH; break; @@ -737,17 +737,17 @@ static int paintcurve_draw_exec(bContext *C, wmOperator *UNUSED(op)) const char *name; switch (mode) { - case PAINT_TEXTURE_2D: - case PAINT_TEXTURE_PROJECTIVE: + case ePaintTexture2D: + case ePaintTextureProjective: name = "PAINT_OT_image_paint"; break; - case PAINT_WEIGHT: + case ePaintWeight: name = "PAINT_OT_weight_paint"; break; - case PAINT_VERTEX: + case ePaintVertex: name = "PAINT_OT_vertex_paint"; break; - case PAINT_SCULPT: + case ePaintSculpt: name = "SCULPT_OT_brush_stroke"; break; default: @@ -777,7 +777,7 @@ static int paintcurve_cursor_invoke(bContext *C, wmOperator *UNUSED(op), const w PaintMode mode = BKE_paintmode_get_active_from_context(C); switch (mode) { - case PAINT_TEXTURE_2D: + case ePaintTexture2D: { ARegion *ar = CTX_wm_region(C); SpaceImage *sima = CTX_wm_space_image(C); diff --git a/source/blender/editors/sculpt_paint/paint_image.c b/source/blender/editors/sculpt_paint/paint_image.c index 64e0aa822df..f0c9c023876 100644 --- a/source/blender/editors/sculpt_paint/paint_image.c +++ b/source/blender/editors/sculpt_paint/paint_image.c @@ -1045,8 +1045,9 @@ static void toggle_paint_cursor(bContext *C, int enable) * purpose is to make sure the paint cursor is shown if paint * mode is enabled in the image editor. the paint poll will * ensure that the cursor is hidden when not in paint mode */ -void ED_space_image_paint_update(wmWindowManager *wm, ToolSettings *settings) +void ED_space_image_paint_update(wmWindowManager *wm, Scene *scene) { + ToolSettings *settings = scene->toolsettings; wmWindow *win; ScrArea *sa; ImagePaintSettings *imapaint = &settings->imapaint; @@ -1059,7 +1060,7 @@ void ED_space_image_paint_update(wmWindowManager *wm, ToolSettings *settings) enabled = true; if (enabled) { - BKE_paint_init(&settings->unified_paint_settings, &imapaint->paint, PAINT_CURSOR_TEXTURE_PAINT); + BKE_paint_init(scene, ePaintTexture2D, PAINT_CURSOR_TEXTURE_PAINT); paint_cursor_start_explicit(&imapaint->paint, wm, image_paint_poll); } @@ -1212,7 +1213,7 @@ static int sample_color_exec(bContext *C, wmOperator *op) RNA_int_get_array(op->ptr, "location", location); use_palette = RNA_boolean_get(op->ptr, "palette"); - paint_sample_color(C, ar, location[0], location[1], mode == PAINT_TEXTURE_PROJECTIVE, use_palette); + paint_sample_color(C, ar, location[0], location[1], mode == ePaintTextureProjective, use_palette); if (show_cursor) { paint->flags |= PAINT_SHOW_BRUSH; @@ -1250,7 +1251,7 @@ static int sample_color_invoke(bContext *C, wmOperator *op, const wmEvent *event RNA_int_set_array(op->ptr, "location", event->mval); - paint_sample_color(C, ar, event->mval[0], event->mval[1], mode == PAINT_TEXTURE_PROJECTIVE, false); + paint_sample_color(C, ar, event->mval[0], event->mval[1], mode == ePaintTextureProjective, false); WM_cursor_modal_set(win, BC_EYEDROPPER_CURSOR); WM_event_add_notifier(C, NC_BRUSH | NA_EDITED, brush); @@ -1289,7 +1290,7 @@ static int sample_color_modal(bContext *C, wmOperator *op, const wmEvent *event) { ARegion *ar = CTX_wm_region(C); RNA_int_set_array(op->ptr, "location", event->mval); - paint_sample_color(C, ar, event->mval[0], event->mval[1], mode == PAINT_TEXTURE_PROJECTIVE, false); + paint_sample_color(C, ar, event->mval[0], event->mval[1], mode == ePaintTextureProjective, false); WM_event_add_notifier(C, NC_BRUSH | NA_EDITED, brush); break; } @@ -1298,7 +1299,7 @@ static int sample_color_modal(bContext *C, wmOperator *op, const wmEvent *event) if (event->val == KM_PRESS) { ARegion *ar = CTX_wm_region(C); RNA_int_set_array(op->ptr, "location", event->mval); - paint_sample_color(C, ar, event->mval[0], event->mval[1], mode == PAINT_TEXTURE_PROJECTIVE, true); + paint_sample_color(C, ar, event->mval[0], event->mval[1], mode == ePaintTextureProjective, true); if (!data->sample_palette) { data->sample_palette = true; sample_color_update_header(data, C); @@ -1416,7 +1417,7 @@ static int texture_paint_toggle_exec(bContext *C, wmOperator *op) ob->mode |= mode_flag; - BKE_paint_init(&scene->toolsettings->unified_paint_settings, &imapaint->paint, PAINT_CURSOR_TEXTURE_PAINT); + BKE_paint_init(scene, ePaintTextureProjective, PAINT_CURSOR_TEXTURE_PAINT); if (U.glreslimit != 0) GPU_free_images(); diff --git a/source/blender/editors/sculpt_paint/paint_image_2d.c b/source/blender/editors/sculpt_paint/paint_image_2d.c index 03a96fb149a..c5a066e9b14 100644 --- a/source/blender/editors/sculpt_paint/paint_image_2d.c +++ b/source/blender/editors/sculpt_paint/paint_image_2d.c @@ -1601,6 +1601,7 @@ void paint_2d_gradient_fill( break; } case BRUSH_GRADIENT_RADIAL: + default: { f = len_v2(p) / line_len; break; @@ -1629,6 +1630,7 @@ void paint_2d_gradient_fill( break; } case BRUSH_GRADIENT_RADIAL: + default: { f = len_v2(p) / line_len; break; diff --git a/source/blender/editors/sculpt_paint/paint_image_proj.c b/source/blender/editors/sculpt_paint/paint_image_proj.c index 2b0aba9e3fb..565f8a51610 100644 --- a/source/blender/editors/sculpt_paint/paint_image_proj.c +++ b/source/blender/editors/sculpt_paint/paint_image_proj.c @@ -298,6 +298,7 @@ typedef struct ProjPaintState { float cloneOffset[2]; float projectMat[4][4]; /* Projection matrix, use for getting screen coords */ + float projectMatInv[4][4]; /* inverse of projectMat */ float viewDir[3]; /* View vector, use for do_backfacecull and for ray casting with an ortho viewport */ float viewPos[3]; /* View location in object relative 3D space, so can compare to verts */ float clipsta, clipend; @@ -1247,6 +1248,55 @@ static void screen_px_from_persp( } +/** + * Set a direction vector based on a screen location. + * (use for perspective view, else we can simply use `ps->viewDir`) + * + * Similar functionality to #ED_view3d_win_to_vector + * + * \param r_dir: Resulting direction (length is undefined). + */ +static void screen_px_to_vector_persp( + int winx, int winy, const float projmat_inv[4][4], const float view_pos[3], + const float co_px[2], + float r_dir[3]) +{ + r_dir[0] = 2.0f * (co_px[0] / winx) - 1.0f; + r_dir[1] = 2.0f * (co_px[1] / winy) - 1.0f; + r_dir[2] = -0.5f; + mul_project_m4_v3((float(*)[4])projmat_inv, r_dir); + sub_v3_v3(r_dir, view_pos); +} + +/** + * Special function to return the factor to a point along a line in pixel space. + * + * This is needed since we can't use #line_point_factor_v2 for perspective screen-space coords. + * + * \param p: 2D screen-space location. + * \param v1, v2: 3D object-space locations. + */ +static float screen_px_line_point_factor_v2_persp( + const ProjPaintState *ps, + const float p[2], + const float v1[3], const float v2[3]) +{ + const float zero[3] = {0}; + float v1_proj[3], v2_proj[3]; + float dir[3]; + + screen_px_to_vector_persp(ps->winx, ps->winy, ps->projectMatInv, ps->viewPos, p, dir); + + sub_v3_v3v3(v1_proj, v1, ps->viewPos); + sub_v3_v3v3(v2_proj, v2, ps->viewPos); + + project_plane_v3_v3v3(v1_proj, v1_proj, dir); + project_plane_v3_v3v3(v2_proj, v2_proj, dir); + + return line_point_factor_v2(zero, v1_proj, v2_proj); +} + + static void project_face_pixel( const float *lt_tri_uv[3], ImBuf *ibuf_other, const float w[3], unsigned char rgba_ub[4], float rgba_f[4]) @@ -2680,8 +2730,15 @@ static void project_paint_face_init( line_clip_rect2f(clip_rect, bucket_bounds, vCoSS[fidx1], vCoSS[fidx2], bucket_clip_edges[0], bucket_clip_edges[1])) { if (len_squared_v2v2(vCoSS[fidx1], vCoSS[fidx2]) > FLT_EPSILON) { /* avoid div by zero */ - fac1 = line_point_factor_v2(bucket_clip_edges[0], vCoSS[fidx1], vCoSS[fidx2]); - fac2 = line_point_factor_v2(bucket_clip_edges[1], vCoSS[fidx1], vCoSS[fidx2]); + + if (is_ortho) { + fac1 = line_point_factor_v2(bucket_clip_edges[0], vCoSS[fidx1], vCoSS[fidx2]); + fac2 = line_point_factor_v2(bucket_clip_edges[1], vCoSS[fidx1], vCoSS[fidx2]); + } + else { + fac1 = screen_px_line_point_factor_v2_persp(ps, bucket_clip_edges[0], vCo[fidx1], vCo[fidx2]); + fac2 = screen_px_line_point_factor_v2_persp(ps, bucket_clip_edges[1], vCo[fidx1], vCo[fidx2]); + } interp_v2_v2v2(seam_subsection[0], lt_uv_pxoffset[fidx1], lt_uv_pxoffset[fidx2], fac1); interp_v2_v2v2(seam_subsection[1], lt_uv_pxoffset[fidx1], lt_uv_pxoffset[fidx2], fac2); @@ -2695,7 +2752,7 @@ static void project_paint_face_init( interp_v3_v3v3(edge_verts_inset_clip[1], insetCos[fidx1], insetCos[fidx2], fac2); - if (pixel_bounds_uv(seam_subsection, &bounds_px, ibuf->x, ibuf->y)) { + if (pixel_bounds_uv((const float (*)[2])seam_subsection, &bounds_px, ibuf->x, ibuf->y)) { /* bounds between the seam rect and the uvspace bucket pixels */ has_isect = 0; @@ -3104,6 +3161,7 @@ static void proj_paint_state_viewport_init( mul_m4_m4m4(ps->projectMat, winmat, vmat); } + invert_m4_m4(ps->projectMatInv, ps->projectMat); /* viewDir - object relative */ copy_m3_m4(mat, viewinv); @@ -3559,34 +3617,6 @@ static bool project_paint_winclip( } #endif //PROJ_DEBUG_WINCLIP -/* Return true if face should be culled, false otherwise */ -static bool project_paint_backface_cull( - const ProjPaintState *ps, const MLoopTri *lt, - const ProjPaintFaceCoSS *coSS) -{ - if (ps->do_backfacecull) { - if (ps->do_mask_normal) { - const int lt_vtri[3] = { PS_LOOPTRI_AS_VERT_INDEX_3(ps, lt) }; - /* Since we are interpolating the normals of faces, we want to make - * sure all the verts are pointing away from the view, - * not just the face */ - if ((ps->vertFlags[lt_vtri[0]] & PROJ_VERT_CULL) && - (ps->vertFlags[lt_vtri[1]] & PROJ_VERT_CULL) && - (ps->vertFlags[lt_vtri[2]] & PROJ_VERT_CULL)) - { - return true; - } - } - else { - if ((line_point_side_v2(coSS->v1, coSS->v2, coSS->v3) < 0.0f) != ps->is_flip_object) { - return true; - } - - } - } - - return false; -} static void project_paint_build_proj_ima( ProjPaintState *ps, MemArena *arena, @@ -3631,6 +3661,7 @@ static void project_paint_prepare_all_faces( TexPaintSlot *slot = NULL; const MLoopTri *lt; int image_index = -1, tri_index; + int prev_poly = -1; for (tri_index = 0, lt = ps->dm_mlooptri; tri_index < ps->dm_totlooptri; tri_index++, lt++) { bool is_face_sel; @@ -3691,8 +3722,37 @@ static void project_paint_prepare_all_faces( #endif //PROJ_DEBUG_WINCLIP - if (project_paint_backface_cull(ps, lt, &coSS)) { - continue; + /* backface culls individual triangles but mask normal will use polygon */ + if (ps->do_backfacecull) { + if (ps->do_mask_normal) { + if (prev_poly != lt->poly) { + int iloop; + bool culled = true; + const MPoly *poly = ps->dm_mpoly + lt->poly; + int poly_loops = poly->totloop; + prev_poly = lt->poly; + for (iloop = 0; iloop < poly_loops; iloop++) { + if (!(ps->vertFlags[ps->dm_mloop[poly->loopstart + iloop].v] & PROJ_VERT_CULL)) { + culled = false; + break; + } + } + + if (culled) { + /* poly loops - 2 is number of triangles for poly, + * but counter gets incremented when continuing, so decrease by 3 */ + int poly_tri = poly_loops - 3; + tri_index += poly_tri; + lt += poly_tri; + continue; + } + } + } + else { + if ((line_point_side_v2(coSS.v1, coSS.v2, coSS.v3) < 0.0f) != ps->is_flip_object) { + continue; + } + } } } @@ -4264,7 +4324,7 @@ static void do_projectpaint_soften(ProjPaintState *ps, ProjPixel *projPixel, flo } else { premul_float_to_straight_uchar(rgba_ub, rgba); - blend_color_interpolate_byte(rgba_ub, rgba_ub, projPixel->pixel.ch_pt, mask); + blend_color_interpolate_byte(rgba_ub, projPixel->pixel.ch_pt, rgba_ub, mask); } BLI_linklist_prepend_arena(softenPixels, (void *)projPixel, softenArena); } @@ -4472,6 +4532,7 @@ static void *do_projectpaint_thread(void *ph_v) break; } case BRUSH_GRADIENT_RADIAL: + default: { f = len_v2(p) / line_len; break; @@ -5338,7 +5399,10 @@ static int texture_paint_image_from_view_exec(bContext *C, wmOperator *op) if (w > maxsize) w = maxsize; if (h > maxsize) h = maxsize; - ibuf = ED_view3d_draw_offscreen_imbuf(scene, CTX_wm_view3d(C), CTX_wm_region(C), w, h, IB_rect, false, R_ALPHAPREMUL, NULL, err_out); + ibuf = ED_view3d_draw_offscreen_imbuf( + scene, CTX_wm_view3d(C), CTX_wm_region(C), + w, h, IB_rect, false, R_ALPHAPREMUL, 0, NULL, + NULL, err_out); if (!ibuf) { /* Mostly happens when OpenGL offscreen buffer was failed to create, */ /* but could be other reasons. Should be handled in the future. nazgul */ @@ -5352,7 +5416,7 @@ static int texture_paint_image_from_view_exec(bContext *C, wmOperator *op) IMB_freeImBuf(ibuf); if (image) { - /* now for the trickyness. store the view projection here! + /* now for the trickiness. store the view projection here! * re-projection will reuse this */ View3D *v3d = CTX_wm_view3d(C); RegionView3D *rv3d = CTX_wm_region_view3d(C); diff --git a/source/blender/editors/sculpt_paint/paint_ops.c b/source/blender/editors/sculpt_paint/paint_ops.c index eebd49895ef..05eda4da63b 100644 --- a/source/blender/editors/sculpt_paint/paint_ops.c +++ b/source/blender/editors/sculpt_paint/paint_ops.c @@ -66,11 +66,12 @@ static int brush_add_exec(bContext *C, wmOperator *UNUSED(op)) Paint *paint = BKE_paint_get_active_from_context(C); Brush *br = BKE_paint_brush(paint); Main *bmain = CTX_data_main(C); + PaintMode mode = BKE_paintmode_get_active_from_context(C); if (br) br = BKE_brush_copy(br); else - br = BKE_brush_add(bmain, "Brush"); + br = BKE_brush_add(bmain, "Brush", BKE_paint_object_mode_from_paint_mode(mode)); BKE_paint_brush_set(paint, br); @@ -201,11 +202,11 @@ static int palette_color_add_exec(bContext *C, wmOperator *UNUSED(op)) color = BKE_palette_color_add(palette); palette->active_color = BLI_listbase_count(&palette->colors) - 1; - if (ELEM(mode, PAINT_TEXTURE_PROJECTIVE, PAINT_TEXTURE_2D, PAINT_VERTEX)) { + if (ELEM(mode, ePaintTextureProjective, ePaintTexture2D, ePaintVertex)) { copy_v3_v3(color->rgb, BKE_brush_color_get(scene, brush)); color->value = 0.0; } - else if (mode == PAINT_WEIGHT) { + else if (mode == ePaintWeight) { zero_v3(color->rgb); color->value = brush->weight; } @@ -431,9 +432,8 @@ static int brush_generic_tool_set(Main *bmain, Paint *paint, const int tool, brush = brush_tool_cycle(bmain, brush_orig, tool, tool_offset, ob_mode); if (!brush && brush_tool(brush_orig, tool_offset) != tool && create_missing) { - brush = BKE_brush_add(bmain, tool_name); + brush = BKE_brush_add(bmain, tool_name, ob_mode); brush_tool_set(brush, tool_offset, tool); - brush->ob_mode = ob_mode; brush->toggle_brush = brush_orig; } diff --git a/source/blender/editors/sculpt_paint/paint_stroke.c b/source/blender/editors/sculpt_paint/paint_stroke.c index a6d80953178..b1ddf1172c8 100644 --- a/source/blender/editors/sculpt_paint/paint_stroke.c +++ b/source/blender/editors/sculpt_paint/paint_stroke.c @@ -194,7 +194,7 @@ static void paint_draw_line_cursor(bContext *C, int x, int y, void *customdata) static bool paint_tool_require_location(Brush *brush, PaintMode mode) { switch (mode) { - case PAINT_SCULPT: + case ePaintSculpt: if (ELEM(brush->sculpt_tool, SCULPT_TOOL_GRAB, SCULPT_TOOL_ROTATE, SCULPT_TOOL_SNAKE_HOOK, SCULPT_TOOL_THUMB)) { @@ -224,6 +224,7 @@ static bool paint_brush_update(bContext *C, bool location_sampled = false; bool location_success = false; bool do_random = false; + bool do_random_mask = false; /* XXX: Use pressure value from first brush step for brushes which don't * support strokes (grab, thumb). They depends on initial state and * brush coord/pressure/etc. @@ -271,9 +272,11 @@ static bool paint_brush_update(bContext *C, } if (paint_supports_dynamic_tex_coords(brush, mode)) { - if (((brush->mtex.brush_map_mode == MTEX_MAP_MODE_VIEW) || - (brush->mtex.brush_map_mode == MTEX_MAP_MODE_AREA) || - (brush->mtex.brush_map_mode == MTEX_MAP_MODE_RANDOM))) + + if (ELEM(brush->mtex.brush_map_mode, + MTEX_MAP_MODE_VIEW, + MTEX_MAP_MODE_AREA, + MTEX_MAP_MODE_RANDOM)) { do_random = true; } @@ -286,6 +289,15 @@ static bool paint_brush_update(bContext *C, /* take care of mask texture, if any */ if (brush->mask_mtex.tex) { + + if (ELEM(brush->mask_mtex.brush_map_mode, + MTEX_MAP_MODE_VIEW, + MTEX_MAP_MODE_AREA, + MTEX_MAP_MODE_RANDOM)) + { + do_random_mask = true; + } + if (brush->mask_mtex.brush_map_mode == MTEX_MAP_MODE_RANDOM) BKE_brush_randomize_texture_coords(ups, true); else { @@ -358,7 +370,9 @@ static bool paint_brush_update(bContext *C, ups->brush_rotation += -brush->mtex.random_angle / 2.0f + brush->mtex.random_angle * BLI_frand(); } + } + if (do_random_mask) { if (brush->mask_mtex.brush_angle_mode & MTEX_ANGLE_RANDOM) { ups->brush_rotation_sec += -brush->mask_mtex.random_angle / 2.0f + brush->mask_mtex.random_angle * BLI_frand(); @@ -389,7 +403,7 @@ static bool paint_stroke_use_jitter(PaintMode mode, Brush *brush, bool invert) /* jitter-ed brush gives weird and unpredictable result for this * kinds of stroke, so manually disable jitter usage (sergey) */ use_jitter &= (brush->flag & (BRUSH_DRAG_DOT | BRUSH_ANCHORED)) == 0; - use_jitter &= (!ELEM(mode, PAINT_TEXTURE_2D, PAINT_TEXTURE_PROJECTIVE) || + use_jitter &= (!ELEM(mode, ePaintTexture2D, ePaintTextureProjective) || !(invert && brush->imagepaint_tool == PAINT_TOOL_CLONE)); @@ -760,13 +774,13 @@ bool paint_supports_dynamic_size(Brush *br, PaintMode mode) return false; switch (mode) { - case PAINT_SCULPT: + case ePaintSculpt: if (sculpt_is_grab_tool(br)) return false; break; - case PAINT_TEXTURE_2D: /* fall through */ - case PAINT_TEXTURE_PROJECTIVE: + case ePaintTexture2D: /* fall through */ + case ePaintTextureProjective: if ((br->imagepaint_tool == PAINT_TOOL_FILL) && (br->flag & BRUSH_USE_GRADIENT)) { @@ -789,7 +803,7 @@ bool paint_supports_smooth_stroke(Brush *br, PaintMode mode) } switch (mode) { - case PAINT_SCULPT: + case ePaintSculpt: if (sculpt_is_grab_tool(br)) return false; break; @@ -802,7 +816,7 @@ bool paint_supports_smooth_stroke(Brush *br, PaintMode mode) bool paint_supports_texture(PaintMode mode) { /* omit: PAINT_WEIGHT, PAINT_SCULPT_UV, PAINT_INVALID */ - return ELEM(mode, PAINT_SCULPT, PAINT_VERTEX, PAINT_TEXTURE_PROJECTIVE, PAINT_TEXTURE_2D); + return ELEM(mode, ePaintSculpt, ePaintVertex, ePaintTextureProjective, ePaintTexture2D); } /* return true if the brush size can change during paint (normally used for pressure) */ @@ -812,7 +826,7 @@ bool paint_supports_dynamic_tex_coords(Brush *br, PaintMode mode) return false; switch (mode) { - case PAINT_SCULPT: + case ePaintSculpt: if (sculpt_is_grab_tool(br)) return false; break; diff --git a/source/blender/editors/sculpt_paint/paint_vertex.c b/source/blender/editors/sculpt_paint/paint_vertex.c index 23f388d2a58..8daad9deea9 100644 --- a/source/blender/editors/sculpt_paint/paint_vertex.c +++ b/source/blender/editors/sculpt_paint/paint_vertex.c @@ -1956,7 +1956,7 @@ static int wpaint_mode_toggle_exec(bContext *C, wmOperator *op) paint_cursor_start(C, weight_paint_poll); - BKE_paint_init(&scene->toolsettings->unified_paint_settings, &wp->paint, PAINT_CURSOR_WEIGHT_PAINT); + BKE_paint_init(scene, ePaintWeight, PAINT_CURSOR_WEIGHT_PAINT); /* weight paint specific */ ED_mesh_mirror_spatial_table(ob, NULL, NULL, 's'); @@ -2564,7 +2564,7 @@ static int vpaint_mode_toggle_exec(bContext *C, wmOperator *op) paint_cursor_start(C, vertex_paint_poll); - BKE_paint_init(&scene->toolsettings->unified_paint_settings, &vp->paint, PAINT_CURSOR_VERTEX_PAINT); + BKE_paint_init(scene, ePaintVertex, PAINT_CURSOR_VERTEX_PAINT); } /* update modifier stack for mapping requirements */ @@ -2675,7 +2675,7 @@ static bool vpaint_stroke_test_start(bContext *C, struct wmOperator *op, const f brush->mtex.tex; /* are we painting onto a modified mesh?, - * if not we can skip face map trickyness */ + * if not we can skip face map trickiness */ if (vertex_paint_use_fast_update_check(ob)) { vpd->use_fast_update = true; /* printf("Fast update!\n");*/ diff --git a/source/blender/editors/sculpt_paint/sculpt.c b/source/blender/editors/sculpt_paint/sculpt.c index 3800271e0cb..07511e1924e 100644 --- a/source/blender/editors/sculpt_paint/sculpt.c +++ b/source/blender/editors/sculpt_paint/sculpt.c @@ -4062,7 +4062,7 @@ static void sculpt_update_cache_variants(bContext *C, Sculpt *sd, Object *ob, * brush coord/pressure/etc. * It's more an events design issue, which doesn't split coordinate/pressure/angle * changing events. We should avoid this after events system re-design */ - if (paint_supports_dynamic_size(brush, PAINT_SCULPT) || cache->first_time) { + if (paint_supports_dynamic_size(brush, ePaintSculpt) || cache->first_time) { cache->pressure = RNA_float_get(ptr, "pressure"); } @@ -4079,7 +4079,7 @@ static void sculpt_update_cache_variants(bContext *C, Sculpt *sd, Object *ob, } } - if (BKE_brush_use_size_pressure(scene, brush) && paint_supports_dynamic_size(brush, PAINT_SCULPT)) { + if (BKE_brush_use_size_pressure(scene, brush) && paint_supports_dynamic_size(brush, ePaintSculpt)) { cache->radius = cache->initial_radius * cache->pressure; } else { @@ -4217,7 +4217,10 @@ static float sculpt_raycast_init(ViewContext *vc, const float mouse[2], float ra sub_v3_v3v3(ray_normal, ray_end, ray_start); dist = normalize_v3(ray_normal); - if (!rv3d->is_persp) { + if ((rv3d->is_persp == false) && + /* if the ray is clipped, don't adjust its start/end */ + ((rv3d->rflag & RV3D_CLIPPING) == 0)) + { BKE_pbvh_raycast_project_ray_root(ob->sculpt->pbvh, original, ray_start, ray_end, ray_normal); /* recalculate the normal */ @@ -5141,7 +5144,7 @@ static int sculpt_mode_toggle_exec(bContext *C, wmOperator *op) "Object has negative scale, sculpting may be unpredictable"); } - BKE_paint_init(&ts->unified_paint_settings, &ts->sculpt->paint, PAINT_CURSOR_SCULPT); + BKE_paint_init(scene, ePaintSculpt, PAINT_CURSOR_SCULPT); paint_cursor_start(C, sculpt_poll_view3d); } diff --git a/source/blender/editors/sculpt_paint/sculpt_uv.c b/source/blender/editors/sculpt_paint/sculpt_uv.c index e01d8a6bd17..405ac3f6808 100644 --- a/source/blender/editors/sculpt_paint/sculpt_uv.c +++ b/source/blender/editors/sculpt_paint/sculpt_uv.c @@ -224,8 +224,9 @@ static void brush_drawcursor_uvsculpt(bContext *C, int x, int y, void *UNUSED(cu } -void ED_space_image_uv_sculpt_update(wmWindowManager *wm, ToolSettings *settings) +void ED_space_image_uv_sculpt_update(wmWindowManager *wm, Scene *scene) { + ToolSettings *settings = scene->toolsettings; if (settings->use_uv_sculpt) { if (!settings->uvsculpt) { settings->uvsculpt = MEM_callocN(sizeof(*settings->uvsculpt), "UV Smooth paint"); @@ -236,7 +237,7 @@ void ED_space_image_uv_sculpt_update(wmWindowManager *wm, ToolSettings *settings settings->uvsculpt->paint.flags |= PAINT_SHOW_BRUSH; } - BKE_paint_init(&settings->unified_paint_settings, &settings->uvsculpt->paint, PAINT_CURSOR_SCULPT); + BKE_paint_init(scene, ePaintSculptUV, PAINT_CURSOR_SCULPT); settings->uvsculpt->paint.paint_cursor = WM_paint_cursor_activate(wm, uv_sculpt_brush_poll, brush_drawcursor_uvsculpt, NULL); diff --git a/source/blender/editors/space_action/action_edit.c b/source/blender/editors/space_action/action_edit.c index b2e046ee24b..e351fb57d9a 100644 --- a/source/blender/editors/space_action/action_edit.c +++ b/source/blender/editors/space_action/action_edit.c @@ -223,7 +223,7 @@ static bool get_keyframe_extents(bAnimContext *ac, float *min, float *max, const float tmin, tmax; /* get range and apply necessary scaling before processing */ - if (calc_fcurve_range(fcu, &tmin, &tmax, onlySel, true)) { + if (calc_fcurve_range(fcu, &tmin, &tmax, onlySel, false)) { if (adt) { tmin = BKE_nla_tweakedit_remap(adt, tmin, NLATIME_CONVERT_MAP); @@ -237,7 +237,7 @@ static bool get_keyframe_extents(bAnimContext *ac, float *min, float *max, const } } } - + /* free memory */ ANIM_animdata_freelist(&anim_data); } @@ -275,8 +275,12 @@ static int actkeys_previewrange_exec(bContext *C, wmOperator *UNUSED(op)) /* set the range directly */ get_keyframe_extents(&ac, &min, &max, false); scene->r.flag |= SCER_PRV_RANGE; - scene->r.psfra = iroundf(min); - scene->r.pefra = iroundf(max); + scene->r.psfra = floorf(min); + scene->r.pefra = ceilf(max); + + if (scene->r.psfra == scene->r.pefra) { + scene->r.pefra = scene->r.psfra + 1; + } /* set notifier that things have changed */ // XXX err... there's nothing for frame ranges yet, but this should do fine too diff --git a/source/blender/editors/space_buttons/buttons_texture.c b/source/blender/editors/space_buttons/buttons_texture.c index b56ff850c35..6bdcee8aaef 100644 --- a/source/blender/editors/space_buttons/buttons_texture.c +++ b/source/blender/editors/space_buttons/buttons_texture.c @@ -539,6 +539,9 @@ static void template_texture_select(bContext *C, void *user_p, void *UNUSED(arg) if (user->ptr.data == part->mtex[a]) part->texact = a; } + + if (sbuts && tex) + sbuts->preview = 1; } ct->user = user; diff --git a/source/blender/editors/space_clip/clip_draw.c b/source/blender/editors/space_clip/clip_draw.c index 74a9eb480b7..40505d28d39 100644 --- a/source/blender/editors/space_clip/clip_draw.c +++ b/source/blender/editors/space_clip/clip_draw.c @@ -286,7 +286,6 @@ static void draw_movieclip_buffer(const bContext *C, SpaceClip *sc, ARegion *ar, MovieClip *clip = ED_space_clip_get_clip(sc); int filter = GL_LINEAR; int x, y; - rctf frame; /* find window pixel coordinates of origin */ UI_view2d_view_to_region(&ar->v2d, 0.0f, 0.0f, &x, &y); @@ -314,10 +313,12 @@ static void draw_movieclip_buffer(const bContext *C, SpaceClip *sc, ARegion *ar, /* reset zoom */ glPixelZoom(1.0f, 1.0f); - BLI_rctf_init(&frame, 0.0f, ibuf->x, 0.0f, ibuf->y); - if (sc->flag & SC_SHOW_METADATA) - ED_region_image_metadata_draw(x, y, ibuf, frame, zoomx * width / ibuf->x, zoomy * height / ibuf->y); + if (sc->flag & SC_SHOW_METADATA) { + rctf frame; + BLI_rctf_init(&frame, 0.0f, ibuf->x, 0.0f, ibuf->y); + ED_region_image_metadata_draw(x, y, ibuf, &frame, zoomx * width / ibuf->x, zoomy * height / ibuf->y); + } if (ibuf->planes == 32) glDisable(GL_BLEND); @@ -521,7 +522,7 @@ static void draw_marker_outline(SpaceClip *sc, MovieTrackingTrack *track, MovieT /* pattern and search outline */ glPushMatrix(); - glTranslatef(marker_pos[0], marker_pos[1], 0); + glTranslate2fv(marker_pos); if (!tiny) glLineWidth(3.0f); @@ -653,7 +654,7 @@ static void draw_marker_areas(SpaceClip *sc, MovieTrackingTrack *track, MovieTra /* pattern */ glPushMatrix(); - glTranslatef(marker_pos[0], marker_pos[1], 0); + glTranslate2fv(marker_pos); if (tiny) { glLineStipple(3, 0xaaaa); @@ -806,7 +807,7 @@ static void draw_marker_slide_zones(SpaceClip *sc, MovieTrackingTrack *track, Mo } glPushMatrix(); - glTranslatef(marker_pos[0], marker_pos[1], 0); + glTranslate2fv(marker_pos); dx = 6.0f / width / sc->zoom; dy = 6.0f / height / sc->zoom; @@ -1260,7 +1261,7 @@ static void draw_tracking_tracks(SpaceClip *sc, Scene *scene, ARegion *ar, Movie /* ** find window pixel coordinates of origin ** */ /* UI_view2d_view_to_region_no_clip return integer values, this could - * lead to 1px flickering when view is locked to selection during playbeck. + * lead to 1px flickering when view is locked to selection during playback. * to avoid this flickering, calculate base point in the same way as it happens * in UI_view2d_view_to_region_no_clip, but do it in floats here */ @@ -1787,7 +1788,7 @@ void clip_draw_grease_pencil(bContext *C, int onlyv2d) int framenr = ED_space_clip_get_clip_frame_number(sc); MovieTrackingMarker *marker = BKE_tracking_marker_get(track, framenr); - glTranslatef(marker->pos[0], marker->pos[1], 0.0f); + glTranslate2fv(marker->pos); } } diff --git a/source/blender/editors/space_clip/clip_ops.c b/source/blender/editors/space_clip/clip_ops.c index 55805e0b907..af3d460fe0f 100644 --- a/source/blender/editors/space_clip/clip_ops.c +++ b/source/blender/editors/space_clip/clip_ops.c @@ -213,7 +213,7 @@ static int open_exec(bContext *C, wmOperator *op) errno = 0; - clip = BKE_movieclip_file_add(bmain, str); + clip = BKE_movieclip_file_add_exists(bmain, str); if (!clip) { if (op->customdata) diff --git a/source/blender/editors/space_file/file_draw.c b/source/blender/editors/space_file/file_draw.c index dac9124a4cb..2d9ecbdf415 100644 --- a/source/blender/editors/space_file/file_draw.c +++ b/source/blender/editors/space_file/file_draw.c @@ -232,9 +232,17 @@ void file_draw_buttons(const bContext *C, ARegion *ar) /* Execute / cancel buttons. */ if (loadbutton) { const struct FileDirEntry *file = sfile->files ? filelist_file(sfile->files, params->active_file) : NULL; - const char *str_exec = (file && (file->typeflag & FILE_TYPE_FOLDER)) ? - /* params->title is already translated! */ - IFACE_("Open Directory") : params->title; + char const *str_exec; + + if (file && FILENAME_IS_PARENT(file->relpath)) { + str_exec = IFACE_("Parent Directory"); + } + else if (file && file->typeflag & FILE_TYPE_DIR) { + str_exec = IFACE_("Open Directory"); + } + else { + str_exec = params->title; /* params->title is already translated! */ + } uiDefButO(block, UI_BTYPE_BUT, "FILE_OT_execute", WM_OP_EXEC_REGION_WIN, str_exec, max_x - loadbutton, line1_y, loadbutton, btn_h, ""); diff --git a/source/blender/editors/space_file/file_ops.c b/source/blender/editors/space_file/file_ops.c index 7f5e6b93cfb..36572d6469d 100644 --- a/source/blender/editors/space_file/file_ops.c +++ b/source/blender/editors/space_file/file_ops.c @@ -237,6 +237,49 @@ static bool file_is_any_selected(struct FileList *files) return false; } +/** + * If \a file is outside viewbounds, this adjusts view to make sure it's inside + */ +static void file_ensure_inside_viewbounds(ARegion *ar, SpaceFile *sfile, const int file) +{ + FileLayout *layout = ED_fileselect_get_layout(sfile, ar); + rctf *cur = &ar->v2d.cur; + rcti rect; + bool changed = true; + + file_tile_boundbox(ar, layout, file, &rect); + + /* down - also use if tile is higher than viewbounds so view is aligned to file name */ + if (cur->ymin > rect.ymin || layout->tile_h > ar->winy) { + cur->ymin = rect.ymin - (2 * layout->tile_border_y); + cur->ymax = cur->ymin + ar->winy; + } + /* up */ + else if (cur->ymax < rect.ymax) { + cur->ymax = rect.ymax + layout->tile_border_y; + cur->ymin = cur->ymax - ar->winy; + } + /* left - also use if tile is wider than viewbounds so view is aligned to file name */ + else if (cur->xmin > rect.xmin || layout->tile_w > ar->winx) { + cur->xmin = rect.xmin - layout->tile_border_x; + cur->xmax = cur->xmin + ar->winx; + } + /* right */ + else if (cur->xmax < rect.xmax) { + cur->xmax = rect.xmax + (2 * layout->tile_border_x); + cur->xmin = cur->xmax - ar->winx; + } + else { + BLI_assert(cur->xmin <= rect.xmin && cur->xmax >= rect.xmax && + cur->ymin <= rect.ymin && cur->ymax >= rect.ymax); + changed = false; + } + + if (changed) { + UI_view2d_curRect_validate(&ar->v2d); + } +} + static FileSelect file_select(bContext *C, const rcti *rect, FileSelType select, bool fill, bool do_diropen) { @@ -262,6 +305,20 @@ static FileSelect file_select(bContext *C, const rcti *rect, FileSelType select, if (select != FILE_SEL_ADD && !file_is_any_selected(sfile->files)) { sfile->params->active_file = -1; } + else { + ARegion *ar = CTX_wm_region(C); + const FileLayout *layout = ED_fileselect_get_layout(sfile, ar); + + /* Adjust view to display selection. Doing iterations for first and last + * selected item makes view showing as much of the selection possible. + * Not really useful if tiles are (almost) bigger than viewbounds though. */ + if (((layout->flag & FILE_LAYOUT_HOR) && ar->winx > (1.2f * layout->tile_w)) || + ((layout->flag & FILE_LAYOUT_VER) && ar->winy > (2.0f * layout->tile_h))) + { + file_ensure_inside_viewbounds(ar, sfile, sel.last); + file_ensure_inside_viewbounds(ar, sfile, sel.first); + } + } /* update operator for name change event */ file_draw_check(C); @@ -276,6 +333,9 @@ static int file_border_select_find_last_selected( FileLayout *layout = ED_fileselect_get_layout(sfile, ar); rcti bounds_first, bounds_last; int dist_first, dist_last; + float mouseco_view[2]; + + UI_view2d_region_to_view(&ar->v2d, UNPACK2(mouse_xy), &mouseco_view[0], &mouseco_view[1]); file_tile_boundbox(ar, layout, sel->first, &bounds_first); file_tile_boundbox(ar, layout, sel->last, &bounds_last); @@ -285,18 +345,18 @@ static int file_border_select_find_last_selected( (layout->flag & FILE_LAYOUT_VER && bounds_first.ymin != bounds_last.ymin)) { /* use vertical distance */ - const int my_loc = mouse_xy[1] - ar->winrct.ymin; + const int my_loc = (int)mouseco_view[1]; dist_first = BLI_rcti_length_y(&bounds_first, my_loc); dist_last = BLI_rcti_length_y(&bounds_last, my_loc); } else { /* use horizontal distance */ - const int mx_loc = mouse_xy[0] - ar->winrct.xmin; + const int mx_loc = (int)mouseco_view[0]; dist_first = BLI_rcti_length_x(&bounds_first, mx_loc); dist_last = BLI_rcti_length_x(&bounds_last, mx_loc); } - return dist_first < dist_last ? sel->first : sel->last; + return (dist_first < dist_last) ? sel->first : sel->last; } static int file_border_select_modal(bContext *C, wmOperator *op, const wmEvent *event) @@ -339,7 +399,7 @@ static int file_border_select_modal(bContext *C, wmOperator *op, const wmEvent * } } params->sel_first = sel.first; params->sel_last = sel.last; - params->active_file = file_border_select_find_last_selected(sfile, ar, &sel, &event->x); + params->active_file = file_border_select_find_last_selected(sfile, ar, &sel, event->mval); } else { params->highlight_file = -1; @@ -571,6 +631,9 @@ static bool file_walk_select_selection_set( BLI_assert(IN_RANGE(active, -1, numfiles)); fileselect_file_set(sfile, params->active_file); + /* ensure newly selected file is inside viewbounds */ + file_ensure_inside_viewbounds(CTX_wm_region(C), sfile, params->active_file); + /* selection changed */ return true; } @@ -1831,12 +1894,13 @@ void file_filename_enter_handle(bContext *C, void *UNUSED(arg_unused), void *arg matched_file[0] = '\0'; filepath[0] = '\0'; - BLI_filename_make_safe(sfile->params->file); - file_expand_directory(C); matches = file_select_match(sfile, sfile->params->file, matched_file); + /* *After* file_select_match! */ + BLI_filename_make_safe(sfile->params->file); + if (matches) { /* int i, numfiles = filelist_numfiles(sfile->files); */ /* XXX UNUSED */ sfile->params->file[0] = '\0'; @@ -1969,6 +2033,37 @@ void FILE_OT_bookmark_toggle(struct wmOperatorType *ot) } +/** + * Looks for a string of digits within name (using BLI_stringdec) and adjusts it by add. + */ +static void filenum_newname(char *name, size_t name_size, int add) +{ + char head[FILE_MAXFILE], tail[FILE_MAXFILE]; + char name_temp[FILE_MAXFILE]; + int pic; + unsigned short digits; + + pic = BLI_stringdec(name, head, tail, &digits); + + /* are we going from 100 -> 99 or from 10 -> 9 */ + if (add < 0 && digits > 0) { + int i, exp; + exp = 1; + for (i = digits; i > 1; i--) { + exp *= 10; + } + if (pic >= exp && (pic + add) < exp) { + digits--; + } + } + + pic += add; + if (pic < 0) + pic = 0; + BLI_stringenc(name_temp, head, tail, digits, pic); + BLI_strncpy(name, name_temp, name_size); +} + static int file_filenum_exec(bContext *C, wmOperator *op) { SpaceFile *sfile = CTX_wm_space_file(C); @@ -1976,7 +2071,7 @@ static int file_filenum_exec(bContext *C, wmOperator *op) int inc = RNA_int_get(op->ptr, "increment"); if (sfile->params && (inc != 0)) { - BLI_newname(sfile->params->file, inc); + filenum_newname(sfile->params->file, sizeof(sfile->params->file), inc); ED_area_tag_redraw(sa); file_draw_check(C); // WM_event_add_notifier(C, NC_WINDOW, NULL); diff --git a/source/blender/editors/space_file/file_utils.c b/source/blender/editors/space_file/file_utils.c index 8a80e4a69ee..3c007f25da3 100644 --- a/source/blender/editors/space_file/file_utils.c +++ b/source/blender/editors/space_file/file_utils.c @@ -41,6 +41,7 @@ void file_tile_boundbox(const ARegion *ar, FileLayout *layout, const int file, r int xmin, ymax; ED_fileselect_layout_tilepos(layout, file, &xmin, &ymax); + ymax = (int)ar->v2d.tot.ymax - ymax; /* real, view space ymax */ BLI_rcti_init(r_bounds, xmin, xmin + layout->tile_w + layout->tile_border_x, - ar->winy - ymax - layout->tile_h - layout->tile_border_y, ar->winy - ymax); + ymax - layout->tile_h - layout->tile_border_y, ymax); } diff --git a/source/blender/editors/space_file/filelist.c b/source/blender/editors/space_file/filelist.c index 0a9bb40a7cd..56c48b7f650 100644 --- a/source/blender/editors/space_file/filelist.c +++ b/source/blender/editors/space_file/filelist.c @@ -233,6 +233,9 @@ typedef struct FileListEntryCache { int flags; + /* This one gathers all entries from both block and misc caches. Used for easy bulk-freing. */ + ListBase cached_entries; + /* Block cache: all entries between start and end index. used for part of the list on diplay. */ FileDirEntry **block_entries; int block_start_index, block_end_index, block_center_index, block_cursor; @@ -247,6 +250,7 @@ typedef struct FileListEntryCache { GHash *uuids; /* Previews handling. */ + TaskScheduler *previews_scheduler; TaskPool *previews_pool; ThreadQueue *previews_todo; ThreadQueue *previews_done; @@ -528,6 +532,7 @@ void filelist_sort(struct FileList *filelist) case FILE_SORT_NONE: /* Should never reach this point! */ default: BLI_assert(0); + break; } filelist_filter_clear(filelist); @@ -1016,6 +1021,7 @@ static void filelist_entry_free(FileDirEntry *entry) static void filelist_direntryarr_free(FileDirEntryArr *array) { +#if 0 FileDirEntry *entry, *entry_next; for (entry = array->entries.first; entry; entry = entry_next) { @@ -1023,6 +1029,9 @@ static void filelist_direntryarr_free(FileDirEntryArr *array) filelist_entry_free(entry); } BLI_listbase_clear(&array->entries); +#else + BLI_assert(BLI_listbase_is_empty(&array->entries)); +#endif array->nbr_entries = 0; array->nbr_entries_filtered = -1; array->entry_idx_start = -1; @@ -1093,10 +1102,11 @@ static void filelist_cache_previewf(TaskPool *pool, void *taskdata, int UNUSED(t static void filelist_cache_preview_ensure_running(FileListEntryCache *cache) { if (!cache->previews_pool) { - TaskScheduler *scheduler = BLI_task_scheduler_get(); + TaskScheduler *scheduler; TaskPool *pool; - int num_tasks = max_ii(2, BLI_system_thread_count() / 2); + int num_tasks = max_ii(1, (BLI_system_thread_count() / 2) + 1); + scheduler = cache->previews_scheduler = BLI_task_scheduler_create(num_tasks + 1); pool = cache->previews_pool = BLI_task_pool_create(scheduler, NULL); cache->previews_todo = BLI_thread_queue_init(); cache->previews_done = BLI_thread_queue_init(); @@ -1143,6 +1153,8 @@ static void filelist_cache_previews_free(FileListEntryCache *cache, const bool s BLI_thread_queue_free(cache->previews_done); BLI_thread_queue_free(cache->previews_todo); BLI_task_pool_free(cache->previews_pool); + BLI_task_scheduler_free(cache->previews_scheduler); + cache->previews_scheduler = NULL; cache->previews_pool = NULL; cache->previews_todo = NULL; cache->previews_done = NULL; @@ -1182,6 +1194,8 @@ static void filelist_cache_previews_push(FileList *filelist, FileDirEntry *entry static void filelist_cache_init(FileListEntryCache *cache, size_t cache_size) { + BLI_listbase_clear(&cache->cached_entries); + cache->block_cursor = cache->block_start_index = cache->block_center_index = cache->block_end_index = 0; cache->block_entries = MEM_mallocN(sizeof(*cache->block_entries) * cache_size, __func__); @@ -1200,30 +1214,38 @@ static void filelist_cache_init(FileListEntryCache *cache, size_t cache_size) static void filelist_cache_free(FileListEntryCache *cache) { + FileDirEntry *entry, *entry_next; + if (!(cache->flags & FLC_IS_INIT)) { return; } filelist_cache_previews_free(cache, true); - /* Note we nearly have nothing to do here, entries are just 'borrowed', not owned by cache... */ MEM_freeN(cache->block_entries); BLI_ghash_free(cache->misc_entries, NULL, NULL); MEM_freeN(cache->misc_entries_indices); BLI_ghash_free(cache->uuids, NULL, NULL); + + for (entry = cache->cached_entries.first; entry; entry = entry_next) { + entry_next = entry->next; + filelist_entry_free(entry); + } + BLI_listbase_clear(&cache->cached_entries); } static void filelist_cache_clear(FileListEntryCache *cache, size_t new_size) { + FileDirEntry *entry, *entry_next; + if (!(cache->flags & FLC_IS_INIT)) { return; } filelist_cache_previews_clear(cache); - /* Note we nearly have nothing to do here, entries are just 'borrowed', not owned by cache... */ cache->block_cursor = cache->block_start_index = cache->block_center_index = cache->block_end_index = 0; if (new_size != cache->size) { cache->block_entries = MEM_reallocN(cache->block_entries, sizeof(*cache->block_entries) * new_size); @@ -1239,6 +1261,12 @@ static void filelist_cache_clear(FileListEntryCache *cache, size_t new_size) BLI_ghash_clear_ex(cache->uuids, NULL, NULL, new_size * 2); cache->size = new_size; + + for (entry = cache->cached_entries.first; entry; entry = entry_next) { + entry_next = entry->next; + filelist_entry_free(entry); + } + BLI_listbase_clear(&cache->cached_entries); } FileList *filelist_new(short type) @@ -1417,6 +1445,7 @@ int filelist_files_ensure(FileList *filelist) static FileDirEntry *filelist_file_create_entry(FileList *filelist, const int index) { FileListInternEntry *entry = filelist->filelist_intern.filtered[index]; + FileListEntryCache *cache = &filelist->filelist_cache; FileDirEntry *ret; FileDirEntryRevision *rev; @@ -1435,13 +1464,13 @@ static FileDirEntry *filelist_file_create_entry(FileList *filelist, const int in ret->blentype = entry->blentype; ret->typeflag = entry->typeflag; - BLI_addtail(&filelist->filelist.entries, ret); + BLI_addtail(&cache->cached_entries, ret); return ret; } static void filelist_file_release_entry(FileList *filelist, FileDirEntry *entry) { - BLI_remlink(&filelist->filelist.entries, entry); + BLI_remlink(&filelist->filelist_cache.cached_entries, entry); filelist_entry_free(entry); } @@ -1507,7 +1536,7 @@ int filelist_file_findpath(struct FileList *filelist, const char *filename) } /* XXX TODO Cache could probably use a ghash on paths too? Not really urgent though. - * This is only used to find again renamed entry, annoying but looks hairy to get rid of it currently. */ + * This is only used to find again renamed entry, annoying but looks hairy to get rid of it currently. */ for (fidx = 0; fidx < filelist->filelist.nbr_entries_filtered; fidx++) { FileListInternEntry *entry = filelist->filelist_intern.filtered[fidx]; @@ -2138,11 +2167,10 @@ static unsigned int groupname_to_filter_id(const char *group) return BKE_idcode_to_idfilter(id_code); } -/* - * From here, we are in 'Job Context', i.e. have to be careful about sharing stuff between bacground working thread +/** + * From here, we are in 'Job Context', i.e. have to be careful about sharing stuff between background working thread * and main one (used by UI among other things). */ - typedef struct TodoDir { int level; char *dir; @@ -2167,14 +2195,14 @@ static int filelist_readjob_list_dir( entry = MEM_callocN(sizeof(*entry), __func__); entry->relpath = MEM_dupallocN(files[i].relname); - if (S_ISDIR(files[i].s.st_mode)) { - entry->typeflag |= FILE_TYPE_DIR; - } entry->st = files[i].s; /* Set file type. */ - /* If we are considering .blend files as libs, promote them to directory status! */ - if (do_lib && BLO_has_bfile_extension(entry->relpath)) { + if (S_ISDIR(files[i].s.st_mode)) { + entry->typeflag = FILE_TYPE_DIR; + } + else if (do_lib && BLO_has_bfile_extension(entry->relpath)) { + /* If we are considering .blend files as libs, promote them to directory status. */ char name[FILE_MAX]; entry->typeflag = FILE_TYPE_BLENDER; @@ -2188,11 +2216,9 @@ static int filelist_readjob_list_dir( } /* Otherwise, do not check extensions for directories! */ else if (!(entry->typeflag & FILE_TYPE_DIR)) { + entry->typeflag = file_extension_type(root, entry->relpath); if (filter_glob[0] && BLI_testextensie_glob(entry->relpath, filter_glob)) { - entry->typeflag = FILE_TYPE_OPERATOR; - } - else { - entry->typeflag = file_extension_type(root, entry->relpath); + entry->typeflag |= FILE_TYPE_OPERATOR; } } @@ -2472,7 +2498,7 @@ static void filelist_readjob_do( * things would crash way before we overflow that counter! * Using an atomic operation to avoid having to lock thread... * Note that we do not really need this here currently, since there is a single listing thread, but better - * remain consistent about threading! */ + * remain consistent about threading! */ *((uint32_t *)entry->uuid) = atomic_add_uint32((uint32_t *)filelist->filelist_intern.curr_uuid, 1); BLI_path_rel(dir, root); diff --git a/source/blender/editors/space_file/filesel.c b/source/blender/editors/space_file/filesel.c index da24f1ce95d..a83cae6eb17 100644 --- a/source/blender/editors/space_file/filesel.c +++ b/source/blender/editors/space_file/filesel.c @@ -260,6 +260,7 @@ short ED_fileselect_set_params(SpaceFile *sfile) params->flag |= FILE_HIDE_DOT; params->flag &= ~FILE_DIRSEL_ONLY; params->display = FILE_SHORTDISPLAY; + params->sort = FILE_SORT_ALPHA; params->filter = 0; params->filter_glob[0] = '\0'; } diff --git a/source/blender/editors/space_file/fsmenu.c b/source/blender/editors/space_file/fsmenu.c index fdf7b458865..33e6990b179 100644 --- a/source/blender/editors/space_file/fsmenu.c +++ b/source/blender/editors/space_file/fsmenu.c @@ -292,6 +292,30 @@ void fsmenu_insert_entry(struct FSMenu *fsmenu, FSMenuCategory category, const c fsm_iter = MEM_mallocN(sizeof(*fsm_iter), "fsme"); fsm_iter->path = BLI_strdup(path); fsm_iter->save = (flag & FS_INSERT_SAVE) != 0; + + if ((category == FS_CATEGORY_RECENT) && (!name || !name[0])) { + /* Special handling when adding new recent entry - check if dir exists in some other categories, + * and try to use name from there if so. */ + FSMenuCategory cats[] = {FS_CATEGORY_SYSTEM, FS_CATEGORY_SYSTEM_BOOKMARKS, FS_CATEGORY_BOOKMARKS}; + int i = ARRAY_SIZE(cats); + + while (i--) { + FSMenuEntry *tfsm = ED_fsmenu_get_category(fsmenu, cats[i]); + + for (; tfsm; tfsm = tfsm->next) { + if (STREQ(tfsm->path, fsm_iter->path)) { + if (tfsm->name[0]) { + name = tfsm->name; + } + break; + } + } + if (tfsm) { + break; + } + } + } + if (name && name[0]) { BLI_strncpy(fsm_iter->name, name, sizeof(fsm_iter->name)); } @@ -439,19 +463,36 @@ void fsmenu_read_system(struct FSMenu *fsmenu, int read_bookmarks) { wchar_t wline[FILE_MAXDIR]; __int64 tmp; - char tmps[4]; + char tmps[4], *name; int i; - + tmp = GetLogicalDrives(); - + for (i = 0; i < 26; i++) { if ((tmp >> i) & 1) { tmps[0] = 'A' + i; tmps[1] = ':'; tmps[2] = '\\'; - tmps[3] = 0; - - fsmenu_insert_entry(fsmenu, FS_CATEGORY_SYSTEM, tmps, NULL, FS_INSERT_SORTED); + tmps[3] = '\0'; + name = NULL; + + /* Flee from horrible win querying hover floppy drives! */ + if (i > 1) { + /* Try to get volume label as well... */ + BLI_strncpy_wchar_from_utf8(wline, tmps, 4); + if (GetVolumeInformationW(wline, wline + 4, FILE_MAXDIR - 4, NULL, NULL, NULL, NULL, 0)) { + size_t label_len; + + BLI_strncpy_wchar_as_utf8(line, wline + 4, FILE_MAXDIR - 4); + + label_len = MIN2(strlen(line), FILE_MAXDIR - 6); + BLI_snprintf(line + label_len, 6, " (%.2s)", tmps); + + name = line; + } + } + + fsmenu_insert_entry(fsmenu, FS_CATEGORY_SYSTEM, tmps, name, FS_INSERT_SORTED); } } diff --git a/source/blender/editors/space_image/image_buttons.c b/source/blender/editors/space_image/image_buttons.c index 191a709af4f..1ee9a67a7a1 100644 --- a/source/blender/editors/space_image/image_buttons.c +++ b/source/blender/editors/space_image/image_buttons.c @@ -411,7 +411,7 @@ static void ui_imageuser_pass_menu(bContext *UNUSED(C), uiLayout *layout, void * uiDefMenuTitleBut(block, IFACE_("Pass")); - nr = (rl ? BLI_listbase_count(&rl->passes) : 0) - 1; + nr = 0; fake_name = ui_imageuser_pass_fake_name(rl); if (fake_name) { @@ -420,7 +420,8 @@ static void ui_imageuser_pass_menu(bContext *UNUSED(C), uiLayout *layout, void * } /* rendered results don't have a Combined pass */ - for (rpass = rl ? rl->passes.last : NULL; rpass; rpass = rpass->prev, nr--) { + /* multiview: the ordering must be ascending, so the left-most pass is always the one picked */ + for (rpass = rl ? rl->passes.first : NULL; rpass; rpass = rpass->next, nr++) { /* just show one pass of each kind */ if (passflag & rpass->passtype) @@ -429,18 +430,17 @@ static void ui_imageuser_pass_menu(bContext *UNUSED(C), uiLayout *layout, void * passflag |= rpass->passtype; final: - uiDefButI(block, UI_BTYPE_BUT_MENU, B_NOP, IFACE_(rpass->internal_name), 0, 0, - UI_UNIT_X * 5, UI_UNIT_X, &iuser->passtype, (float) rpass->passtype, 0.0, 0, -1, ""); + uiDefButS(block, UI_BTYPE_BUT_MENU, B_NOP, IFACE_(rpass->internal_name), 0, 0, + UI_UNIT_X * 5, UI_UNIT_X, &iuser->pass, (float) nr, 0.0, 0, -1, ""); } if (fake_name) { fake_name = NULL; rpass = &rpass_fake; + nr = 0; goto final; } - BLI_assert(nr == -1); - BKE_image_release_renderresult(scene, image); } @@ -537,7 +537,6 @@ static void image_multi_incpass_cb(bContext *C, void *rr_v, void *iuser_v) ImageUser *iuser = iuser_v; RenderLayer *rl; RenderPass *rp; - RenderPass *next = NULL; int layer = iuser->layer; if (RE_HasFakeLayer(rr)) @@ -546,20 +545,20 @@ static void image_multi_incpass_cb(bContext *C, void *rr_v, void *iuser_v) rl = BLI_findlink(&rr->layers, layer); if (rl) { - for (rp = rl->passes.first; rp; rp = rp->next) { - if (rp->passtype == iuser->passtype) { - next = rp->next; - if (next != NULL && next->passtype == rp->passtype) - next = next->next; + RenderPass *rpass = BLI_findlink(&rl->passes, iuser->pass); + int rp_index = iuser->pass + 1; + + if (rpass == NULL) + return; + + for (rp = rpass->next; rp; rp = rp->next, rp_index++) { + if (rp->passtype != rpass->passtype) { + iuser->pass = rp_index; + BKE_image_multilayer_index(rr, iuser); + WM_event_add_notifier(C, NC_IMAGE | ND_DRAW, NULL); break; } } - - if (next != NULL && iuser->passtype != next->passtype) { - iuser->passtype = next->passtype; - BKE_image_multilayer_index(rr, iuser); - WM_event_add_notifier(C, NC_IMAGE | ND_DRAW, NULL); - } } } static void image_multi_decpass_cb(bContext *C, void *rr_v, void *iuser_v) @@ -568,29 +567,31 @@ static void image_multi_decpass_cb(bContext *C, void *rr_v, void *iuser_v) ImageUser *iuser = iuser_v; RenderLayer *rl; RenderPass *rp; - RenderPass *prev = NULL; int layer = iuser->layer; + if (iuser->pass == 0) + return; + if (RE_HasFakeLayer(rr)) layer -= 1; rl = BLI_findlink(&rr->layers, layer); if (rl) { - for (rp = rl->passes.last; rp; rp = rp->prev) { - if (rp->passtype == iuser->passtype) { - prev = rp->prev; - if (prev != NULL && prev->passtype == rp->passtype) - prev = prev->prev; + RenderPass *rpass = BLI_findlink(&rl->passes, iuser->pass); + int rp_index = 0; + + if (rpass == NULL) + return; + + for (rp = rl->passes.first; rp; rp = rp->next, rp_index++) { + if (rp->passtype == rpass->passtype) { + iuser->pass = rp_index - 1; + BKE_image_multilayer_index(rr, iuser); + WM_event_add_notifier(C, NC_IMAGE | ND_DRAW, NULL); break; } } - - if (prev != NULL && iuser->passtype != prev->passtype) { - iuser->passtype = prev->passtype; - BKE_image_multilayer_index(rr, iuser); - WM_event_add_notifier(C, NC_IMAGE | ND_DRAW, NULL); - } } } @@ -630,7 +631,7 @@ static void uiblock_layer_pass_buttons(uiLayout *layout, Image *image, RenderRes int wmenu1, wmenu2, wmenu3, wmenu4; const char *fake_name; const char *display_name = ""; - const bool show_stereo = (iuser->flag & IMA_SHOW_STEREO); + const bool show_stereo = (iuser->flag & IMA_SHOW_STEREO) != 0; uiLayoutRow(layout, true); @@ -679,7 +680,7 @@ static void uiblock_layer_pass_buttons(uiLayout *layout, Image *image, RenderRes /* pass */ fake_name = ui_imageuser_pass_fake_name(rl); - rpass = (rl ? RE_pass_find_by_type(rl, iuser->passtype, ((RenderView *)rr->views.first)->name) : NULL); + rpass = (rl ? BLI_findlink(&rl->passes, iuser->pass - (fake_name ? 1 : 0)) : NULL); display_name = rpass ? rpass->internal_name : (fake_name ? fake_name : ""); but = uiDefMenuBut(block, ui_imageuser_pass_menu, rnd_pt, IFACE_(display_name), @@ -688,7 +689,9 @@ static void uiblock_layer_pass_buttons(uiLayout *layout, Image *image, RenderRes UI_but_type_set_menu_from_pulldown(but); /* view */ - if (BLI_listbase_count_ex(&rr->views, 2) > 1 && !show_stereo) { + if (BLI_listbase_count_ex(&rr->views, 2) > 1 && + ((!show_stereo) || (!RE_RenderResult_is_stereo(rr)))) + { rview = BLI_findlink(&rr->views, iuser->view); display_name = rview ? rview->name : ""; @@ -699,8 +702,8 @@ static void uiblock_layer_pass_buttons(uiLayout *layout, Image *image, RenderRes } /* stereo image */ - else if (((image->flag & IMA_IS_STEREO) && (!show_stereo)) || - ((image->flag & IMA_IS_MULTIVIEW) && ((image->flag & IMA_IS_STEREO) == 0))) + else if ((BKE_image_is_stereo(image) && (!show_stereo)) || + (BKE_image_is_multiview(image) && !BKE_image_is_stereo(image))) { ImageView *iv; int nr = 0; diff --git a/source/blender/editors/space_image/image_draw.c b/source/blender/editors/space_image/image_draw.c index b157d1c7627..4f5fa6c2063 100644 --- a/source/blender/editors/space_image/image_draw.c +++ b/source/blender/editors/space_image/image_draw.c @@ -813,7 +813,7 @@ void draw_image_main(const bContext *C, ARegion *ar) show_viewer = (ima && ima->source == IMA_SRC_VIEWER) != 0; show_render = (show_viewer && ima->type == IMA_TYPE_R_RESULT) != 0; show_paint = (ima && (sima->mode == SI_MODE_PAINT) && (show_viewer == false) && (show_render == false)); - show_stereo3d = (ima && (ima->flag & IMA_IS_STEREO) && (sima->iuser.flag & IMA_SHOW_STEREO)); + show_stereo3d = (ima && BKE_image_is_stereo(ima) && (sima->iuser.flag & IMA_SHOW_STEREO)); show_multilayer = ima && BKE_image_is_multilayer(ima); if (show_viewer) { @@ -855,7 +855,7 @@ void draw_image_main(const bContext *C, ARegion *ar) BLI_rctf_init(&frame, 0.0f, ibuf->x, 0.0f, ibuf->y); UI_view2d_view_to_region(&ar->v2d, 0.0f, 0.0f, &x, &y); - ED_region_image_metadata_draw(x, y, ibuf, frame, zoomx, zoomy); + ED_region_image_metadata_draw(x, y, ibuf, &frame, zoomx, zoomy); } } diff --git a/source/blender/editors/space_image/image_ops.c b/source/blender/editors/space_image/image_ops.c index 3c5aff4d698..faba61c7d28 100644 --- a/source/blender/editors/space_image/image_ops.c +++ b/source/blender/editors/space_image/image_ops.c @@ -1153,8 +1153,6 @@ static int image_open_exec(bContext *C, wmOperator *op) } else { ima->flag &= ~IMA_USE_VIEWS; - ima->flag &= ~IMA_IS_STEREO; - ima->flag &= ~IMA_IS_MULTIVIEW; BKE_image_free_views(ima); } @@ -1703,7 +1701,7 @@ static bool save_image_doit(bContext *C, SpaceImage *sima, wmOperator *op, SaveI /* we need renderresult for exr and rendered multiview */ scene = CTX_data_scene(C); rr = BKE_image_acquire_renderresult(scene, ima); - is_mono = rr ? BLI_listbase_count_ex(&rr->views, 2) < 2 : (ima->flag & IMA_IS_MULTIVIEW) == 0; + is_mono = rr ? BLI_listbase_count_ex(&rr->views, 2) < 2 : BLI_listbase_count_ex(&ima->views, 2) < 2; /* error handling */ if (!rr) { @@ -1714,7 +1712,7 @@ static bool save_image_doit(bContext *C, SpaceImage *sima, wmOperator *op, SaveI } else { if (imf->views_format == R_IMF_VIEWS_STEREO_3D) { - if ((ima->flag & IMA_IS_STEREO) == 0) { + if (!BKE_image_is_stereo(ima)) { BKE_reportf(op->reports, RPT_ERROR, "Did not write, the image doesn't have a \"%s\" and \"%s\" views", STEREO_LEFT_NAME, STEREO_RIGHT_NAME); goto cleanup; @@ -1959,9 +1957,9 @@ static int image_save_as_invoke(bContext *C, wmOperator *op, const wmEvent *UNUS /* show multiview save options only if image has multiviews */ prop = RNA_struct_find_property(op->ptr, "show_multiview"); - RNA_property_boolean_set(op->ptr, prop, (ima->flag & IMA_IS_MULTIVIEW) != 0); + RNA_property_boolean_set(op->ptr, prop, BKE_image_is_multiview(ima)); prop = RNA_struct_find_property(op->ptr, "use_multiview"); - RNA_property_boolean_set(op->ptr, prop, (ima->flag & IMA_IS_MULTIVIEW) != 0); + RNA_property_boolean_set(op->ptr, prop, BKE_image_is_multiview(ima)); image_filesel(C, op, simopts.filepath); diff --git a/source/blender/editors/space_image/space_image.c b/source/blender/editors/space_image/space_image.c index 928e064b730..97e3390f142 100644 --- a/source/blender/editors/space_image/space_image.c +++ b/source/blender/editors/space_image/space_image.c @@ -157,7 +157,6 @@ static SpaceLink *image_new(const bContext *UNUSED(C)) simage->iuser.fie_ima = 2; simage->iuser.frames = 100; simage->iuser.flag = IMA_SHOW_STEREO; - simage->iuser.passtype = SCE_PASS_COMBINED; scopes_new(&simage->scopes); simage->sample_line_hist.height = 100; @@ -920,7 +919,8 @@ static void image_tools_area_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ED_region_tag_redraw(ar); break; case NC_BRUSH: - if (wmn->action == NA_EDITED) + /* NA_SELECTED is used on brush changes */ + if (ELEM(wmn->action, NA_EDITED, NA_SELECTED)) ED_region_tag_redraw(ar); break; case NC_SCENE: diff --git a/source/blender/editors/space_logic/logic_window.c b/source/blender/editors/space_logic/logic_window.c index ccf8460e9a3..a8536496059 100644 --- a/source/blender/editors/space_logic/logic_window.c +++ b/source/blender/editors/space_logic/logic_window.c @@ -1696,7 +1696,7 @@ static void draw_actuator_filter_2d(uiLayout *layout, PointerRNA *ptr) static void draw_actuator_game(uiLayout *layout, PointerRNA *ptr) { uiItemR(layout, ptr, "mode", 0, NULL, ICON_NONE); - if (RNA_enum_get(ptr, "mode") == ACT_GAME_LOAD) + if (ELEM(RNA_enum_get(ptr, "mode"), ACT_GAME_LOAD, ACT_GAME_SCREENSHOT)) uiItemR(layout, ptr, "filename", 0, NULL, ICON_NONE); } diff --git a/source/blender/editors/space_nla/nla_draw.c b/source/blender/editors/space_nla/nla_draw.c index 745774577be..b0adabe4d1d 100644 --- a/source/blender/editors/space_nla/nla_draw.c +++ b/source/blender/editors/space_nla/nla_draw.c @@ -422,13 +422,14 @@ static void nla_draw_strip(SpaceNla *snla, AnimData *adt, NlaTrack *nlt, NlaStri } /* add the relevant text to the cache of text-strings to draw in pixelspace */ -static void nla_draw_strip_text(AnimData *adt, NlaTrack *nlt, NlaStrip *strip, int index, View2D *v2d, float yminc, float ymaxc) +static void nla_draw_strip_text( + AnimData *adt, NlaTrack *nlt, NlaStrip *strip, int index, View2D *v2d, + float xminc, float xmaxc, float yminc, float ymaxc) { const bool non_solo = ((adt && (adt->flag & ADT_NLA_SOLO_TRACK)) && (nlt->flag & NLATRACK_SOLO) == 0); char str[256]; size_t str_len; char col[4]; - float xofs; rctf rect; /* just print the name and the range */ @@ -452,20 +453,14 @@ static void nla_draw_strip_text(AnimData *adt, NlaTrack *nlt, NlaStrip *strip, i col[3] = 255; else col[3] = 128; - - /* determine the amount of padding required - cannot be constant otherwise looks weird in some cases */ - if ((strip->end - strip->start) <= 5.0f) - xofs = 0.5f; - else - xofs = 1.0f; - + /* set bounding-box for text * - padding of 2 'units' on either side */ // TODO: make this centered? - rect.xmin = strip->start + xofs; + rect.xmin = xminc; rect.ymin = yminc; - rect.xmax = strip->end - xofs; + rect.xmax = xmaxc; rect.ymax = ymaxc; /* add this string to the cache of texts to draw */ @@ -510,6 +505,8 @@ void draw_nla_main_data(bAnimContext *ac, SpaceNla *snla, ARegion *ar) 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); @@ -550,11 +547,16 @@ void draw_nla_main_data(bAnimContext *ac, SpaceNla *snla, ARegion *ar) /* draw each strip in the track (if visible) */ for (strip = nlt->strips.first, index = 1; 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; + /* draw the visualization of the strip */ nla_draw_strip(snla, adt, nlt, strip, v2d, yminc, ymaxc); /* add the text for this strip to the cache */ - nla_draw_strip_text(adt, nlt, strip, index, v2d, yminc, ymaxc); + if (xminc < xmaxc) { + nla_draw_strip_text(adt, nlt, strip, index, v2d, xminc, xmaxc, yminc, ymaxc); + } /* if transforming strips (only real reason for temp-metas currently), * add to the cache the frame numbers of the strip's extents diff --git a/source/blender/editors/space_node/drawnode.c b/source/blender/editors/space_node/drawnode.c index 7ba75f99211..a25b55b7108 100644 --- a/source/blender/editors/space_node/drawnode.c +++ b/source/blender/editors/space_node/drawnode.c @@ -391,6 +391,7 @@ static void node_draw_frame_label(bNodeTree *ntree, bNode *node, const float asp float x, y; const int font_size = data->label_size / aspect; const float margin = (float)(NODE_DY / 4); + int label_height; nodeLabel(ntree, node, label, sizeof(label)); @@ -403,10 +404,11 @@ static void node_draw_frame_label(bNodeTree *ntree, bNode *node, const float asp width = BLF_width(fontid, label, sizeof(label)); ascender = BLF_ascender(fontid); + label_height = ((margin / aspect) + (ascender * aspect)); /* 'x' doesn't need aspect correction */ x = BLI_rctf_cent_x(rct) - (0.5f * width); - y = rct->ymax - ((margin / aspect) + (ascender * aspect)); + y = rct->ymax - label_height; BLF_position(fontid, x, y, 0); BLF_draw(fontid, label, BLF_DRAW_STR_DUMMY_MAX); @@ -415,31 +417,39 @@ static void node_draw_frame_label(bNodeTree *ntree, bNode *node, const float asp if (node->id) { Text *text = (Text *)node->id; TextLine *line; - const float line_spacing = (BLF_height_max(fontid) * aspect) * 0.7f; + const int line_height_max = BLF_height_max(fontid); + const float line_spacing = (line_height_max * aspect); + const float line_width = (BLI_rctf_size_x(rct) - margin) / aspect; + int y_min; /* 'x' doesn't need aspect correction */ x = rct->xmin + margin; - y = rct->ymax - ((margin / aspect) + (ascender * aspect)); - y -= line_spacing; + y = rct->ymax - (label_height + line_spacing); + /* early exit */ + y_min = y + ((margin * 2) - (y - rct->ymin)); - BLF_enable(fontid, BLF_CLIPPING); + BLF_enable(fontid, BLF_CLIPPING | BLF_WORD_WRAP); BLF_clipping( fontid, rct->xmin, - rct->ymin, - rct->xmin + ((rct->xmax - rct->xmin) / aspect) - margin, + /* round to avoid clipping half-way through a line */ + y - (floorf(((y - rct->ymin) - (margin * 2)) / line_spacing) * line_spacing), + rct->xmin + line_width, rct->ymax); + BLF_wordwrap(fontid, line_width); + for (line = text->lines.first; line; line = line->next) { + struct ResultBLF info; BLF_position(fontid, x, y, 0); - BLF_draw(fontid, line->line, line->len); - y -= line_spacing; - if (y < rct->ymin) { + BLF_draw_ex(fontid, line->line, line->len, &info); + y -= line_spacing * info.lines; + if (y < y_min) { break; } } - BLF_disable(fontid, BLF_CLIPPING); + BLF_disable(fontid, BLF_CLIPPING | BLF_WORD_WRAP); } BLF_disable(fontid, BLF_ASPECT); @@ -847,6 +857,7 @@ static void node_shader_buts_tex_environment(uiLayout *layout, bContext *C, Poin node_buts_image_user(layout, C, &iuserptr, &imaptr, &iuserptr); uiItemR(layout, ptr, "color_space", 0, "", ICON_NONE); + uiItemR(layout, ptr, "interpolation", 0, "", ICON_NONE); uiItemR(layout, ptr, "projection", 0, "", ICON_NONE); } @@ -888,6 +899,7 @@ static void node_shader_buts_tex_environment_ex(uiLayout *layout, bContext *C, P } uiItemR(layout, ptr, "color_space", 0, IFACE_("Color Space"), ICON_NONE); + uiItemR(layout, ptr, "interpolation", 0, IFACE_("Interpolation"), ICON_NONE); uiItemR(layout, ptr, "projection", 0, IFACE_("Projection"), ICON_NONE); } diff --git a/source/blender/editors/space_node/node_relationships.c b/source/blender/editors/space_node/node_relationships.c index d31d1687e5e..4097db29e5a 100644 --- a/source/blender/editors/space_node/node_relationships.c +++ b/source/blender/editors/space_node/node_relationships.c @@ -1436,7 +1436,7 @@ static void node_parent_offset_apply(NodeInsertOfsData *data, bNode *parent, con #define NODE_INSOFS_ANIM_DURATION 0.25f /** - * Callback that applies NodeInsertOfsData.offset_x to a node or its parent, similiar + * Callback that applies NodeInsertOfsData.offset_x to a node or its parent, similar * to node_link_insert_offset_output_chain_cb below, but with slightly different logic */ static bool node_link_insert_offset_frame_chain_cb( @@ -1600,7 +1600,7 @@ static void node_link_insert_offset_ntree( node_offset_apply(offs_node, addval); } else if (!insert->parent && offs_node->parent) { - node_offset_apply(offs_node->parent, addval); + node_offset_apply(nodeFindRootParent(offs_node), addval); } margin = addval; } @@ -1634,12 +1634,36 @@ static int node_insert_offset_modal(bContext *C, wmOperator *UNUSED(op), const w NodeInsertOfsData *iofsd = snode->iofsd; bNode *node; float duration; + bool redraw = false; if (!snode || event->type != TIMER || iofsd->anim_timer != event->customdata) return OPERATOR_PASS_THROUGH; - /* end timer + free insert offset data */ duration = (float)iofsd->anim_timer->duration; + + /* handle animation - do this before possibly aborting due to duration, since + * main thread might be so busy that node hasn't reached final position yet */ + for (node = snode->edittree->nodes.first; node; node = node->next) { + if (UNLIKELY(node->anim_ofsx)) { + const float endval = node->anim_init_locx + node->anim_ofsx; + if (IS_EQF(node->locx, endval) == false) { + node->locx = BLI_easing_cubic_ease_in_out(duration, node->anim_init_locx, node->anim_ofsx, + NODE_INSOFS_ANIM_DURATION); + if (node->anim_ofsx < 0) { + CLAMP_MIN(node->locx, endval); + } + else { + CLAMP_MAX(node->locx, endval); + } + redraw = true; + } + } + } + if (redraw) { + ED_region_tag_redraw(CTX_wm_region(C)); + } + + /* end timer + free insert offset data */ if (duration > NODE_INSOFS_ANIM_DURATION) { WM_event_remove_timer(CTX_wm_manager(C), NULL, iofsd->anim_timer); @@ -1653,15 +1677,6 @@ static int node_insert_offset_modal(bContext *C, wmOperator *UNUSED(op), const w return (OPERATOR_FINISHED | OPERATOR_PASS_THROUGH); } - /* handle animation */ - for (node = snode->edittree->nodes.first; node; node = node->next) { - if (node->anim_ofsx) { - node->locx = BLI_easing_cubic_ease_in_out(duration, node->anim_init_locx, node->anim_ofsx, - NODE_INSOFS_ANIM_DURATION); - } - } - ED_region_tag_redraw(CTX_wm_region(C)); - return OPERATOR_RUNNING_MODAL; } diff --git a/source/blender/editors/space_node/node_templates.c b/source/blender/editors/space_node/node_templates.c index 85288aa0011..ec6ef3c4697 100644 --- a/source/blender/editors/space_node/node_templates.c +++ b/source/blender/editors/space_node/node_templates.c @@ -524,7 +524,7 @@ static void ui_template_node_link_menu(bContext *C, uiLayout *layout, void *but_ bNodeSocket *sock = arg->sock; bNodeTreeType *ntreetype = arg->ntree->typeinfo; - UI_block_flag_enable(block, UI_BLOCK_NO_FLIP); + UI_block_flag_enable(block, UI_BLOCK_NO_FLIP | UI_BLOCK_IS_FLIP); UI_block_layout_set_current(block, layout); split = uiLayoutSplit(layout, 0.0f, false); @@ -622,7 +622,7 @@ static void ui_node_draw_input(uiLayout *layout, bContext *C, bNodeTree *ntree, uiLayout *split, *row, *col; bNode *lnode; char label[UI_MAX_NAME_STR]; - int indent = (depth > 1) ? 2 * (depth - 1) : 0; + int i, indent = (depth > 1) ? 2 * (depth - 1) : 0; int dependency_loop; if (input->flag & SOCK_UNAVAIL) @@ -641,7 +641,8 @@ static void ui_node_draw_input(uiLayout *layout, bContext *C, bNodeTree *ntree, RNA_pointer_create(&ntree->id, &RNA_Node, node, &nodeptr); /* indented label */ - memset(label, ' ', indent); + for (i = 0; i < indent; i++) + label[i] = ' '; label[indent] = '\0'; BLI_snprintf(label, UI_MAX_NAME_STR, "%s%s:", label, IFACE_(input->name)); diff --git a/source/blender/editors/space_outliner/outliner_draw.c b/source/blender/editors/space_outliner/outliner_draw.c index ac9e2e36ded..665ae88d833 100644 --- a/source/blender/editors/space_outliner/outliner_draw.c +++ b/source/blender/editors/space_outliner/outliner_draw.c @@ -1318,7 +1318,16 @@ static void tselem_draw_icon(uiBlock *block, int xmax, float x, float y, TreeSto case ID_GR: tselem_draw_icon_uibut(&arg, ICON_GROUP); break; case ID_LI: - tselem_draw_icon_uibut(&arg, ICON_LIBRARY_DATA_DIRECT); break; + if (tselem->id->flag & LIB_MISSING) { + tselem_draw_icon_uibut(&arg, ICON_LIBRARY_DATA_BROKEN); + } + else if (((Library *)tselem->id)->parent) { + tselem_draw_icon_uibut(&arg, ICON_LIBRARY_DATA_INDIRECT); + } + else { + tselem_draw_icon_uibut(&arg, ICON_LIBRARY_DATA_DIRECT); + } + break; case ID_LS: tselem_draw_icon_uibut(&arg, ICON_LINE_DATA); break; case ID_GD: @@ -1553,10 +1562,15 @@ static void outliner_draw_tree_element( if (tselem->type == 0 && tselem->id->lib) { glPixelTransferf(GL_ALPHA_SCALE, 0.5f); - if (tselem->id->flag & LIB_INDIRECT) + if (tselem->id->flag & LIB_MISSING) { + UI_icon_draw((float)startx + offsx, (float)*starty + 2 * ufac, ICON_LIBRARY_DATA_BROKEN); + } + else if (tselem->id->flag & LIB_INDIRECT) { UI_icon_draw((float)startx + offsx, (float)*starty + 2 * ufac, ICON_LIBRARY_DATA_INDIRECT); - else + } + else { UI_icon_draw((float)startx + offsx, (float)*starty + 2 * ufac, ICON_LIBRARY_DATA_DIRECT); + } glPixelTransferf(GL_ALPHA_SCALE, 1.0f); offsx += UI_UNIT_X; } diff --git a/source/blender/editors/space_outliner/outliner_edit.c b/source/blender/editors/space_outliner/outliner_edit.c index 1ddd25f9219..6d420674f3e 100644 --- a/source/blender/editors/space_outliner/outliner_edit.c +++ b/source/blender/editors/space_outliner/outliner_edit.c @@ -220,7 +220,7 @@ static void do_item_rename(ARegion *ar, TreeElement *te, TreeStoreElem *tselem, else if (tselem->id->lib) { BKE_report(reports, RPT_WARNING, "Cannot edit external libdata"); } - else if (te->idcode == ID_LI && te->parent) { + else if (te->idcode == ID_LI && ((Library *)tselem->id)->parent) { BKE_report(reports, RPT_WARNING, "Cannot edit the path of an indirectly linked library"); } else { diff --git a/source/blender/editors/space_outliner/outliner_intern.h b/source/blender/editors/space_outliner/outliner_intern.h index 7d151282bd2..c89a1bb1b9f 100644 --- a/source/blender/editors/space_outliner/outliner_intern.h +++ b/source/blender/editors/space_outliner/outliner_intern.h @@ -58,9 +58,9 @@ typedef struct TreeElement { } TreeElement; #define TREESTORE_ID_TYPE(_id) \ - (ELEM(GS((_id)->name), ID_SCE, ID_LI, ID_OB, ID_ME, ID_CU, ID_MB, ID_MA, ID_TE, ID_IM, ID_LT, ID_LA, ID_CA) || \ + (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) || \ ELEM(GS((_id)->name), ID_KE, ID_WO, ID_SPK, ID_GR, ID_AR, ID_AC, ID_BR, ID_PA, ID_GD, ID_LS) || \ - ELEM(GS((_id)->name), ID_SCR, ID_WM, ID_TXT)) /* Only in 'blendfile' mode ... :/ */ + ELEM(GS((_id)->name), ID_SCR, ID_WM, ID_TXT, ID_VF)) /* Only in 'blendfile' mode ... :/ */ /* TreeElement->flag */ #define TE_ACTIVE 1 @@ -68,47 +68,6 @@ typedef struct TreeElement { #define TE_LAZY_CLOSED 4 #define TE_FREE_NAME 8 -/* TreeStoreElem types */ -#define TSE_NLA 1 -#define TSE_NLA_ACTION 2 -#define TSE_DEFGROUP_BASE 3 -#define TSE_DEFGROUP 4 -#define TSE_BONE 5 -#define TSE_EBONE 6 -#define TSE_CONSTRAINT_BASE 7 -#define TSE_CONSTRAINT 8 -#define TSE_MODIFIER_BASE 9 -#define TSE_MODIFIER 10 -#define TSE_LINKED_OB 11 -// #define TSE_SCRIPT_BASE 12 // UNUSED -#define TSE_POSE_BASE 13 -#define TSE_POSE_CHANNEL 14 -#define TSE_ANIM_DATA 15 -#define TSE_DRIVER_BASE 16 -#define TSE_DRIVER 17 - -#define TSE_PROXY 18 -#define TSE_R_LAYER_BASE 19 -#define TSE_R_LAYER 20 -#define TSE_R_PASS 21 -#define TSE_LINKED_MAT 22 -/* NOTE, is used for light group */ -#define TSE_LINKED_LAMP 23 -#define TSE_POSEGRP_BASE 24 -#define TSE_POSEGRP 25 -#define TSE_SEQUENCE 26 -#define TSE_SEQ_STRIP 27 -#define TSE_SEQUENCE_DUP 28 -#define TSE_LINKED_PSYS 29 -#define TSE_RNA_STRUCT 30 -#define TSE_RNA_PROPERTY 31 -#define TSE_RNA_ARRAY_ELEM 32 -#define TSE_NLA_TRACK 33 -#define TSE_KEYMAP 34 -#define TSE_KEYMAP_ITEM 35 -#define TSE_ID_BASE 36 -#define TSE_GP_LAYER 37 - /* button events */ #define OL_NAMEBUTTON 1 diff --git a/source/blender/editors/space_sequencer/sequencer_draw.c b/source/blender/editors/space_sequencer/sequencer_draw.c index ba07572a8b0..17d2208d4f8 100644 --- a/source/blender/editors/space_sequencer/sequencer_draw.c +++ b/source/blender/editors/space_sequencer/sequencer_draw.c @@ -198,7 +198,7 @@ static void drawseqwave(const bContext *C, SpaceSeq *sseq, Scene *scene, Sequenc float yscale = (y2 - y1) / 2; float samplestep; float startsample, endsample; - float value; + float value1, value2; bSound *sound = seq->sound; SoundWaveform *waveform; @@ -238,35 +238,37 @@ static void drawseqwave(const bContext *C, SpaceSeq *sseq, Scene *scene, Sequenc if (length > floor((waveform->length - startsample) / samplestep)) length = floor((waveform->length - startsample) / samplestep); - glBegin(GL_LINE_STRIP); + glColor4f(1.0f, 1.0f, 1.0f, 0.5); + glEnable(GL_BLEND); + glBegin(GL_TRIANGLE_STRIP); for (i = 0; i < length; i++) { - pos = startsample + i * samplestep; - - value = waveform->data[pos * 3]; - - for (j = pos + 1; (j < waveform->length) && (j < pos + samplestep); j++) { - if (value > waveform->data[j * 3]) - value = waveform->data[j * 3]; - } - - glVertex2f(x1 + i * stepsize, ymid + value * yscale); - } - glEnd(); + float sampleoffset = startsample + i * samplestep; + pos = sampleoffset; - glBegin(GL_LINE_STRIP); - for (i = 0; i < length; i++) { - pos = startsample + i * samplestep; + value1 = waveform->data[pos * 3]; + value2 = waveform->data[pos * 3 + 1]; - value = waveform->data[pos * 3 + 1]; + if (samplestep > 1.0f) { + for (j = pos + 1; (j < waveform->length) && (j < pos + samplestep); j++) { + if (value1 > waveform->data[j * 3]) + value1 = waveform->data[j * 3]; - for (j = pos + 1; (j < waveform->length) && (j < pos + samplestep); j++) { - if (value < waveform->data[j * 3 + 1]) - value = waveform->data[j * 3 + 1]; + if (value2 < waveform->data[j * 3 + 1]) + value2 = waveform->data[j * 3 + 1]; + } + } + 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]; } - glVertex2f(x1 + i * stepsize, ymid + value * yscale); + glVertex2f(x1 + i * stepsize, ymid + value1 * yscale); + glVertex2f(x1 + i * stepsize, ymid + value2 * yscale); } glEnd(); + glDisable(GL_BLEND); } } @@ -1347,7 +1349,7 @@ void draw_image_seq(const bContext *C, Scene *scene, ARegion *ar, SpaceSeq *sseq IMB_freeImBuf(ibuf); if (draw_metadata) { - ED_region_image_metadata_draw(0.0, 0.0, ibuf, v2d->tot, 1.0, 1.0); + ED_region_image_metadata_draw(0.0, 0.0, ibuf, &v2d->tot, 1.0, 1.0); } if (draw_overdrop) { diff --git a/source/blender/editors/space_sequencer/sequencer_edit.c b/source/blender/editors/space_sequencer/sequencer_edit.c index 3cc0276104e..8025994d16c 100644 --- a/source/blender/editors/space_sequencer/sequencer_edit.c +++ b/source/blender/editors/space_sequencer/sequencer_edit.c @@ -3859,7 +3859,9 @@ static int sequencer_export_subtitles_exec(bContext *C, wmOperator *op) { Scene *scene = CTX_data_scene(C); Sequence *seq = BKE_sequencer_active_get(scene); + Sequence *seq_next; Editing *ed = BKE_sequencer_editing_get(scene, false); + ListBase text_seq = {0}; int iter = 0; FILE *file; char filepath[FILE_MAX]; @@ -3885,35 +3887,40 @@ static int sequencer_export_subtitles_exec(bContext *C, wmOperator *op) return OPERATOR_CANCELLED; } - /* time to open and write! */ - file = BLI_fopen(filepath, "w"); - SEQ_BEGIN(ed, seq) { if (seq->type == SEQ_TYPE_TEXT) { - TextVars *data = seq->effectdata; - char timecode_str[32]; - double sec; - int frac; - int len; - fprintf(file, "%d\n", iter++); - sec = FRA2TIME(seq->startdisp); - frac = 1000 * (sec - floor(sec)); - sec = floor(sec); - BLI_timecode_string_from_time(timecode_str, sizeof(timecode_str), 1, sec, FPS, USER_TIMECODE_SMPTE_FULL); - len = strlen(timecode_str); - timecode_str[len - 3] = 0; - fprintf(file, "%s,%d", timecode_str, frac); - sec = FRA2TIME(seq->enddisp); - BLI_timecode_string_from_time(timecode_str, sizeof(timecode_str), 1, sec, FPS, USER_TIMECODE_SMPTE_FULL); - len = strlen(timecode_str); - timecode_str[len - 3] = 0; - fprintf(file, " --> %s,%d\n", timecode_str, frac); - fprintf(file, "%s\n\n", data->text); + BLI_addtail(&text_seq, MEM_dupallocN(seq)); } } SEQ_END + if (BLI_listbase_is_empty(&text_seq)) { + BKE_report(op->reports, RPT_ERROR, "No subtitles (text strips) to export"); + return OPERATOR_CANCELLED; + } + + BLI_listbase_sort(&text_seq, BKE_sequencer_cmp_time_startdisp); + + /* time to open and write! */ + file = BLI_fopen(filepath, "w"); + + for (seq = text_seq.first; seq; seq = seq_next) { + TextVars *data = seq->effectdata; + char timecode_str_start[32]; + char timecode_str_end[32]; + + BLI_timecode_string_from_time(timecode_str_start, sizeof(timecode_str_start), + -2, FRA2TIME(seq->startdisp), FPS, USER_TIMECODE_SUBRIP); + BLI_timecode_string_from_time(timecode_str_end, sizeof(timecode_str_end), + -2, FRA2TIME(seq->enddisp), FPS, USER_TIMECODE_SUBRIP); + + fprintf(file, "%d\n%s --> %s\n%s\n\n", iter++, timecode_str_start, timecode_str_end, data->text); + + seq_next = seq->next; + MEM_freeN(seq); + } + fclose(file); return OPERATOR_FINISHED; diff --git a/source/blender/editors/space_text/text_ops.c b/source/blender/editors/space_text/text_ops.c index a2fae2d5667..948293d150b 100644 --- a/source/blender/editors/space_text/text_ops.c +++ b/source/blender/editors/space_text/text_ops.c @@ -1054,108 +1054,102 @@ static int text_convert_whitespace_exec(bContext *C, wmOperator *op) Text *text = CTX_data_edit_text(C); TextLine *tmp; FlattenString fs; - size_t a, j; - char *new_line; - int extra, number; //unknown for now + size_t a, j, max_len = 0; int type = RNA_enum_get(op->ptr, "type"); /* first convert to all space, this make it a lot easier to convert to tabs * because there is no mixtures of ' ' && '\t' */ for (tmp = text->lines.first; tmp; tmp = tmp->next) { - const char *text_check_line = tmp->line; - const int text_check_line_len = tmp->len; - number = flatten_string(st, &fs, text_check_line) + 1; + char *new_line; + + BLI_assert(tmp->line); + + flatten_string(st, &fs, tmp->line); + new_line = BLI_strdup(fs.buf); flatten_string_free(&fs); - new_line = MEM_callocN(number, "Converted_Line"); - j = 0; - for (a = 0; a < text_check_line_len; a++) { //foreach char in line - if (text_check_line[a] == '\t') { //checking for tabs - //get the number of spaces this tabs is showing - //i don't like doing it this way but will look into it later - new_line[j] = '\0'; - number = flatten_string(st, &fs, new_line); - flatten_string_free(&fs); - new_line[j] = '\t'; - new_line[j + 1] = '\0'; - number = flatten_string(st, &fs, new_line) - number; - flatten_string_free(&fs); - for (extra = 0; extra < number; extra++) { - new_line[j] = ' '; - j++; - } - } - else { - new_line[j] = text_check_line[a]; - j++; - } - } - new_line[j] = '\0'; - // put new_line in the tmp->line spot still need to try and set the curc correctly - if (tmp->line) MEM_freeN(tmp->line); - if (tmp->format) MEM_freeN(tmp->format); + MEM_freeN(tmp->line); + if (tmp->format) + MEM_freeN(tmp->format); + /* Put new_line in the tmp->line spot still need to try and set the curc correctly. */ tmp->line = new_line; tmp->len = strlen(new_line); tmp->format = NULL; + if (tmp->len > max_len) { + max_len = tmp->len; + } } - if (type == TO_TABS) { // Converting to tabs - //start over from the beginning - + if (type == TO_TABS) { + char *tmp_line = MEM_mallocN(sizeof(*tmp_line) * (max_len + 1), __func__); + for (tmp = text->lines.first; tmp; tmp = tmp->next) { const char *text_check_line = tmp->line; const int text_check_line_len = tmp->len; - extra = 0; - for (a = 0; a < text_check_line_len; a++) { - number = 0; - for (j = 0; j < (size_t)st->tabnumber; j++) { - if ((a + j) <= text_check_line_len) { //check to make sure we are not pass the end of the line - if (text_check_line[a + j] != ' ') { - number = 1; + char *tmp_line_cur = tmp_line; + const size_t tab_len = st->tabnumber; + + BLI_assert(text_check_line); + + for (a = 0; a < text_check_line_len;) { + /* A tab can only start at a position multiple of tab_len... */ + if (!(a % tab_len) && (text_check_line[a] == ' ')) { + /* a + 0 we already know to be ' ' char... */ + for (j = 1; (j < tab_len) && (a + j < text_check_line_len) && (text_check_line[a + j] == ' '); j++); + + if (j == tab_len) { + /* We found a set of spaces that can be replaced by a tab... */ + if ((tmp_line_cur == tmp_line) && a != 0) { + /* Copy all 'valid' string already 'parsed'... */ + memcpy(tmp_line_cur, text_check_line, a); + tmp_line_cur += a; } + *tmp_line_cur = '\t'; + tmp_line_cur++; + a += j; } - } - if (!number) { //found all number of space to equal a tab - a = a + (st->tabnumber - 1); - extra = extra + 1; - } - } - - if (extra > 0) { //got tabs make malloc and do what you have to do - new_line = MEM_callocN(text_check_line_len - (((st->tabnumber * extra) - extra) - 1), "Converted_Line"); - extra = 0; //reuse vars - for (a = 0; a < text_check_line_len; a++) { - number = 0; - for (j = 0; j < (size_t)st->tabnumber; j++) { - if ((a + j) <= text_check_line_len) { //check to make sure we are not pass the end of the line - if (text_check_line[a + j] != ' ') { - number = 1; - } + else { + if (tmp_line_cur != tmp_line) { + memcpy(tmp_line_cur, &text_check_line[a], j); + tmp_line_cur += j; } + a += j; } - - if (!number) { //found all number of space to equal a tab - new_line[extra] = '\t'; - a = a + (st->tabnumber - 1); - extra++; - - } - else { //not adding a tab - new_line[extra] = text_check_line[a]; - extra++; + } + else { + size_t len = BLI_str_utf8_size_safe(&text_check_line[a]); + if (tmp_line_cur != tmp_line) { + memcpy(tmp_line_cur, &text_check_line[a], len); + tmp_line_cur += len; } + a += len; } - new_line[extra] = '\0'; - // put new_line in the tmp->line spot still need to try and set the curc correctly - if (tmp->line) MEM_freeN(tmp->line); - if (tmp->format) MEM_freeN(tmp->format); - - tmp->line = new_line; - tmp->len = strlen(new_line); + } + + if (tmp_line_cur != tmp_line) { + *tmp_line_cur = '\0'; + +#ifndef NDEBUG + BLI_assert(tmp_line_cur - tmp_line <= max_len); + + flatten_string(st, &fs, tmp_line); + BLI_assert(STREQ(fs.buf, tmp->line)); + flatten_string_free(&fs); +#endif + + MEM_freeN(tmp->line); + if (tmp->format) + MEM_freeN(tmp->format); + + /* Put new_line in the tmp->line spot still need to try and set the curc correctly. */ + tmp->line = BLI_strdup(tmp_line); + tmp->len = strlen(tmp_line); tmp->format = NULL; } } + + MEM_freeN(tmp_line); } text_update_edited(text); @@ -2375,21 +2369,23 @@ static int flatten_column_to_offset(SpaceText *st, const char *str, int index) return j; } -static TextLine *get_first_visible_line(SpaceText *st, ARegion *ar, int *y) +static TextLine *get_line_pos_wrapped(SpaceText *st, ARegion *ar, int *y) { TextLine *linep = st->text->lines.first; - int i; - for (i = st->top; i > 0 && linep; ) { - int lines = text_get_visible_lines(st, ar, linep->line); - - if (i - lines < 0) { - *y += i; + int i, lines; + + if (*y < -st->top) { + return NULL; /* We are beyond the first line... */ + } + + for (i = -st->top; i <= *y && linep; linep = linep->next, i += lines) { + lines = text_get_visible_lines(st, ar, linep->line); + + if (i + lines > *y) { + /* We found the line matching given vertical 'coordinate', now set y relative to this line's start. */ + *y -= i; break; } - else { - linep = linep->next; - i -= lines; - } } return linep; } @@ -2399,23 +2395,22 @@ static void text_cursor_set_to_pos_wrapped(SpaceText *st, ARegion *ar, int x, in Text *text = st->text; int max = wrap_width(st, ar); /* column */ int charp = -1; /* mem */ - int loop = 1, found = 0; /* flags */ - char ch; + bool found = false; /* flags */ - /* Point to first visible line */ - TextLine *linep = get_first_visible_line(st, ar, &y); - - while (loop && linep) { + /* Point to line matching given y position, if any. */ + TextLine *linep = get_line_pos_wrapped(st, ar, &y); + + if (linep) { int i = 0, start = 0, end = max; /* column */ - int j = 0, curs = 0, endj = 0; /* mem */ - int chop = 1; /* flags */ - - for (; loop; j += BLI_str_utf8_size_safe(linep->line + j)) { + int j, curs = 0, endj = 0; /* mem */ + bool chop = true; /* flags */ + char ch; + + for (j = 0 ; !found && ((ch = linep->line[j]) != '\0'); j += BLI_str_utf8_size_safe(linep->line + j)) { int chars; int columns = BLI_str_utf8_char_width_safe(linep->line + j); /* = 1 for tab */ /* Mimic replacement of tabs */ - ch = linep->line[j]; if (ch == '\t') { chars = st->tabnumber - i % st->tabnumber; ch = ' '; @@ -2428,7 +2423,8 @@ static void text_cursor_set_to_pos_wrapped(SpaceText *st, ARegion *ar, int x, in /* Gone too far, go back to last wrap point */ if (y < 0) { charp = endj; - loop = 0; + y = 0; + found = true; break; /* Exactly at the cursor */ } @@ -2436,7 +2432,7 @@ static void text_cursor_set_to_pos_wrapped(SpaceText *st, ARegion *ar, int x, in /* current position could be wrapped to next line */ /* this should be checked when end of current line would be reached */ charp = curs = j; - found = 1; + found = true; /* Prepare curs for next wrap */ } else if (i - end <= x && i + columns - end > x) { @@ -2446,68 +2442,70 @@ static void text_cursor_set_to_pos_wrapped(SpaceText *st, ARegion *ar, int x, in end = MIN2(end, i); if (found) { - /* exact cursor position was found, check if it's */ - /* still on needed line (hasn't been wrapped) */ - if (charp > endj && !chop && ch != '\0') charp = endj; - loop = 0; + /* exact cursor position was found, check if it's still on needed line (hasn't been wrapped) */ + if (charp > endj && !chop && ch != '\0') + charp = endj; break; } - if (chop) endj = j; + if (chop) + endj = j; start = end; end += max; if (j < linep->len) y--; - chop = 1; + chop = true; if (y == 0 && i + columns - start > x) { charp = curs; - loop = 0; + found = true; break; } } else if (ch == ' ' || ch == '-' || ch == '\0') { if (found) { - loop = 0; break; } if (y == 0 && i + columns - start > x) { charp = curs; - loop = 0; + found = true; break; } end = i + 1; endj = j; - chop = 0; + chop = false; } i += columns; } - - if (ch == '\0') break; - } - - if (!loop || found) break; - - if (!linep->next) { - charp = linep->len; - break; } + + BLI_assert(y == 0); - /* On correct line but didn't meet cursor, must be at end */ - if (y == 0) { + if (!found) { + /* On correct line but didn't meet cursor, must be at end */ charp = linep->len; - break; } - linep = linep->next; - - y--; + } + else if (y < 0) { /* Before start of text. */ + linep = st->text->lines.first; + charp = 0; + } + else { /* Beyond end of text */ + linep = st->text->lines.last; + charp = linep->len; } - if (linep && charp != -1) { - if (sel) { text->sell = linep; text->selc = charp; } - else { text->curl = linep; text->curc = charp; } + BLI_assert(linep && charp != -1); + + if (sel) { + text->sell = linep; + text->selc = charp; + } + else { + text->curl = linep; + text->curc = charp; } } diff --git a/source/blender/editors/space_view3d/CMakeLists.txt b/source/blender/editors/space_view3d/CMakeLists.txt index 181a0adfd28..059b384a9e2 100644 --- a/source/blender/editors/space_view3d/CMakeLists.txt +++ b/source/blender/editors/space_view3d/CMakeLists.txt @@ -90,4 +90,8 @@ if(WITH_FREESTYLE) add_definitions(-DWITH_FREESTYLE) 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/SConscript b/source/blender/editors/space_view3d/SConscript index 6e4e47e22a4..7fdccce1c0e 100644 --- a/source/blender/editors/space_view3d/SConscript +++ b/source/blender/editors/space_view3d/SConscript @@ -68,4 +68,7 @@ if env['WITH_BF_INTERNATIONAL']: if env['WITH_BF_FREESTYLE']: defs.append('WITH_FREESTYLE') +if env['WITH_BF_LEGACY_DEPSGRAPH']: + defs.append('WITH_LEGACY_DEPSGRAPH') + env.BlenderLib ( 'bf_editors_space_view3d', sources, incs, defines = defs, libtype=['core'], priority=[40] ) diff --git a/source/blender/editors/space_view3d/drawarmature.c b/source/blender/editors/space_view3d/drawarmature.c index fc7c5c897d8..02a53521a46 100644 --- a/source/blender/editors/space_view3d/drawarmature.c +++ b/source/blender/editors/space_view3d/drawarmature.c @@ -1547,7 +1547,7 @@ static void draw_pose_dofs(Object *ob) glPushMatrix(); copy_v3_v3(posetrans, pchan->pose_mat[3]); - glTranslatef(posetrans[0], posetrans[1], posetrans[2]); + glTranslate3fv(posetrans); if (pchan->parent) { copy_m4_m4(mat, pchan->parent->pose_mat); @@ -1780,7 +1780,7 @@ static void draw_pose_bones(Scene *scene, View3D *v3d, ARegion *ar, Base *base, } draw_custom_bone(scene, v3d, rv3d, pchan->custom, - OB_SOLID, arm->flag, flag, index, bone->length); + OB_SOLID, arm->flag, flag, index, PCHAN_CUSTOM_DRAW_SIZE(pchan)); } } else { @@ -1871,7 +1871,7 @@ static void draw_pose_bones(Scene *scene, View3D *v3d, ARegion *ar, Base *base, flag |= BONE_DRAW_ACTIVE; draw_custom_bone(scene, v3d, rv3d, pchan->custom, - OB_WIRE, arm->flag, flag, index, bone->length); + OB_WIRE, arm->flag, flag, index, PCHAN_CUSTOM_DRAW_SIZE(pchan)); glPopMatrix(); } diff --git a/source/blender/editors/space_view3d/drawmesh.c b/source/blender/editors/space_view3d/drawmesh.c index d806dfa015a..68e536662d6 100644 --- a/source/blender/editors/space_view3d/drawmesh.c +++ b/source/blender/editors/space_view3d/drawmesh.c @@ -664,7 +664,7 @@ static void update_tface_color_layer(DerivedMesh *dm, bool use_mcol) else if (ma && (ma->shade_flag & MA_OBCOLOR)) { int loop_index = mp->loopstart; for (j = 0; j < mp->totloop; j++, loop_index++) { - copy_v3_v3_char(&finalCol[loop_index].r, (char *)Gtexdraw.obcol); + copy_v3_v3_uchar(&finalCol[loop_index].r, Gtexdraw.obcol); } copy_mode = COPY_PREV; } @@ -1114,8 +1114,7 @@ void draw_mesh_textured(Scene *scene, View3D *v3d, RegionView3D *rv3d, /* if not cycles, or preview-modifiers, or drawing matcaps */ if ((draw_flags & DRAW_MODIFIERS_PREVIEW) || (v3d->flag2 & V3D_SHOW_SOLID_MATCAP) || - (BKE_scene_use_new_shading_nodes(scene) == false) || - ((ob->mode & OB_MODE_TEXTURE_PAINT) && ELEM(v3d->drawtype, OB_TEXTURE, OB_SOLID))) + (BKE_scene_use_new_shading_nodes(scene) == false)) { draw_mesh_textured_old(scene, v3d, rv3d, ob, dm, draw_flags); return; diff --git a/source/blender/editors/space_view3d/drawobject.c b/source/blender/editors/space_view3d/drawobject.c index 0747ade18bd..62204eee518 100644 --- a/source/blender/editors/space_view3d/drawobject.c +++ b/source/blender/editors/space_view3d/drawobject.c @@ -830,7 +830,7 @@ void view3d_cached_text_draw_add(const float co[3], BLI_LINKS_PREPEND(g_v3d_strings[g_v3d_string_level], vos); copy_v3_v3(vos->vec, co); - copy_v4_v4_char((char *)vos->col.ub, (const char *)col); + copy_v4_v4_uchar(vos->col.ub, col); vos->xoffs = xoffs; vos->flag = flag; vos->str_len = str_len; @@ -977,7 +977,7 @@ static void drawcube_size(const float size[3]) { glPushMatrix(); - glScalef(size[0], size[1], size[2]); + glScale3fv(size); glBegin(GL_LINE_STRIP); @@ -1199,7 +1199,7 @@ static void drawlamp(View3D *v3d, RegionView3D *rv3d, Base *base, 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, x, y, z; + float vec[3], lvec[3], vvec[3], circrad; float lampsize; float imat[4][4]; @@ -1316,7 +1316,7 @@ static void drawlamp(View3D *v3d, RegionView3D *rv3d, Base *base, mul_v3_v3fl(v2, imat[0], circrad * 2.5f); /* center */ - glTranslatef(vec[0], vec[1], vec[2]); + glTranslate3fv(vec); setlinestyle(3); @@ -1346,7 +1346,7 @@ static void drawlamp(View3D *v3d, RegionView3D *rv3d, Base *base, /* skip drawing extra info */ } else if ((la->type == LA_SPOT) || (la->type == LA_YF_PHOTON)) { - + float x, y, z, z_abs; copy_v3_fl3(lvec, 0.0f, 0.0f, 1.0f); copy_v3_fl3(vvec, rv3d->persmat[0][2], rv3d->persmat[1][2], rv3d->persmat[2][2]); mul_transposed_mat3_m4_v3(ob->obmat, vvec); @@ -1359,46 +1359,75 @@ static void drawlamp(View3D *v3d, RegionView3D *rv3d, Base *base, mul_v3_fl(lvec, x); mul_v3_fl(vvec, x); - /* draw the angled sides of the cone */ - glBegin(GL_LINE_STRIP); - glVertex3fv(vvec); - glVertex3fv(vec); - glVertex3fv(lvec); - glEnd(); - x *= y; - /* draw the circle/square at the end of the cone */ - glTranslatef(0.0, 0.0, x); + z_abs = fabsf(z); + if (la->mode & LA_SQUARE) { - float tvec[3]; - float z_abs = fabsf(z); - - tvec[0] = tvec[1] = z_abs; - tvec[2] = 0.0; - - glBegin(GL_LINE_LOOP); - glVertex3fv(tvec); - tvec[1] = -z_abs; /* neg */ - glVertex3fv(tvec); - tvec[0] = -z_abs; /* neg */ - glVertex3fv(tvec); - tvec[1] = z_abs; /* pos */ - glVertex3fv(tvec); - glEnd(); + /* draw pyramid */ + const float vertices[5][3] = { + /* 5 of vertex coords of pyramid */ + {0.0f, 0.0f, 0.0f}, + {z_abs, z_abs, x}, + {-z_abs, -z_abs, x}, + {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); + + glTranslatef(0.0f, 0.0f, x); + + /* draw the square representing spotbl */ + if (la->type == LA_SPOT) { + float blend = z_abs * (1.0f - pow2f(la->spotblend)); + + /* hide line if it is zero size or overlaps with outer border, + * 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); + } + } } else { - circ(0.0, 0.0, fabsf(z)); - } - /* draw the circle/square representing spotbl */ - if (la->type == LA_SPOT) { - float spotblcirc = fabsf(z) * (1.0f - pow2f(la->spotblend)); - /* hide line if it is zero size or overlaps with outer border, - * previously it adjusted to always to show it but that seems - * confusing because it doesn't show the actual blend size */ - if (spotblcirc != 0 && spotblcirc != fabsf(z)) - circ(0.0, 0.0, spotblcirc); + /* draw the angled sides of the cone */ + glBegin(GL_LINE_STRIP); + glVertex3fv(vvec); + glVertex3fv(vec); + glVertex3fv(lvec); + glEnd(); + + /* draw the circle at the end of the cone */ + glTranslatef(0.0f, 0.0f, x); + circ(0.0f, 0.0f, z_abs); + + /* draw the circle representing spotbl */ + if (la->type == LA_SPOT) { + float blend = z_abs * (1.0f - pow2f(la->spotblend)); + + /* hide line if it is zero size or overlaps with outer border, + * 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); + } + } } if (drawcone) @@ -1660,7 +1689,7 @@ static void draw_viewport_object_reconstruction(Scene *scene, Base *base, View3D GPU_select_load_id(base->selcol + (tracknr << 16)); glPushMatrix(); - glTranslatef(track->bundle_pos[0], track->bundle_pos[1], track->bundle_pos[2]); + glTranslate3fv(track->bundle_pos); glScalef(v3d->bundle_size / 0.05f / camera_size[0], v3d->bundle_size / 0.05f / camera_size[1], v3d->bundle_size / 0.05f / camera_size[2]); @@ -7185,7 +7214,7 @@ static void draw_bb_quadric(BoundBox *bb, char type, bool around_origin) glPushMatrix(); if (type == OB_BOUND_SPHERE) { float scale = MAX3(size[0], size[1], size[2]); - glTranslatef(cent[0], cent[1], cent[2]); + glTranslate3fv(cent); glScalef(scale, scale, scale); gluSphere(qobj, 1.0, 8, 5); } @@ -7654,7 +7683,10 @@ void draw_object(Scene *scene, ARegion *ar, View3D *v3d, Base *base, const short } } - if ((md = modifiers_findByType(ob, eModifierType_Smoke)) && (modifier_isEnabled(scene, md, eModifierMode_Realtime))) { + if (((base->flag & OB_FROMDUPLI) == 0) && + (md = modifiers_findByType(ob, eModifierType_Smoke)) && + (modifier_isEnabled(scene, md, eModifierMode_Realtime))) + { smd = (SmokeModifierData *)md; if (smd->domain) { diff --git a/source/blender/editors/space_view3d/space_view3d.c b/source/blender/editors/space_view3d/space_view3d.c index 22090e6cb30..7f038a13fd0 100644 --- a/source/blender/editors/space_view3d/space_view3d.c +++ b/source/blender/editors/space_view3d/space_view3d.c @@ -1096,6 +1096,7 @@ static void view3d_main_area_listener(bScreen *sc, ScrArea *sa, ARegion *ar, wmN 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)) || @@ -1103,6 +1104,7 @@ static void view3d_main_area_listener(bScreen *sc, ScrArea *sa, ARegion *ar, wmN (scene->gm.matmode == GAME_MAT_GLSL || BKE_scene_use_new_shading_nodes(scene))) || !DEG_depsgraph_use_legacy()) +#endif { ED_region_tag_redraw(ar); } diff --git a/source/blender/editors/space_view3d/view3d_draw.c b/source/blender/editors/space_view3d/view3d_draw.c index e6a73048273..25fa3085596 100644 --- a/source/blender/editors/space_view3d/view3d_draw.c +++ b/source/blender/editors/space_view3d/view3d_draw.c @@ -1381,7 +1381,7 @@ static void backdrawview3d(Scene *scene, ARegion *ar, View3D *v3d) } if (!rv3d->gpuoffscreen) { - rv3d->gpuoffscreen = GPU_offscreen_create(w, h, error); + 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); @@ -1618,7 +1618,7 @@ exit: static void view3d_stereo_bgpic_setup(Scene *scene, View3D *v3d, Image *ima, ImageUser *iuser) { - if ((ima->flag & IMA_IS_STEREO)) { + if (BKE_image_is_stereo(ima)) { iuser->flag |= IMA_SHOW_STEREO; if ((scene->r.scemode & R_MULTIVIEW) == 0) { @@ -1961,15 +1961,13 @@ void ED_view3d_after_add(ListBase *lb, Base *base, const short dflag) /* disables write in zbuffer and draws it over */ static void view3d_draw_transp(Scene *scene, ARegion *ar, View3D *v3d) { - View3DAfter *v3da, *next; + View3DAfter *v3da; glDepthMask(GL_FALSE); v3d->transp = true; - for (v3da = v3d->afterdraw_transp.first; v3da; v3da = next) { - next = v3da->next; + while ((v3da = BLI_pophead(&v3d->afterdraw_transp))) { draw_object(scene, ar, v3d, v3da->base, v3da->dflag); - BLI_remlink(&v3d->afterdraw_transp, v3da); MEM_freeN(v3da); } v3d->transp = false; @@ -1981,7 +1979,7 @@ static void view3d_draw_transp(Scene *scene, ARegion *ar, View3D *v3d) /* clears zbuffer and draws it over */ static void view3d_draw_xray(Scene *scene, ARegion *ar, View3D *v3d, bool *clear) { - View3DAfter *v3da, *next; + View3DAfter *v3da; if (*clear && v3d->zbuf) { glClear(GL_DEPTH_BUFFER_BIT); @@ -1989,10 +1987,8 @@ static void view3d_draw_xray(Scene *scene, ARegion *ar, View3D *v3d, bool *clear } v3d->xray = true; - for (v3da = v3d->afterdraw_xray.first; v3da; v3da = next) { - next = v3da->next; + while ((v3da = BLI_pophead(&v3d->afterdraw_xray))) { draw_object(scene, ar, v3d, v3da->base, v3da->dflag); - BLI_remlink(&v3d->afterdraw_xray, v3da); MEM_freeN(v3da); } v3d->xray = false; @@ -2002,7 +1998,7 @@ static void view3d_draw_xray(Scene *scene, ARegion *ar, View3D *v3d, bool *clear /* clears zbuffer and draws it over */ static void view3d_draw_xraytransp(Scene *scene, ARegion *ar, View3D *v3d, const bool clear) { - View3DAfter *v3da, *next; + View3DAfter *v3da; if (clear && v3d->zbuf) glClear(GL_DEPTH_BUFFER_BIT); @@ -2012,10 +2008,8 @@ static void view3d_draw_xraytransp(Scene *scene, ARegion *ar, View3D *v3d, const glDepthMask(GL_FALSE); - for (v3da = v3d->afterdraw_xraytransp.first; v3da; v3da = next) { - next = v3da->next; + while ((v3da = BLI_pophead(&v3d->afterdraw_xraytransp))) { draw_object(scene, ar, v3d, v3da->base, v3da->dflag); - BLI_remlink(&v3d->afterdraw_xraytransp, v3da); MEM_freeN(v3da); } @@ -2431,7 +2425,7 @@ void ED_view3d_draw_depth(Scene *scene, ARegion *ar, View3D *v3d, bool alphaover v3d->afterdraw_xray.first || v3d->afterdraw_xraytransp.first) { - View3DAfter *v3da, *next; + View3DAfter *v3da; int mask_orig; v3d->xray = true; @@ -2442,8 +2436,7 @@ void ED_view3d_draw_depth(Scene *scene, ARegion *ar, View3D *v3d, bool alphaover 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 = next) { - next = v3da->next; + for (v3da = v3d->afterdraw_xray.first; v3da; v3da = v3da->next) { draw_object(scene, ar, v3d, v3da->base, dflag_depth); } glDepthFunc(GL_LEQUAL); /* Now write the depth buffer normally */ @@ -2452,28 +2445,22 @@ void ED_view3d_draw_depth(Scene *scene, ARegion *ar, View3D *v3d, bool alphaover /* draw 3 passes, transp/xray/xraytransp */ v3d->xray = false; v3d->transp = true; - for (v3da = v3d->afterdraw_transp.first; v3da; v3da = next) { - next = v3da->next; + while ((v3da = BLI_pophead(&v3d->afterdraw_transp))) { draw_object(scene, ar, v3d, v3da->base, dflag_depth); - BLI_remlink(&v3d->afterdraw_transp, v3da); MEM_freeN(v3da); } v3d->xray = true; v3d->transp = false; - for (v3da = v3d->afterdraw_xray.first; v3da; v3da = next) { - next = v3da->next; + while ((v3da = BLI_pophead(&v3d->afterdraw_xray))) { draw_object(scene, ar, v3d, v3da->base, dflag_depth); - BLI_remlink(&v3d->afterdraw_xray, v3da); MEM_freeN(v3da); } v3d->xray = true; v3d->transp = true; - for (v3da = v3d->afterdraw_xraytransp.first; v3da; v3da = next) { - next = v3da->next; + while ((v3da = BLI_pophead(&v3d->afterdraw_xraytransp))) { draw_object(scene, ar, v3d, v3da->base, dflag_depth); - BLI_remlink(&v3d->afterdraw_xraytransp, v3da); MEM_freeN(v3da); } @@ -3153,10 +3140,9 @@ static void view3d_main_area_clear(Scene *scene, View3D *v3d, ARegion *ar) 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, - GPUOffScreen *ofs, + bool do_bgpic, bool do_sky, bool is_persp, const char *viewname, GPUFX *fx, GPUFXSettings *fx_settings, - const char *viewname) + GPUOffScreen *ofs) { struct bThemeState theme_state; int bwinx, bwiny; @@ -3256,26 +3242,37 @@ void ED_view3d_draw_offscreen( G.f &= ~G_RENDER_OGL; } -/* utility func for ED_view3d_draw_offscreen */ -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, const char *viewname, char err_out[256]) +/** + * 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, const char *viewname, + /* output vars */ + GPUOffScreen *ofs, char err_out[256]) { RegionView3D *rv3d = ar->regiondata; ImBuf *ibuf; - GPUOffScreen *ofs; - bool draw_sky = (alpha_mode == R_ADDSKY) && v3d && (v3d->flag3 & V3D_SHOW_WORLD); + const bool draw_sky = (alpha_mode == R_ADDSKY) && v3d && (v3d->flag3 & V3D_SHOW_WORLD); + const bool own_ofs = (ofs == NULL); if (UNLIKELY(v3d == NULL)) return NULL; - /* state changes make normal drawing go weird otherwise */ - glPushAttrib(GL_LIGHTING_BIT); + if (own_ofs) { + /* state changes make normal drawing go weird otherwise */ + glPushAttrib(GL_LIGHTING_BIT); - /* bind */ - ofs = GPU_offscreen_create(sizex, sizey, err_out); - if (ofs == NULL) { - glPopAttrib(); - return NULL; + /* bind */ + ofs = GPU_offscreen_create(sizex, sizey, samples, err_out); + if (ofs == NULL) { + glPopAttrib(); + return NULL; + } } ED_view3d_draw_offscreen_init(scene, v3d); @@ -3301,14 +3298,15 @@ ImBuf *ED_view3d_draw_offscreen_imbuf(Scene *scene, View3D *v3d, ARegion *ar, in ED_view3d_draw_offscreen( scene, v3d, ar, sizex, sizey, NULL, params.winmat, - draw_background, draw_sky, !params.is_ortho, - ofs, NULL, &fx_settings, viewname); + draw_background, draw_sky, !params.is_ortho, viewname, + NULL, &fx_settings, + ofs); } else { ED_view3d_draw_offscreen( scene, v3d, ar, sizex, sizey, NULL, NULL, - draw_background, draw_sky, true, - ofs, NULL, NULL, viewname); + draw_background, draw_sky, true, viewname, + NULL, NULL, ofs); } /* read in pixels & stamp */ @@ -3321,9 +3319,12 @@ ImBuf *ED_view3d_draw_offscreen_imbuf(Scene *scene, View3D *v3d, ARegion *ar, in /* unbind */ GPU_offscreen_unbind(ofs, true); - GPU_offscreen_free(ofs); - glPopAttrib(); + if (own_ofs) { + GPU_offscreen_free(ofs); + + glPopAttrib(); + } if (ibuf->rect_float && ibuf->rect) IMB_rect_from_float(ibuf); @@ -3331,10 +3332,19 @@ ImBuf *ED_view3d_draw_offscreen_imbuf(Scene *scene, View3D *v3d, ARegion *ar, in return ibuf; } -/* creates own 3d views, 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, - const char *viewname, char err_out[256]) +/** + * 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, const char *viewname, + GPUOffScreen *ofs, char err_out[256]) { View3D v3d = {NULL}; ARegion ar = {NULL}; @@ -3381,8 +3391,10 @@ ImBuf *ED_view3d_draw_offscreen_imbuf_simple(Scene *scene, Object *camera, int w 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, viewname, err_out); + return ED_view3d_draw_offscreen_imbuf( + scene, &v3d, &ar, width, height, flag, + draw_background, alpha_mode, samples, viewname, + ofs, err_out); // seq_view3d_cb(scene, cfra, render_size, seqrectx, seqrecty); } diff --git a/source/blender/editors/space_view3d/view3d_edit.c b/source/blender/editors/space_view3d/view3d_edit.c index 9a4cd3f248e..b774b2e192d 100644 --- a/source/blender/editors/space_view3d/view3d_edit.c +++ b/source/blender/editors/space_view3d/view3d_edit.c @@ -44,6 +44,7 @@ #include "BLI_math.h" #include "BLI_utildefines.h" +#include "BKE_armature.h" #include "BKE_camera.h" #include "BKE_context.h" #include "BKE_font.h" @@ -557,7 +558,7 @@ typedef struct ViewOpsData { } ViewOpsData; -#define TRACKBALLSIZE (1.1) +#define TRACKBALLSIZE (1.1f) static void calctrackballvec(const rcti *rect, int mx, int my, float vec[3]) { @@ -1027,31 +1028,25 @@ static void viewrotate_apply(ViewOpsData *vod, int x, int y) rv3d->view = RV3D_VIEW_USER; /* need to reset every time because of view snapping */ if (U.flag & USER_TRACKBALL) { - float phi, si, q1[4], dvec[3], newvec[3]; + float axis[3], q1[4], dvec[3], newvec[3]; + float angle; calctrackballvec(&vod->ar->winrct, x, y, newvec); sub_v3_v3v3(dvec, newvec, vod->trackvec); - si = len_v3(dvec); - si /= (float)(2.0 * TRACKBALLSIZE); - - cross_v3_v3v3(q1 + 1, vod->trackvec, newvec); - normalize_v3(q1 + 1); + angle = (len_v3(dvec) / (2.0f * TRACKBALLSIZE)) * (float)M_PI; /* Allow for rotation beyond the interval [-pi, pi] */ - while (si > 1.0f) - si -= 2.0f; - - /* This relation is used instead of - * - phi = asin(si) so that the angle - * - of rotation is linearly proportional - * - to the distance that the mouse is - * - dragged. */ - phi = si * (float)M_PI_2; - - q1[0] = cosf(phi); - mul_v3_fl(q1 + 1, sinf(phi)); + angle = angle_wrap_rad(angle); + + /* This relation is used instead of the actual angle between vectors + * so that the angle of rotation is linearly proportional to + * the distance that the mouse is dragged. */ + + cross_v3_v3v3(axis, vod->trackvec, newvec); + axis_angle_to_quat(q1, axis, angle); + mul_qt_qtqt(vod->viewquat, q1, vod->oldquat); viewrotate_apply_dyn_ofs(vod, vod->viewquat); @@ -1475,8 +1470,7 @@ static void view3d_ndof_orbit(const struct wmNDOFMotionData *ndof, ScrArea *sa, /* Perform the up/down rotation */ angle = ndof->dt * rot[0]; - quat[0] = cosf(angle); - mul_v3_v3fl(quat + 1, xvec, sinf(angle)); + axis_angle_to_quat(quat, xvec, angle * 2); mul_qt_qtqt(rv3d->viewquat, rv3d->viewquat, quat); /* Perform the orbital rotation */ @@ -3042,24 +3036,7 @@ static int viewselected_exec(bContext *C, wmOperator *op) ok = ED_view3d_minmax_verts(obedit, min, max); /* only selected */ } else if (ob && (ob->mode & OB_MODE_POSE)) { - if (ob->pose) { - bArmature *arm = ob->data; - bPoseChannel *pchan; - float vec[3]; - - for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) { - if (pchan->bone->flag & BONE_SELECTED) { - if (pchan->bone->layer & arm->layer) { - bPoseChannel *pchan_tx = pchan->custom_tx ? pchan->custom_tx : pchan; - ok = 1; - mul_v3_m4v3(vec, ob->obmat, pchan_tx->pose_head); - minmax_v3v3_v3(min, max, vec); - mul_v3_m4v3(vec, ob->obmat, pchan_tx->pose_tail); - minmax_v3v3_v3(min, max, vec); - } - } - } - } + ok = BKE_pose_minmax(ob, min, max, true, true); } else if (BKE_paint_select_face_test(ob)) { ok = paintface_minmax(ob, min, max); @@ -3785,7 +3762,7 @@ static void axis_set_view(bContext *C, View3D *v3d, ARegion *ar, float twmat[3][3]; /* same as transform manipulator when normal is set */ - ED_getTransformOrientationMatrix(C, twmat, true); + ED_getTransformOrientationMatrix(C, twmat, V3D_ACTIVE); mat3_to_quat(obact_quat, twmat); invert_qt(obact_quat); diff --git a/source/blender/editors/space_view3d/view3d_select.c b/source/blender/editors/space_view3d/view3d_select.c index 5a35e9fcad1..69e354d87c7 100644 --- a/source/blender/editors/space_view3d/view3d_select.c +++ b/source/blender/editors/space_view3d/view3d_select.c @@ -1193,7 +1193,10 @@ static short selectbuffer_ret_hits_5(unsigned int *buffer, const short hits15, c /* we want a select buffer with bones, if there are... */ /* so check three selection levels and compare */ -static short mixed_bones_object_selectbuffer(ViewContext *vc, unsigned int *buffer, const int mval[2], bool *p_do_nearest, bool enumerate) +static short mixed_bones_object_selectbuffer( + ViewContext *vc, unsigned int *buffer, const int mval[2], + bool use_cycle, bool enumerate, + bool *r_do_nearest) { rcti rect; int offs; @@ -1204,16 +1207,24 @@ static short mixed_bones_object_selectbuffer(ViewContext *vc, unsigned int *buff View3D *v3d = vc->v3d; /* define if we use solid nearest select or not */ - if (v3d->drawtype > OB_WIRE) { - do_nearest = true; - if (len_manhattan_v2v2_int(mval, last_mval) < 3) { - do_nearest = false; + if (use_cycle) { + if (v3d->drawtype > OB_WIRE) { + do_nearest = true; + if (len_manhattan_v2v2_int(mval, last_mval) < 3) { + do_nearest = false; + } + } + copy_v2_v2_int(last_mval, mval); + } + else { + if (v3d->drawtype > OB_WIRE) { + do_nearest = true; } } - copy_v2_v2_int(last_mval, mval); - if (p_do_nearest) - *p_do_nearest = do_nearest; + if (r_do_nearest) { + *r_do_nearest = do_nearest; + } do_nearest = do_nearest && !enumerate; @@ -1353,7 +1364,7 @@ Base *ED_view3d_give_base_under_cursor(bContext *C, const int mval[2]) view3d_operator_needs_opengl(C); view3d_set_viewcontext(C, &vc); - hits = mixed_bones_object_selectbuffer(&vc, buffer, mval, &do_nearest, false); + hits = mixed_bones_object_selectbuffer(&vc, buffer, mval, false, false, &do_nearest); if (hits > 0) { const bool has_bones = selectbuffer_has_bones(buffer, hits); @@ -1448,7 +1459,7 @@ static bool mouse_select(bContext *C, const int mval[2], /* if objects have posemode set, the bones are in the same selection buffer */ - hits = mixed_bones_object_selectbuffer(&vc, buffer, mval, &do_nearest, enumerate); + hits = mixed_bones_object_selectbuffer(&vc, buffer, mval, true, enumerate, &do_nearest); if (hits > 0) { /* note: bundles are handling in the same way as bones */ diff --git a/source/blender/editors/space_view3d/view3d_view.c b/source/blender/editors/space_view3d/view3d_view.c index 49ac3881fab..0f05f4e52dd 100644 --- a/source/blender/editors/space_view3d/view3d_view.c +++ b/source/blender/editors/space_view3d/view3d_view.c @@ -1785,7 +1785,7 @@ float ED_view3d_radius_to_dist( lens = params.lens; sensor_size = BKE_camera_sensor_size(params.sensor_fit, params.sensor_x, params.sensor_y); - /* ignore 'rv3d->camzoom' because we wan't to fit to the cameras frame */ + /* ignore 'rv3d->camzoom' because we want to fit to the cameras frame */ zoom = CAMERA_PARAM_ZOOM_INIT_CAMOB; } else { diff --git a/source/blender/editors/space_view3d/view3d_walk.c b/source/blender/editors/space_view3d/view3d_walk.c index e2fbbf58a5c..0bda6e37fd1 100644 --- a/source/blender/editors/space_view3d/view3d_walk.c +++ b/source/blender/editors/space_view3d/view3d_walk.c @@ -62,6 +62,9 @@ #define USE_TABLET_SUPPORT +/* ensure the target position is one we can reach, see: T45771 */ +#define USE_PIXELSIZE_NATIVE_SUPPORT + /* prototypes */ static float getVelocityZeroTime(const float gravity, const float velocity); @@ -578,6 +581,16 @@ static bool initWalkInfo(bContext *C, WalkInfo *walk, wmOperator *op) walk->center_mval[0] = walk->ar->winx * 0.5f; walk->center_mval[1] = walk->ar->winy * 0.5f; +#ifdef USE_PIXELSIZE_NATIVE_SUPPORT + walk->center_mval[0] += walk->ar->winrct.xmin; + walk->center_mval[1] += walk->ar->winrct.ymin; + + WM_cursor_compatible_xy(win, &walk->center_mval[0], &walk->center_mval[1]); + + walk->center_mval[0] -= walk->ar->winrct.xmin; + walk->center_mval[1] -= walk->ar->winrct.ymin; +#endif + copy_v2_v2_int(walk->prev_mval, walk->center_mval); WM_cursor_warp(win, diff --git a/source/blender/editors/transform/transform.c b/source/blender/editors/transform/transform.c index 3f9077421b1..d6ce32f9974 100644 --- a/source/blender/editors/transform/transform.c +++ b/source/blender/editors/transform/transform.c @@ -168,11 +168,12 @@ static void applyBoneEnvelope(TransInfo *t, const int mval[2]); static void initBoneRoll(TransInfo *t); static void applyBoneRoll(TransInfo *t, const int mval[2]); -static void initEdgeSlide_ex(TransInfo *t, bool use_double_side); +static void initEdgeSlide_ex(TransInfo *t, bool use_double_side, bool use_even, bool flipped, bool use_clamp); static void initEdgeSlide(TransInfo *t); static eRedrawFlag handleEventEdgeSlide(TransInfo *t, const struct wmEvent *event); static void applyEdgeSlide(TransInfo *t, const int mval[2]); +static void initVertSlide_ex(TransInfo *t, bool use_even, bool flipped, bool use_clamp); static void initVertSlide(TransInfo *t); static eRedrawFlag handleEventVertSlide(TransInfo *t, const struct wmEvent *event); static void applyVertSlide(TransInfo *t, const int mval[2]); @@ -1037,6 +1038,7 @@ int transformEvent(TransInfo *t, const wmEvent *event) } /* vert slide can fail on unconnected vertices (rare but possible) */ if (t->state == TRANS_CANCEL) { + t->mode = TFM_TRANSLATION; t->state = TRANS_STARTING; restoreTransObjects(t); resetTransRestrictions(t); @@ -1063,15 +1065,14 @@ int transformEvent(TransInfo *t, const wmEvent *event) /* only switch when... */ if (!(t->options & CTX_TEXTURE) && !(t->options & (CTX_MOVIECLIP | CTX_MASK))) { if (ELEM(t->mode, TFM_ROTATION, TFM_RESIZE, TFM_TRACKBALL, TFM_TRANSLATION, TFM_EDGE_SLIDE, TFM_VERT_SLIDE)) { + restoreTransObjects(t); resetTransModal(t); resetTransRestrictions(t); if (t->mode == TFM_ROTATION) { - restoreTransObjects(t); initTrackball(t); } else { - restoreTransObjects(t); initRotation(t); } initSnapping(t, NULL); // need to reinit after mode change @@ -1363,15 +1364,14 @@ int transformEvent(TransInfo *t, const wmEvent *event) /* only switch when... */ if (!(t->options & CTX_TEXTURE)) { if (ELEM(t->mode, TFM_ROTATION, TFM_RESIZE, TFM_TRACKBALL, TFM_TRANSLATION)) { + restoreTransObjects(t); resetTransModal(t); resetTransRestrictions(t); if (t->mode == TFM_ROTATION) { - restoreTransObjects(t); initTrackball(t); } else { - restoreTransObjects(t); initRotation(t); } initSnapping(t, NULL); // need to reinit after mode change @@ -1721,7 +1721,7 @@ static void drawHelpline(bContext *UNUSED(C), int x, int y, void *customdata) glVertex2fv(cent); glEnd(); - glTranslatef(mval[0], mval[1], 0); + glTranslate2iv(mval); glRotatef(-RAD2DEGF(atan2f(cent[0] - t->mval[0], cent[1] - t->mval[1])), 0, 0, 1); setlinestyle(0); @@ -1733,7 +1733,7 @@ static void drawHelpline(bContext *UNUSED(C), int x, int y, void *customdata) case HLP_HARROW: UI_ThemeColor(TH_VIEW_OVERLAY); - glTranslatef(mval[0], mval[1], 0); + glTranslate2iv(mval); glLineWidth(3.0); drawArrow(RIGHT, 5, 10, 5); @@ -1743,7 +1743,7 @@ static void drawHelpline(bContext *UNUSED(C), int x, int y, void *customdata) case HLP_VARROW: UI_ThemeColor(TH_VIEW_OVERLAY); - glTranslatef(mval[0], mval[1], 0); + glTranslate2iv(mval); glLineWidth(3.0); drawArrow(UP, 5, 10, 5); @@ -1794,7 +1794,7 @@ static void drawHelpline(bContext *UNUSED(C), int x, int y, void *customdata) unsigned char col[3], col2[3]; UI_GetThemeColor3ubv(TH_GRID, col); - glTranslatef(mval[0], mval[1], 0); + glTranslate2iv(mval); glLineWidth(3.0); @@ -2077,47 +2077,41 @@ bool initTransform(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve t->launch_event = LEFTMOUSE; } + unit_m3(t->spacemtx); + initTransInfo(C, t, op, event); + initTransformOrientation(C, t); if (t->spacetype == SPACE_VIEW3D) { - initTransformOrientation(C, t); - t->draw_handle_apply = ED_region_draw_cb_activate(t->ar->type, drawTransformApply, t, REGION_DRAW_PRE_VIEW); t->draw_handle_view = ED_region_draw_cb_activate(t->ar->type, drawTransformView, t, REGION_DRAW_POST_VIEW); t->draw_handle_pixel = ED_region_draw_cb_activate(t->ar->type, drawTransformPixel, t, REGION_DRAW_POST_PIXEL); t->draw_handle_cursor = WM_paint_cursor_activate(CTX_wm_manager(C), helpline_poll, drawHelpline, t); } else if (t->spacetype == SPACE_IMAGE) { - unit_m3(t->spacemtx); t->draw_handle_view = ED_region_draw_cb_activate(t->ar->type, drawTransformView, t, REGION_DRAW_POST_VIEW); //t->draw_handle_pixel = ED_region_draw_cb_activate(t->ar->type, drawTransformPixel, t, REGION_DRAW_POST_PIXEL); t->draw_handle_cursor = WM_paint_cursor_activate(CTX_wm_manager(C), helpline_poll, drawHelpline, t); } else if (t->spacetype == SPACE_CLIP) { - unit_m3(t->spacemtx); t->draw_handle_view = ED_region_draw_cb_activate(t->ar->type, drawTransformView, t, REGION_DRAW_POST_VIEW); t->draw_handle_cursor = WM_paint_cursor_activate(CTX_wm_manager(C), helpline_poll, drawHelpline, t); } else if (t->spacetype == SPACE_NODE) { - unit_m3(t->spacemtx); /*t->draw_handle_apply = ED_region_draw_cb_activate(t->ar->type, drawTransformApply, t, REGION_DRAW_PRE_VIEW);*/ t->draw_handle_view = ED_region_draw_cb_activate(t->ar->type, drawTransformView, t, REGION_DRAW_POST_VIEW); t->draw_handle_cursor = WM_paint_cursor_activate(CTX_wm_manager(C), helpline_poll, drawHelpline, t); } else if (t->spacetype == SPACE_IPO) { - unit_m3(t->spacemtx); t->draw_handle_view = ED_region_draw_cb_activate(t->ar->type, drawTransformView, t, REGION_DRAW_POST_VIEW); //t->draw_handle_pixel = ED_region_draw_cb_activate(t->ar->type, drawTransformPixel, t, REGION_DRAW_POST_PIXEL); t->draw_handle_cursor = WM_paint_cursor_activate(CTX_wm_manager(C), helpline_poll, drawHelpline, t); } else if (t->spacetype == SPACE_ACTION) { - unit_m3(t->spacemtx); t->draw_handle_view = ED_region_draw_cb_activate(t->ar->type, drawTransformView, t, REGION_DRAW_POST_VIEW); //t->draw_handle_pixel = ED_region_draw_cb_activate(t->ar->type, drawTransformPixel, t, REGION_DRAW_POST_PIXEL); t->draw_handle_cursor = WM_paint_cursor_activate(CTX_wm_manager(C), helpline_poll, drawHelpline, t); } - else - unit_m3(t->spacemtx); createTransData(C, t); // make TransData structs from selection @@ -2234,14 +2228,20 @@ bool initTransform(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve t->mode = TFM_BONE_ENVELOPE_DIST; break; case TFM_EDGE_SLIDE: + case TFM_VERT_SLIDE: { - const bool use_double_side = (op ? !RNA_boolean_get(op->ptr, "single_side") : true); - initEdgeSlide_ex(t, use_double_side); + const bool use_even = (op ? RNA_boolean_get(op->ptr, "use_even") : false); + const bool flipped = (op ? RNA_boolean_get(op->ptr, "flipped") : false); + const bool use_clamp = (op ? RNA_boolean_get(op->ptr, "use_clamp") : true); + if (mode == TFM_EDGE_SLIDE) { + const bool use_double_side = (op ? !RNA_boolean_get(op->ptr, "single_side") : true); + initEdgeSlide_ex(t, use_double_side, use_even, flipped, use_clamp); + } + else { + initVertSlide_ex(t, use_even, flipped, use_clamp); + } break; } - case TFM_VERT_SLIDE: - initVertSlide(t); - break; case TFM_BONE_ROLL: initBoneRoll(t); break; @@ -3092,6 +3092,7 @@ static void applyShear(TransInfo *t, const int UNUSED(mval[2])) float value; int i; char str[MAX_INFO_LEN]; + const bool is_local_center = transdata_check_local_center(t, t->around); copy_m3_m4(persmat, t->viewmat); invert_m3_m3(persinv, persmat); @@ -3127,8 +3128,10 @@ static void applyShear(TransInfo *t, const int UNUSED(mval[2])) mul_m3_m3m3(tmat, smat, persmat); mul_m3_m3m3(totmat, persinv, tmat); - + for (i = 0; i < t->total; i++, td++) { + const float *center, *co; + if (td->flag & TD_NOACTION) break; @@ -3143,12 +3146,22 @@ static void applyShear(TransInfo *t, const int UNUSED(mval[2])) else { copy_m3_m3(tmat, totmat); } - sub_v3_v3v3(vec, td->center, t->center); + + if (is_local_center) { + center = td->center; + co = td->loc; + } + else { + center = t->center; + co = td->center; + } + + sub_v3_v3v3(vec, co, center); mul_m3_v3(tmat, vec); - add_v3_v3(vec, t->center); - sub_v3_v3(vec, td->center); + add_v3_v3(vec, center); + sub_v3_v3(vec, co); mul_v3_fl(vec, td->factor); @@ -5967,7 +5980,7 @@ static void calcEdgeSlide_mval_range( } } -static void calcEdgeSlide_non_proportional( +static void calcEdgeSlide_even( TransInfo *t, EdgeSlideData *sld, const float mval[2]) { TransDataEdgeSlideVert *sv = sld->sv; @@ -6013,7 +6026,7 @@ static void calcEdgeSlide_non_proportional( } } -static bool createEdgeSlideVerts_double_side(TransInfo *t) +static bool createEdgeSlideVerts_double_side(TransInfo *t, bool use_even, bool flipped, bool use_clamp) { BMEditMesh *em = BKE_editmesh_from_object(t->obedit); BMesh *bm = em->bm; @@ -6032,9 +6045,11 @@ static bool createEdgeSlideVerts_double_side(TransInfo *t) slide_origdata_init_flag(t, &sld->orig_data); - sld->is_proportional = true; + sld->use_even = use_even; sld->curr_sv_index = 0; - sld->flipped_vtx = false; + sld->flipped = flipped; + if (!use_clamp) + t->flag |= T_ALT_TRANSFORM; /*ensure valid selection*/ BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) { @@ -6340,7 +6355,7 @@ static bool createEdgeSlideVerts_double_side(TransInfo *t) slide_origdata_create_data(t, &sld->orig_data, (TransDataGenericSlideVert *)sld->sv, sizeof(*sld->sv), sld->totsv); if (rv3d) { - calcEdgeSlide_non_proportional(t, sld, mval); + calcEdgeSlide_even(t, sld, mval); } sld->em = em; @@ -6358,7 +6373,7 @@ static bool createEdgeSlideVerts_double_side(TransInfo *t) * A simple version of #createEdgeSlideVerts_double_side * Which assumes the longest unselected. */ -static bool createEdgeSlideVerts_single_side(TransInfo *t) +static bool createEdgeSlideVerts_single_side(TransInfo *t, bool use_even, bool flipped, bool use_clamp) { BMEditMesh *em = BKE_editmesh_from_object(t->obedit); BMesh *bm = em->bm; @@ -6383,10 +6398,12 @@ static bool createEdgeSlideVerts_single_side(TransInfo *t) slide_origdata_init_flag(t, &sld->orig_data); - sld->is_proportional = true; + sld->use_even = use_even; sld->curr_sv_index = 0; - /* heppans to be best for single-sided */ - sld->flipped_vtx = true; + /* happens to be best for single-sided */ + sld->flipped = !flipped; + if (!use_clamp) + t->flag |= T_ALT_TRANSFORM; /* ensure valid selection */ j = 0; @@ -6532,7 +6549,7 @@ static bool createEdgeSlideVerts_single_side(TransInfo *t) slide_origdata_create_data(t, &sld->orig_data, (TransDataGenericSlideVert *)sld->sv, sizeof(*sld->sv), sld->totsv); if (rv3d) { - calcEdgeSlide_non_proportional(t, sld, mval); + calcEdgeSlide_even(t, sld, mval); } sld->em = em; @@ -6580,7 +6597,7 @@ void freeEdgeSlideVerts(TransInfo *t) t->customData = NULL; } -static void initEdgeSlide_ex(TransInfo *t, bool use_double_side) +static void initEdgeSlide_ex(TransInfo *t, bool use_double_side, bool use_even, bool flipped, bool use_clamp) { EdgeSlideData *sld; bool ok; @@ -6590,10 +6607,10 @@ static void initEdgeSlide_ex(TransInfo *t, bool use_double_side) t->handleEvent = handleEventEdgeSlide; if (use_double_side) { - ok = createEdgeSlideVerts_double_side(t); + ok = createEdgeSlideVerts_double_side(t, use_even, flipped, use_clamp); } else { - ok = createEdgeSlideVerts_single_side(t); + ok = createEdgeSlideVerts_single_side(t, use_even, flipped, use_clamp); } if (!ok) { @@ -6627,7 +6644,7 @@ static void initEdgeSlide_ex(TransInfo *t, bool use_double_side) static void initEdgeSlide(TransInfo *t) { - initEdgeSlide_ex(t, true); + initEdgeSlide_ex(t, true, false, false, true); } static eRedrawFlag handleEventEdgeSlide(struct TransInfo *t, const struct wmEvent *event) @@ -6639,16 +6656,14 @@ static eRedrawFlag handleEventEdgeSlide(struct TransInfo *t, const struct wmEven switch (event->type) { case EKEY: if (event->val == KM_PRESS) { - sld->is_proportional = !sld->is_proportional; + sld->use_even = !sld->use_even; calcEdgeSlideCustomPoints(t); return TREDRAW_HARD; } break; case FKEY: if (event->val == KM_PRESS) { - if (sld->is_proportional == false) { - sld->flipped_vtx = !sld->flipped_vtx; - } + sld->flipped = !sld->flipped; calcEdgeSlideCustomPoints(t); return TREDRAW_HARD; } @@ -6688,8 +6703,8 @@ static void drawEdgeSlide(TransInfo *t) EdgeSlideData *sld = t->customData; const bool is_clamp = !(t->flag & T_ALT_TRANSFORM); - /* Non-Prop mode */ - if ((sld->is_proportional == false) || (is_clamp == false)) { + /* Even mode */ + if ((sld->use_even == true) || (is_clamp == false)) { View3D *v3d = t->view; const float line_size = UI_GetThemeValuef(TH_OUTLINE_WIDTH) + 0.5f; @@ -6704,7 +6719,7 @@ static void drawEdgeSlide(TransInfo *t) glMultMatrixf(t->obedit->obmat); - if (sld->is_proportional == false) { + if (sld->use_even == true) { float co_a[3], co_b[3], co_mark[3]; TransDataEdgeSlideVert *curr_sv = &sld->sv[sld->curr_sv_index]; const float fac = (sld->perc + 1.0f) / 2.0f; @@ -6731,7 +6746,7 @@ static void drawEdgeSlide(TransInfo *t) UI_ThemeColorShadeAlpha(TH_SELECT, -30, alpha_shade); glPointSize(ctrl_size); bglBegin(GL_POINTS); - if (sld->flipped_vtx) { + if (sld->flipped) { if (curr_sv->v_side[1]) bglVertex3fv(curr_sv->v_side[1]->co); } else { @@ -6807,7 +6822,7 @@ static void doEdgeSlide(TransInfo *t, float perc) sld->perc = perc; sv = svlist; - if (sld->is_proportional == true) { + if (sld->use_even == false) { const bool is_clamp = !(t->flag & T_ALT_TRANSFORM); if (is_clamp) { const int side_index = (perc < 0.0f); @@ -6837,7 +6852,7 @@ static void doEdgeSlide(TransInfo *t, float perc) } else { /** - * Implementation note, non proportional mode ignores the starting positions and uses only the + * Implementation note, even mode ignores the starting positions and uses only the * a/b verts, this could be changed/improved so the distance is still met but the verts are moved along * their original path (which may not be straight), however how it works now is OK and matches 2.4x - Campbell * @@ -6845,7 +6860,7 @@ static void doEdgeSlide(TransInfo *t, float perc) * is the same as the distance between the original vert locations, same goes for the lines below. */ TransDataEdgeSlideVert *curr_sv = &sld->sv[sld->curr_sv_index]; - const float curr_length_perc = curr_sv->edge_len * (((sld->flipped_vtx ? perc : -perc) + 1.0f) / 2.0f); + const float curr_length_perc = curr_sv->edge_len * (((sld->flipped ? perc : -perc) + 1.0f) / 2.0f); float co_a[3]; float co_b[3]; @@ -6857,7 +6872,7 @@ static void doEdgeSlide(TransInfo *t, float perc) add_v3_v3v3(co_a, sv->v_co_orig, sv->dir_side[0]); add_v3_v3v3(co_b, sv->v_co_orig, sv->dir_side[1]); - if (sld->flipped_vtx) { + if (sld->flipped) { interp_line_v3_v3v3v3(sv->v->co, co_b, sv->v_co_orig, co_a, fac); } else { @@ -6874,8 +6889,8 @@ static void applyEdgeSlide(TransInfo *t, const int UNUSED(mval[2])) size_t ofs = 0; float final; EdgeSlideData *sld = t->customData; - bool flipped = sld->flipped_vtx; - bool is_proportional = sld->is_proportional; + bool flipped = sld->flipped; + bool use_even = sld->use_even; const bool is_clamp = !(t->flag & T_ALT_TRANSFORM); const bool is_constrained = !(is_clamp == false || hasNumInput(&t->num)); @@ -6902,8 +6917,8 @@ static void applyEdgeSlide(TransInfo *t, const int UNUSED(mval[2])) else { ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, "%.4f ", final); } - ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, IFACE_("(E)ven: %s, "), WM_bool_as_string(!is_proportional)); - if (!is_proportional) { + ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, IFACE_("(E)ven: %s, "), WM_bool_as_string(use_even)); + if (use_even) { ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, IFACE_("(F)lipped: %s, "), WM_bool_as_string(flipped)); } ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, IFACE_("Alt or (C)lamp: %s"), WM_bool_as_string(is_clamp)); @@ -6944,7 +6959,7 @@ static void calcVertSlideCustomPoints(struct TransInfo *t) ARRAY_SET_ITEMS(mval_start, co_orig_2d[0] + mval_ofs[0], co_orig_2d[1] + mval_ofs[1]); ARRAY_SET_ITEMS(mval_end, co_curr_2d[0] + mval_ofs[0], co_curr_2d[1] + mval_ofs[1]); - if (sld->flipped_vtx && sld->is_proportional == false) { + if (sld->flipped && sld->use_even) { setCustomPoints(t, &t->mouse, mval_start, mval_end); } else { @@ -7035,7 +7050,7 @@ static void calcVertSlideMouseActiveEdges(struct TransInfo *t, const int mval[2] } } -static bool createVertSlideVerts(TransInfo *t) +static bool createVertSlideVerts(TransInfo *t, bool use_even, bool flipped, bool use_clamp) { BMEditMesh *em = BKE_editmesh_from_object(t->obedit); BMesh *bm = em->bm; @@ -7049,9 +7064,11 @@ static bool createVertSlideVerts(TransInfo *t) slide_origdata_init_flag(t, &sld->orig_data); - sld->is_proportional = true; + sld->use_even = use_even; sld->curr_sv_index = 0; - sld->flipped_vtx = false; + sld->flipped = flipped; + if (!use_clamp) + t->flag |= T_ALT_TRANSFORM; j = 0; BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) { @@ -7185,7 +7202,7 @@ void freeVertSlideVerts(TransInfo *t) t->customData = NULL; } -static void initVertSlide(TransInfo *t) +static void initVertSlide_ex(TransInfo *t, bool use_even, bool flipped, bool use_clamp) { VertSlideData *sld; @@ -7193,7 +7210,7 @@ static void initVertSlide(TransInfo *t) t->transform = applyVertSlide; t->handleEvent = handleEventVertSlide; - if (!createVertSlideVerts(t)) { + if (!createVertSlideVerts(t, use_even, flipped, use_clamp)) { t->state = TRANS_CANCEL; return; } @@ -7222,6 +7239,11 @@ static void initVertSlide(TransInfo *t) t->flag |= T_NO_CONSTRAINT | T_NO_PROJECT; } +static void initVertSlide(TransInfo *t) +{ + initVertSlide_ex(t, false, false, true); +} + static eRedrawFlag handleEventVertSlide(struct TransInfo *t, const struct wmEvent *event) { if (t->mode == TFM_VERT_SLIDE) { @@ -7231,8 +7253,8 @@ static eRedrawFlag handleEventVertSlide(struct TransInfo *t, const struct wmEven switch (event->type) { case EKEY: if (event->val == KM_PRESS) { - sld->is_proportional = !sld->is_proportional; - if (sld->flipped_vtx) { + sld->use_even = !sld->use_even; + if (sld->flipped) { calcVertSlideCustomPoints(t); } return TREDRAW_HARD; @@ -7240,7 +7262,7 @@ static eRedrawFlag handleEventVertSlide(struct TransInfo *t, const struct wmEven break; case FKEY: if (event->val == KM_PRESS) { - sld->flipped_vtx = !sld->flipped_vtx; + sld->flipped = !sld->flipped; calcVertSlideCustomPoints(t); return TREDRAW_HARD; } @@ -7339,7 +7361,7 @@ static void drawVertSlide(TransInfo *t) glPointSize(ctrl_size); bglBegin(GL_POINTS); - bglVertex3fv((sld->flipped_vtx && sld->is_proportional == false) ? + bglVertex3fv((sld->flipped && sld->use_even) ? curr_sv->co_link_orig_3d[curr_sv->co_link_curr] : curr_sv->co_orig_3d); bglEnd(); @@ -7397,7 +7419,7 @@ static void doVertSlide(TransInfo *t, float perc) sld->perc = perc; sv = svlist; - if (sld->is_proportional == true) { + if (sld->use_even == false) { for (i = 0; i < sld->totsv; i++, sv++) { interp_v3_v3v3(sv->v->co, sv->co_orig_3d, sv->co_link_orig_3d[sv->co_link_curr], perc); } @@ -7415,7 +7437,7 @@ static void doVertSlide(TransInfo *t, float perc) edge_len = normalize_v3(dir); if (edge_len > FLT_EPSILON) { - if (sld->flipped_vtx) { + if (sld->flipped) { madd_v3_v3v3fl(sv->v->co, sv->co_link_orig_3d[sv->co_link_curr], dir, -tperc); } else { @@ -7435,8 +7457,8 @@ static void applyVertSlide(TransInfo *t, const int UNUSED(mval[2])) size_t ofs = 0; float final; VertSlideData *sld = t->customData; - const bool flipped = sld->flipped_vtx; - const bool is_proportional = sld->is_proportional; + const bool flipped = sld->flipped; + const bool use_even = sld->use_even; const bool is_clamp = !(t->flag & T_ALT_TRANSFORM); const bool is_constrained = !(is_clamp == false || hasNumInput(&t->num)); @@ -7463,8 +7485,8 @@ static void applyVertSlide(TransInfo *t, const int UNUSED(mval[2])) else { ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, "%.4f ", final); } - ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, IFACE_("(E)ven: %s, "), WM_bool_as_string(!is_proportional)); - if (!is_proportional) { + ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, IFACE_("(E)ven: %s, "), WM_bool_as_string(use_even)); + if (use_even) { ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, IFACE_("(F)lipped: %s, "), WM_bool_as_string(flipped)); } ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, IFACE_("Alt or (C)lamp: %s"), WM_bool_as_string(is_clamp)); diff --git a/source/blender/editors/transform/transform.h b/source/blender/editors/transform/transform.h index 79bb0fe0b76..a735801ff47 100644 --- a/source/blender/editors/transform/transform.h +++ b/source/blender/editors/transform/transform.h @@ -252,8 +252,8 @@ typedef struct EdgeSlideData { float perc; - bool is_proportional; - bool flipped_vtx; + bool use_even; + bool flipped; int curr_sv_index; @@ -284,8 +284,8 @@ typedef struct VertSlideData { float perc; - bool is_proportional; - bool flipped_vtx; + bool use_even; + bool flipped; int curr_sv_index; @@ -729,7 +729,7 @@ bool createSpaceNormalTangent(float mat[3][3], const float normal[3], const floa struct TransformOrientation *addMatrixSpace(struct bContext *C, float mat[3][3], const char *name, const bool overwrite); -bool applyTransformOrientation(const struct bContext *C, float mat[3][3], char r_name[64]); +bool applyTransformOrientation(const struct bContext *C, float mat[3][3], char r_name[64], int index); #define ORIENTATION_NONE 0 #define ORIENTATION_NORMAL 1 @@ -737,7 +737,8 @@ bool applyTransformOrientation(const struct bContext *C, float mat[3][3], char r #define ORIENTATION_EDGE 3 #define ORIENTATION_FACE 4 -int getTransformOrientation(const struct bContext *C, float normal[3], float plane[3], const bool activeOnly); +int getTransformOrientation_ex(const struct bContext *C, float normal[3], float plane[3], const short around); +int getTransformOrientation(const struct bContext *C, float normal[3], float plane[3]); void freeEdgeSlideTempFaces(EdgeSlideData *sld); void freeEdgeSlideVerts(TransInfo *t); diff --git a/source/blender/editors/transform/transform_constraints.c b/source/blender/editors/transform/transform_constraints.c index 9f4d53f1f22..895c8a81044 100644 --- a/source/blender/editors/transform/transform_constraints.c +++ b/source/blender/editors/transform/transform_constraints.c @@ -855,21 +855,15 @@ void getConstraintMatrix(TransInfo *t) unit_m3(t->con.pmtx); if (!(t->con.mode & CON_AXIS0)) { - t->con.pmtx[0][0] = - t->con.pmtx[0][1] = - t->con.pmtx[0][2] = 0.0f; + zero_v3(t->con.pmtx[0]); } if (!(t->con.mode & CON_AXIS1)) { - t->con.pmtx[1][0] = - t->con.pmtx[1][1] = - t->con.pmtx[1][2] = 0.0f; + zero_v3(t->con.pmtx[1]); } if (!(t->con.mode & CON_AXIS2)) { - t->con.pmtx[2][0] = - t->con.pmtx[2][1] = - t->con.pmtx[2][2] = 0.0f; + zero_v3(t->con.pmtx[2]); } mul_m3_m3m3(mat, t->con.pmtx, t->con.imtx); diff --git a/source/blender/editors/transform/transform_conversions.c b/source/blender/editors/transform/transform_conversions.c index 687cf2f69e4..5e13afdc152 100644 --- a/source/blender/editors/transform/transform_conversions.c +++ b/source/blender/editors/transform/transform_conversions.c @@ -1252,7 +1252,18 @@ static void createTransArmatureVerts(TransInfo *t) else { if (ebo->flag & BONE_TIPSEL) { copy_v3_v3(td->iloc, ebo->tail); - copy_v3_v3(td->center, (t->around == V3D_LOCAL) ? ebo->head : td->iloc); + + /* Don't allow single selected tips to have a modified center, + * causes problem with snapping (see T45974). + * However, in rotation mode, we want to keep that 'rotate bone around root with + * only its tip selected' behavior (see T46325). */ + if ((t->around == V3D_LOCAL) && ((t->mode == TFM_ROTATION) || (ebo->flag & BONE_ROOTSEL))) { + copy_v3_v3(td->center, ebo->head); + } + else { + copy_v3_v3(td->center, td->iloc); + } + td->loc = ebo->tail; td->flag = TD_SELECTED; if (ebo->flag & BONE_EDITMODE_LOCKED) @@ -1655,7 +1666,7 @@ static void createTransCurveVerts(TransInfo *t) /* TODO - in the case of tilt and radius we can also avoid allocating the initTransDataCurveHandles * but for now just don't change handle types */ - if (ELEM(t->mode, TFM_CURVE_SHRINKFATTEN, TFM_TILT) == 0) { + if (ELEM(t->mode, TFM_CURVE_SHRINKFATTEN, TFM_TILT, TFM_DUMMY) == 0) { /* sets the handles based on their selection, do this after the data is copied to the TransData */ BKE_nurb_handles_test(nu, !hide_handles); } @@ -5548,7 +5559,7 @@ void autokeyframe_ob_cb_func(bContext *C, Scene *scene, View3D *v3d, Object *ob, if (IS_AUTOKEY_FLAG(scene, ONLYKEYINGSET) && (active_ks)) { /* only insert into active keyingset - * NOTE: we assume here that the active Keying Set does not need to have its iterator overridden spe + * NOTE: we assume here that the active Keying Set does not need to have its iterator overridden */ ANIM_apply_keyingset(C, &dsources, NULL, active_ks, MODIFYKEY_MODE_INSERT, cfra); } diff --git a/source/blender/editors/transform/transform_generics.c b/source/blender/editors/transform/transform_generics.c index 83e43bd08af..f3009ba0068 100644 --- a/source/blender/editors/transform/transform_generics.c +++ b/source/blender/editors/transform/transform_generics.c @@ -1213,18 +1213,7 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve t->around = V3D_CURSOR; } - if (op && ((prop = RNA_struct_find_property(op->ptr, "constraint_orientation")) && - RNA_property_is_set(op->ptr, prop))) - { - t->current_orientation = RNA_property_enum_get(op->ptr, prop); - - if (t->current_orientation >= V3D_MANIP_CUSTOM + BIF_countTransformOrientation(C)) { - t->current_orientation = V3D_MANIP_GLOBAL; - } - } - else { - t->current_orientation = v3d->twmode; - } + t->current_orientation = v3d->twmode; /* exceptional case */ if (t->around == V3D_LOCAL) { @@ -1311,6 +1300,16 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve } t->around = V3D_CENTER; } + + if (op && ((prop = RNA_struct_find_property(op->ptr, "constraint_orientation")) && + RNA_property_is_set(op->ptr, prop))) + { + t->current_orientation = RNA_property_enum_get(op->ptr, prop); + + if (t->current_orientation >= V3D_MANIP_CUSTOM + BIF_countTransformOrientation(C)) { + t->current_orientation = V3D_MANIP_GLOBAL; + } + } if (op && ((prop = RNA_struct_find_property(op->ptr, "release_confirm")) && RNA_property_is_set(op->ptr, prop))) @@ -1838,7 +1837,7 @@ void calculateCenter(TransInfo *t) /* zfac is only used convertViewVec only in cases operator was invoked in RGN_TYPE_WINDOW * and never used in other cases. * - * We need special case here as well, since ED_view3d_calc_zfac will crahs when called + * We need special case here as well, since ED_view3d_calc_zfac will crash when called * for a region different from RGN_TYPE_WINDOW. */ if (t->ar->regiontype == RGN_TYPE_WINDOW) { diff --git a/source/blender/editors/transform/transform_manipulator.c b/source/blender/editors/transform/transform_manipulator.c index a4ea37bc175..522cf15eb10 100644 --- a/source/blender/editors/transform/transform_manipulator.c +++ b/source/blender/editors/transform/transform_manipulator.c @@ -889,6 +889,7 @@ static int calc_manipulator_stats(const bContext *C) /* fall-through */ case V3D_MANIP_NORMAL: if (obedit || ob->mode & OB_MODE_POSE) { + float mat[3][3]; ED_getTransformOrientationMatrix(C, mat, (v3d->around == V3D_ACTIVE)); copy_m4_m3(rv3d->twmat, mat); break; @@ -901,6 +902,7 @@ static int calc_manipulator_stats(const bContext *C) * use the active pones axis for display [#33575], this works as expected on a single bone * and users who select many bones will understand whats going on and what local means * when they start transforming */ + float mat[3][3]; ED_getTransformOrientationMatrix(C, mat, (v3d->around == V3D_ACTIVE)); copy_m4_m3(rv3d->twmat, mat); break; @@ -914,10 +916,13 @@ static int calc_manipulator_stats(const bContext *C) copy_m4_m3(rv3d->twmat, mat); break; default: /* V3D_MANIP_CUSTOM */ - if (applyTransformOrientation(C, mat, NULL)) { + { + float mat[3][3]; + if (applyTransformOrientation(C, mat, NULL, v3d->twmode - V3D_MANIP_CUSTOM)) { copy_m4_m3(rv3d->twmat, mat); } break; + } } } diff --git a/source/blender/editors/transform/transform_ops.c b/source/blender/editors/transform/transform_ops.c index d7cb5362cd6..a95fa627ef2 100644 --- a/source/blender/editors/transform/transform_ops.c +++ b/source/blender/editors/transform/transform_ops.c @@ -644,8 +644,6 @@ static void TRANSFORM_OT_skin_resize(struct wmOperatorType *ot) static void TRANSFORM_OT_trackball(struct wmOperatorType *ot) { - PropertyRNA *prop; - /* identifiers */ ot->name = "Trackball"; ot->description = "Trackball style rotation of selected items"; @@ -660,16 +658,13 @@ static void TRANSFORM_OT_trackball(struct wmOperatorType *ot) ot->poll = ED_operator_screenactive; /* Maybe we could use float_vector_xyz here too? */ - prop = RNA_def_float_vector(ot->srna, "value", 2, NULL, -FLT_MAX, FLT_MAX, "Angle", "", -FLT_MAX, FLT_MAX); - RNA_def_property_subtype(prop, PROP_ANGLE); + RNA_def_float_rotation(ot->srna, "value", 2, NULL, -FLT_MAX, FLT_MAX, "Angle", "", -FLT_MAX, FLT_MAX); Transform_Properties(ot, P_PROPORTIONAL | P_MIRROR | P_SNAP | P_GPENCIL_EDIT); } static void TRANSFORM_OT_rotate(struct wmOperatorType *ot) { - PropertyRNA *prop; - /* identifiers */ ot->name = "Rotate"; ot->description = "Rotate selected items"; @@ -683,8 +678,7 @@ static void TRANSFORM_OT_rotate(struct wmOperatorType *ot) ot->cancel = transform_cancel; ot->poll = ED_operator_screenactive; - prop = RNA_def_float(ot->srna, "value", 0.0f, -FLT_MAX, FLT_MAX, "Angle", "", -M_PI * 2, M_PI * 2); - RNA_def_property_subtype(prop, PROP_ANGLE); + RNA_def_float_rotation(ot->srna, "value", 0, NULL, -FLT_MAX, FLT_MAX, "Angle", "", -M_PI * 2, M_PI * 2); Transform_Properties(ot, P_AXIS | P_CONSTRAINT | P_PROPORTIONAL | P_MIRROR | P_GEO_SNAP | P_GPENCIL_EDIT); } @@ -858,6 +852,12 @@ static void TRANSFORM_OT_edge_slide(struct wmOperatorType *ot) prop = RNA_def_boolean(ot->srna, "single_side", false, "Single Side", ""); RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE); + RNA_def_boolean(ot->srna, "use_even", false, "Even", + "Make the edge loop match the shape of the adjacent edge loop"); + RNA_def_boolean(ot->srna, "flipped", false, "Flipped", + "When Even mode is active, flips between the two adjacent edge loops"); + RNA_def_boolean(ot->srna, "use_clamp", true, "Clamp", + "Clamp within the edge extents"); Transform_Properties(ot, P_MIRROR | P_SNAP | P_CORRECT_UV); } @@ -878,6 +878,12 @@ static void TRANSFORM_OT_vert_slide(struct wmOperatorType *ot) ot->poll = ED_operator_editmesh_region_view3d; RNA_def_float_factor(ot->srna, "value", 0, -10.0f, 10.0f, "Factor", "", -1.0f, 1.0f); + RNA_def_boolean(ot->srna, "use_even", false, "Even", + "Make the edge loop match the shape of the adjacent edge loop"); + RNA_def_boolean(ot->srna, "flipped", false, "Flipped", + "When Even mode is active, flips between the two adjacent edge loops"); + RNA_def_boolean(ot->srna, "use_clamp", true, "Clamp", + "Clamp within the edge extents"); Transform_Properties(ot, P_MIRROR | P_SNAP | P_CORRECT_UV); } diff --git a/source/blender/editors/transform/transform_orientations.c b/source/blender/editors/transform/transform_orientations.c index cea19e928bc..d6fbc46715e 100644 --- a/source/blender/editors/transform/transform_orientations.c +++ b/source/blender/editors/transform/transform_orientations.c @@ -36,6 +36,7 @@ #include "DNA_object_types.h" #include "DNA_scene_types.h" #include "DNA_screen_types.h" +#include "DNA_space_types.h" #include "DNA_view3d_types.h" #include "BLI_math.h" @@ -144,7 +145,7 @@ static TransformOrientation *createBoneSpace(bContext *C, ReportList *reports, float mat[3][3]; float normal[3], plane[3]; - getTransformOrientation(C, normal, plane, 0); + getTransformOrientation(C, normal, plane); if (createSpaceNormalTangent(mat, normal, plane) == 0) { BKE_reports_prepend(reports, "Cannot use zero-length bone"); @@ -164,7 +165,7 @@ static TransformOrientation *createCurveSpace(bContext *C, ReportList *reports, float mat[3][3]; float normal[3], plane[3]; - getTransformOrientation(C, normal, plane, 0); + getTransformOrientation(C, normal, plane); if (createSpaceNormalTangent(mat, normal, plane) == 0) { BKE_reports_prepend(reports, "Cannot use zero-length curve"); @@ -186,7 +187,7 @@ static TransformOrientation *createMeshSpace(bContext *C, ReportList *reports, float normal[3], plane[3]; int type; - type = getTransformOrientation(C, normal, plane, 0); + type = getTransformOrientation(C, normal, plane); switch (type) { case ORIENTATION_VERT: @@ -390,15 +391,12 @@ int BIF_countTransformOrientation(const bContext *C) return BLI_listbase_count(transform_spaces); } -bool applyTransformOrientation(const bContext *C, float mat[3][3], char *r_name) +bool applyTransformOrientation(const bContext *C, float mat[3][3], char *r_name, int index) { - View3D *v3d = CTX_wm_view3d(C); - int selected_index = (v3d->twmode - V3D_MANIP_CUSTOM); - ListBase *transform_spaces = &CTX_data_scene(C)->transform_spaces; - TransformOrientation *ts = BLI_findlink(transform_spaces, selected_index); + TransformOrientation *ts = BLI_findlink(transform_spaces, index); - BLI_assert(selected_index >= 0); + BLI_assert(index >= 0); if (ts) { if (r_name) { @@ -442,7 +440,6 @@ static int count_bone_select(bArmature *arm, ListBase *lb, const bool do_it) void initTransformOrientation(bContext *C, TransInfo *t) { - View3D *v3d = CTX_wm_view3d(C); Object *ob = CTX_data_active_object(C); Object *obedit = CTX_data_active_object(C); @@ -462,7 +459,7 @@ void initTransformOrientation(bContext *C, TransInfo *t) case V3D_MANIP_NORMAL: if (obedit || (ob && ob->mode & OB_MODE_POSE)) { BLI_strncpy(t->spacename, IFACE_("normal"), sizeof(t->spacename)); - ED_getTransformOrientationMatrix(C, t->spacemtx, (v3d->around == V3D_ACTIVE)); + ED_getTransformOrientationMatrix(C, t->spacemtx, t->around); break; } /* fall-through */ /* we define 'normal' as 'local' in Object mode */ @@ -480,7 +477,9 @@ void initTransformOrientation(bContext *C, TransInfo *t) break; case V3D_MANIP_VIEW: - if (t->ar->regiontype == RGN_TYPE_WINDOW) { + if ((t->spacetype == SPACE_VIEW3D) && + (t->ar->regiontype == RGN_TYPE_WINDOW)) + { RegionView3D *rv3d = t->ar->regiondata; float mat[3][3]; @@ -494,7 +493,7 @@ void initTransformOrientation(bContext *C, TransInfo *t) } break; default: /* V3D_MANIP_CUSTOM */ - if (applyTransformOrientation(C, t->spacemtx, t->spacename)) { + if (applyTransformOrientation(C, t->spacemtx, t->spacename, t->current_orientation - V3D_MANIP_CUSTOM)) { /* pass */ } else { @@ -585,14 +584,14 @@ static unsigned int bm_mesh_faces_select_get_n(BMesh *bm, BMVert **elems, const } #endif -int getTransformOrientation(const bContext *C, float normal[3], float plane[3], const bool activeOnly) +int getTransformOrientation_ex(const bContext *C, float normal[3], float plane[3], const short around) { Scene *scene = CTX_data_scene(C); - View3D *v3d = CTX_wm_view3d(C); Object *obedit = CTX_data_edit_object(C); Base *base; Object *ob = OBACT; int result = ORIENTATION_NONE; + const bool activeOnly = (around == V3D_ACTIVE); zero_v3(normal); zero_v3(plane); @@ -855,7 +854,7 @@ int getTransformOrientation(const bContext *C, float normal[3], float plane[3], /* exception */ if (flag) { float tvec[3]; - if ((v3d->around == V3D_LOCAL) || + if ((around == V3D_LOCAL) || ELEM(flag, SEL_F2, SEL_F1 | SEL_F3, SEL_F1 | SEL_F2 | SEL_F3)) { BKE_nurb_bezt_calc_normal(nu, bezt, tvec); @@ -1017,6 +1016,7 @@ int getTransformOrientation(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)) { /* pass */ @@ -1042,14 +1042,22 @@ int getTransformOrientation(const bContext *C, float normal[3], float plane[3], return result; } -void ED_getTransformOrientationMatrix(const bContext *C, float orientation_mat[3][3], const bool activeOnly) +int getTransformOrientation(const bContext *C, float normal[3], float plane[3]) +{ + /* dummy value, not V3D_ACTIVE and not V3D_LOCAL */ + short around = V3D_CENTER; + + return getTransformOrientation_ex(C, normal, plane, around); +} + +void ED_getTransformOrientationMatrix(const bContext *C, float orientation_mat[3][3], const short around) { float normal[3] = {0.0, 0.0, 0.0}; float plane[3] = {0.0, 0.0, 0.0}; int type; - type = getTransformOrientation(C, normal, plane, activeOnly); + type = getTransformOrientation_ex(C, normal, plane, around); switch (type) { case ORIENTATION_NORMAL: diff --git a/source/blender/editors/transform/transform_snap.c b/source/blender/editors/transform/transform_snap.c index dfa5032d303..0e954d40c18 100644 --- a/source/blender/editors/transform/transform_snap.c +++ b/source/blender/editors/transform/transform_snap.c @@ -85,6 +85,8 @@ #define TRANSFORM_DIST_MAX_PX 1000.0f #define TRANSFORM_SNAP_MAX_PX 100.0f +#define TRANSFORM_DIST_INVALID NAN_FLT + /* use half of flt-max so we can scale up without an exception */ /********************* PROTOTYPES ***********************/ @@ -220,7 +222,7 @@ void drawSnapping(const struct bContext *C, TransInfo *t) h = (((float)hi) / IMG_SIZE_FALLBACK) * G.sima->zoom * yuser_asp; cpack(0xFFFFFF); - glTranslatef(t->tsnap.snapPoint[0], t->tsnap.snapPoint[1], 0.0f); + glTranslate2fv(t->tsnap.snapPoint); //glRectf(0, 0, 1, 1); @@ -897,7 +899,10 @@ static float ResizeBetween(TransInfo *t, const float p1[3], const float p2[3]) len_d1 = len_v3(d1); - return len_d1 != 0.0f ? len_v3(d2) / len_d1 : 1; + /* Use 'invalid' dist when `center == p1` (after projecting), + * in this case scale will _never_ move the point in relation to the center, + * so it makes no sense to take it into account when scaling. see: T46503 */ + return len_d1 != 0.0f ? len_v3(d2) / len_d1 : TRANSFORM_DIST_INVALID; } /********************** CALC **************************/ @@ -981,7 +986,7 @@ static void CalcSnapGeometry(TransInfo *t, float *UNUSED(vec)) break; } - new_dist = len_v3v3(last_p, vec); + new_dist = len_squared_v3v3(last_p, vec); if (new_dist < max_dist) { copy_v3_v3(p, vec); @@ -1002,6 +1007,7 @@ static void CalcSnapGeometry(TransInfo *t, float *UNUSED(vec)) BLI_freelistN(&depth_peels); } else { + zero_v3(no); /* objects won't set this */ found = snapObjectsTransform(t, mval, &dist_px, loc, no, t->tsnap.modeSelect); } @@ -1176,8 +1182,10 @@ static void TargetSnapClosest(TransInfo *t) mul_m4_v3(td->ext->obmat, loc); dist = t->tsnap.distance(t, loc, t->tsnap.snapPoint); - - if (closest == NULL || fabsf(dist) < fabsf(t->tsnap.dist)) { + + if ((dist != TRANSFORM_DIST_INVALID) && + (closest == NULL || fabsf(dist) < fabsf(t->tsnap.dist))) + { copy_v3_v3(t->tsnap.snapTarget, loc); closest = td; t->tsnap.dist = dist; @@ -1192,8 +1200,10 @@ static void TargetSnapClosest(TransInfo *t) copy_v3_v3(loc, td->center); dist = t->tsnap.distance(t, loc, t->tsnap.snapPoint); - - if (closest == NULL || fabsf(dist) < fabsf(t->tsnap.dist)) { + + if ((dist != TRANSFORM_DIST_INVALID) && + (closest == NULL || fabsf(dist) < fabsf(t->tsnap.dist))) + { copy_v3_v3(t->tsnap.snapTarget, loc); closest = td; t->tsnap.dist = dist; @@ -1216,7 +1226,9 @@ static void TargetSnapClosest(TransInfo *t) dist = t->tsnap.distance(t, loc, t->tsnap.snapPoint); - if (closest == NULL || fabsf(dist) < fabsf(t->tsnap.dist)) { + if ((dist != TRANSFORM_DIST_INVALID) && + (closest == NULL || fabsf(dist) < fabsf(t->tsnap.dist))) + { copy_v3_v3(t->tsnap.snapTarget, loc); closest = td; t->tsnap.dist = dist; @@ -1526,8 +1538,17 @@ static bool snapDerivedMesh(short snap_mode, ARegion *ar, Object *ob, DerivedMes if (do_bb) { BoundBox *bb = BKE_object_boundbox_get(ob); - if (!BKE_boundbox_ray_hit_check(bb, ray_start_local, ray_normal_local, &len_diff)) { - return retval; + + if (bb) { + BoundBox bb_temp; + + /* We cannot aford a bbox with some null dimension, which may happen in some cases... + * Threshold is rather high, but seems to be needed to get good behavior, see T46099. */ + bb = BKE_boundbox_ensure_minimum_dimensions(bb, &bb_temp, 1e-1f); + + if (!BKE_boundbox_ray_hit_check(bb, ray_start_local, ray_normal_local, &len_diff)) { + return retval; + } } } else if (do_ray_start_correction) { @@ -1539,6 +1560,7 @@ static bool snapDerivedMesh(short snap_mode, ARegion *ar, Object *ob, DerivedMes len_diff = 0.0f; /* In case BVHTree would fail for some reason... */ treeData.em_evil = em; + treeData.em_evil_all = false; bvhtree_from_mesh_looptri(&treeData, dm, 0.0f, 2, 6); if (treeData.tree != NULL) { nearest.index = -1; @@ -1581,6 +1603,7 @@ static bool snapDerivedMesh(short snap_mode, ARegion *ar, Object *ob, DerivedMes } treeData.em_evil = em; + treeData.em_evil_all = false; bvhtree_from_mesh_looptri(&treeData, dm, 0.0f, 4, 6); hit.index = -1; @@ -1853,8 +1876,16 @@ static bool snapObject(Scene *scene, short snap_mode, ARegion *ar, Object *ob, f do_bb = false; } else { + /* in this case we want the mesh from the editmesh, avoids stale data. see: T45978. + * still set the 'em' to NULL, since we only want the 'dm'. */ + em = BKE_editmesh_from_object(ob); + if (em) { + editbmesh_get_derived_cage_and_final(scene, ob, em, CD_MASK_BAREMESH, &dm); + } + else { + dm = mesh_get_derived_final(scene, ob, CD_MASK_BAREMESH); + } em = NULL; - dm = mesh_get_derived_final(scene, ob, CD_MASK_BAREMESH); } retval = snapDerivedMesh(snap_mode, ar, ob, dm, em, obmat, ray_start, ray_normal, ray_origin, mval, r_loc, r_no, r_dist_px, r_depth, do_bb); @@ -1974,8 +2005,20 @@ static bool snapObjects(Scene *scene, short snap_mode, Base *base_act, View3D *v bool snapObjectsTransform(TransInfo *t, const float mval[2], float *r_dist_px, float r_loc[3], float r_no[3], SnapMode mode) { float ray_dist = TRANSFORM_DIST_MAX_RAY; - return snapObjects(t->scene, t->scene->toolsettings->snap_mode, t->scene->basact, t->view, t->ar, t->obedit, - mval, r_dist_px, r_loc, r_no, &ray_dist, mode); + Object *obedit = NULL; + Base *base_act = NULL; + + if (t->flag & T_EDIT) { + obedit = t->obedit; + } + + if ((t->options & CTX_GPENCIL_STROKES) == 0) { + base_act = t->scene->basact; + } + + return snapObjects( + t->scene, t->scene->toolsettings->snap_mode, base_act, t->view, t->ar, obedit, + mval, r_dist_px, r_loc, r_no, &ray_dist, mode); } bool snapObjectsContext(bContext *C, const float mval[2], float *r_dist_px, float r_loc[3], float r_no[3], SnapMode mode) @@ -2130,20 +2173,30 @@ static bool peelDerivedMesh( * test against boundbox first * */ if (looptri_num > 16) { - struct BoundBox *bb = BKE_object_boundbox_get(ob); - test = BKE_boundbox_ray_hit_check(bb, ray_start_local, ray_normal_local, NULL); + BoundBox *bb = BKE_object_boundbox_get(ob); + + if (bb) { + BoundBox bb_temp; + + /* We cannot aford a bbox with some null dimension, which may happen in some cases... + * Threshold is rather high, but seems to be needed to get good behavior, see T46099. */ + bb = BKE_boundbox_ensure_minimum_dimensions(bb, &bb_temp, 1e-1f); + + test = BKE_boundbox_ray_hit_check(bb, ray_start_local, ray_normal_local, NULL); + } } if (test == true) { struct PeelRayCast_Data data; data.bvhdata.em_evil = em; + data.bvhdata.em_evil_all = false; bvhtree_from_mesh_looptri(&data.bvhdata, dm, 0.0f, 4, 6); if (data.bvhdata.tree != NULL) { data.ob = ob; - data.obmat = obmat; - data.timat = timat; + data.obmat = (const float (*)[4])obmat; + data.timat = (const float (*)[3])timat; data.ray_start = ray_start; data.looptri = looptri; data.polynors = dm->getPolyDataArray(dm, CD_NORMAL); /* can be NULL */ diff --git a/source/blender/editors/util/ed_util.c b/source/blender/editors/util/ed_util.c index 802c4e796dd..f727f48e993 100644 --- a/source/blender/editors/util/ed_util.c +++ b/source/blender/editors/util/ed_util.c @@ -111,7 +111,7 @@ void ED_editors_init(bContext *C) /* image editor paint mode */ if (sce) { - ED_space_image_paint_update(wm, sce->toolsettings); + ED_space_image_paint_update(wm, sce); } SWAP(int, reports->flag, reports_flag_prev); diff --git a/source/blender/editors/uvedit/uvedit_draw.c b/source/blender/editors/uvedit/uvedit_draw.c index 9431d754b5f..f4eed3e1fda 100644 --- a/source/blender/editors/uvedit/uvedit_draw.c +++ b/source/blender/editors/uvedit/uvedit_draw.c @@ -81,7 +81,7 @@ void ED_image_draw_cursor(ARegion *ar, const float cursor[2]) y_fac = zoom[1]; cpack(0xFFFFFF); - glTranslatef(cursor[0], cursor[1], 0.0); + 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); @@ -187,8 +187,8 @@ static void draw_uvs_stretch(SpaceImage *sima, Scene *scene, BMEditMesh *em, MTe BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) { const int efa_len = efa->len; - float (*tf_uv)[2] = (float (*)[2])BLI_buffer_resize_data(&tf_uv_buf, vec2f, efa_len); - float (*tf_uvorig)[2] = (float (*)[2])BLI_buffer_resize_data(&tf_uvorig_buf, vec2f, efa_len); + float (*tf_uv)[2] = (float (*)[2])BLI_buffer_reinit_data(&tf_uv_buf, vec2f, efa_len); + float (*tf_uvorig)[2] = (float (*)[2])BLI_buffer_reinit_data(&tf_uvorig_buf, vec2f, efa_len); tf = BM_ELEM_CD_GET_VOID_P(efa, cd_poly_tex_offset); BM_ITER_ELEM_INDEX (l, &liter, efa, BM_LOOPS_OF_FACE, i) { @@ -230,8 +230,8 @@ static void draw_uvs_stretch(SpaceImage *sima, Scene *scene, BMEditMesh *em, MTe BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) { if (BM_elem_flag_test(efa, BM_ELEM_TAG)) { const int efa_len = efa->len; - float (*tf_uv)[2] = (float (*)[2])BLI_buffer_resize_data(&tf_uv_buf, vec2f, efa_len); - float (*tf_uvorig)[2] = (float (*)[2])BLI_buffer_resize_data(&tf_uvorig_buf, vec2f, efa_len); + float (*tf_uv)[2] = (float (*)[2])BLI_buffer_reinit_data(&tf_uv_buf, vec2f, efa_len); + float (*tf_uvorig)[2] = (float (*)[2])BLI_buffer_reinit_data(&tf_uvorig_buf, vec2f, efa_len); area = BM_face_calc_area(efa) / totarea; @@ -284,12 +284,12 @@ static void draw_uvs_stretch(SpaceImage *sima, Scene *scene, BMEditMesh *em, MTe if (uvedit_face_visible_test(scene, ima, efa, tf)) { const int efa_len = efa->len; - float (*tf_uv)[2] = (float (*)[2])BLI_buffer_resize_data(&tf_uv_buf, vec2f, efa_len); - float (*tf_uvorig)[2] = (float (*)[2])BLI_buffer_resize_data(&tf_uvorig_buf, vec2f, efa_len); - float *uvang = BLI_buffer_resize_data(&uvang_buf, float, efa_len); - float *ang = BLI_buffer_resize_data(&ang_buf, float, efa_len); - float (*av)[3] = (float (*)[3])BLI_buffer_resize_data(&av_buf, vec3f, efa_len); - float (*auv)[2] = (float (*)[2])BLI_buffer_resize_data(&auv_buf, vec2f, efa_len); + float (*tf_uv)[2] = (float (*)[2])BLI_buffer_reinit_data(&tf_uv_buf, vec2f, efa_len); + float (*tf_uvorig)[2] = (float (*)[2])BLI_buffer_reinit_data(&tf_uvorig_buf, vec2f, efa_len); + float *uvang = BLI_buffer_reinit_data(&uvang_buf, float, efa_len); + float *ang = BLI_buffer_reinit_data(&ang_buf, float, efa_len); + float (*av)[3] = (float (*)[3])BLI_buffer_reinit_data(&av_buf, vec3f, efa_len); + float (*auv)[2] = (float (*)[2])BLI_buffer_reinit_data(&auv_buf, vec2f, efa_len); int j; BM_elem_flag_enable(efa, BM_ELEM_TAG); diff --git a/source/blender/editors/uvedit/uvedit_ops.c b/source/blender/editors/uvedit/uvedit_ops.c index 71d557f6fc7..728e3662ce6 100644 --- a/source/blender/editors/uvedit/uvedit_ops.c +++ b/source/blender/editors/uvedit/uvedit_ops.c @@ -4119,7 +4119,13 @@ static int uv_seams_from_islands_exec(bContext *C, wmOperator *op) } } - me->drawflag |= ME_DRAWSEAMS; + if (mark_seams) { + me->drawflag |= ME_DRAWSEAMS; + } + if (mark_sharp) { + me->drawflag |= ME_DRAWSHARP; + } + BM_uv_vert_map_free(vmap); diff --git a/source/blender/editors/uvedit/uvedit_unwrap_ops.c b/source/blender/editors/uvedit/uvedit_unwrap_ops.c index f915a4b2e51..3ff3e29f79d 100644 --- a/source/blender/editors/uvedit/uvedit_unwrap_ops.c +++ b/source/blender/editors/uvedit/uvedit_unwrap_ops.c @@ -344,7 +344,8 @@ static ParamHandle *construct_param_handle_subsurfed(Scene *scene, Object *ob, B { ParamHandle *handle; /* index pointers */ - MFace *face; + MPoly *mpoly; + MLoop *mloop; MEdge *edge; int i; @@ -356,11 +357,12 @@ static ParamHandle *construct_param_handle_subsurfed(Scene *scene, Object *ob, B /* Used to hold subsurfed Mesh */ DerivedMesh *derivedMesh, *initialDerived; /* holds original indices for subsurfed mesh */ - const int *origVertIndices, *origEdgeIndices, *origFaceIndices, *origPolyIndices; + const int *origVertIndices, *origEdgeIndices, *origPolyIndices; /* Holds vertices of subsurfed mesh */ MVert *subsurfedVerts; MEdge *subsurfedEdges; - MFace *subsurfedFaces; + MPoly *subsurfedPolys; + MLoop *subsurfedLoops; /* number of vertices and faces for subsurfed mesh*/ int numOfEdges, numOfFaces; @@ -398,15 +400,15 @@ static ParamHandle *construct_param_handle_subsurfed(Scene *scene, Object *ob, B /* get the derived data */ subsurfedVerts = derivedMesh->getVertArray(derivedMesh); subsurfedEdges = derivedMesh->getEdgeArray(derivedMesh); - subsurfedFaces = derivedMesh->getTessFaceArray(derivedMesh); + subsurfedPolys = derivedMesh->getPolyArray(derivedMesh); + subsurfedLoops = derivedMesh->getLoopArray(derivedMesh); origVertIndices = derivedMesh->getVertDataArray(derivedMesh, CD_ORIGINDEX); origEdgeIndices = derivedMesh->getEdgeDataArray(derivedMesh, CD_ORIGINDEX); - origFaceIndices = derivedMesh->getTessFaceDataArray(derivedMesh, CD_ORIGINDEX); origPolyIndices = derivedMesh->getPolyDataArray(derivedMesh, CD_ORIGINDEX); numOfEdges = derivedMesh->getNumEdges(derivedMesh); - numOfFaces = derivedMesh->getNumTessFaces(derivedMesh); + numOfFaces = derivedMesh->getNumPolys(derivedMesh); faceMap = MEM_mallocN(numOfFaces * sizeof(BMFace *), "unwrap_edit_face_map"); @@ -415,7 +417,7 @@ static ParamHandle *construct_param_handle_subsurfed(Scene *scene, Object *ob, B /* map subsurfed faces to original editFaces */ for (i = 0; i < numOfFaces; i++) - faceMap[i] = BM_face_at_index(em->bm, DM_origindex_mface_mpoly(origFaceIndices, origPolyIndices, i)); + faceMap[i] = BM_face_at_index(em->bm, origPolyIndices[i]); edgeMap = MEM_mallocN(numOfEdges * sizeof(BMEdge *), "unwrap_edit_edge_map"); @@ -427,15 +429,13 @@ static ParamHandle *construct_param_handle_subsurfed(Scene *scene, Object *ob, B } /* Prepare and feed faces to the solver */ - for (i = 0; i < numOfFaces; i++) { + for (i = 0, mpoly = subsurfedPolys; i < numOfFaces; i++, mpoly++) { ParamKey key, vkeys[4]; ParamBool pin[4], select[4]; float *co[4]; float *uv[4]; BMFace *origFace = faceMap[i]; - face = subsurfedFaces + i; - if (scene->toolsettings->uv_flag & UV_SYNC_SELECTION) { if (BM_elem_flag_test(origFace, BM_ELEM_HIDDEN)) continue; @@ -445,24 +445,27 @@ static ParamHandle *construct_param_handle_subsurfed(Scene *scene, Object *ob, B continue; } + mloop = &subsurfedLoops[mpoly->loopstart]; + /* We will not check for v4 here. Subsurfed mfaces always have 4 vertices. */ - key = (ParamKey)face; - vkeys[0] = (ParamKey)face->v1; - vkeys[1] = (ParamKey)face->v2; - vkeys[2] = (ParamKey)face->v3; - vkeys[3] = (ParamKey)face->v4; - - co[0] = subsurfedVerts[face->v1].co; - co[1] = subsurfedVerts[face->v2].co; - co[2] = subsurfedVerts[face->v3].co; - co[3] = subsurfedVerts[face->v4].co; + BLI_assert(mpoly->totloop == 4); + key = (ParamKey)mpoly; + vkeys[0] = (ParamKey)mloop[0].v; + vkeys[1] = (ParamKey)mloop[1].v; + vkeys[2] = (ParamKey)mloop[2].v; + vkeys[3] = (ParamKey)mloop[3].v; + + co[0] = subsurfedVerts[mloop[0].v].co; + co[1] = subsurfedVerts[mloop[1].v].co; + co[2] = subsurfedVerts[mloop[2].v].co; + co[3] = subsurfedVerts[mloop[3].v].co; /* This is where all the magic is done. If the vertex exists in the, we pass the original uv pointer to the solver, thus * flushing the solution to the edit mesh. */ - texface_from_original_index(origFace, origVertIndices[face->v1], &uv[0], &pin[0], &select[0], scene, cd_loop_uv_offset); - texface_from_original_index(origFace, origVertIndices[face->v2], &uv[1], &pin[1], &select[1], scene, cd_loop_uv_offset); - texface_from_original_index(origFace, origVertIndices[face->v3], &uv[2], &pin[2], &select[2], scene, cd_loop_uv_offset); - texface_from_original_index(origFace, origVertIndices[face->v4], &uv[3], &pin[3], &select[3], scene, cd_loop_uv_offset); + texface_from_original_index(origFace, origVertIndices[mloop[0].v], &uv[0], &pin[0], &select[0], scene, cd_loop_uv_offset); + texface_from_original_index(origFace, origVertIndices[mloop[1].v], &uv[1], &pin[1], &select[1], scene, cd_loop_uv_offset); + texface_from_original_index(origFace, origVertIndices[mloop[2].v], &uv[2], &pin[2], &select[2], scene, cd_loop_uv_offset); + texface_from_original_index(origFace, origVertIndices[mloop[3].v], &uv[3], &pin[3], &select[3], scene, cd_loop_uv_offset); param_face_add(handle, key, 4, vkeys, co, uv, pin, select, NULL); } diff --git a/source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.cpp b/source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.cpp index 64ef49d74a3..7c10591591c 100644 --- a/source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.cpp +++ b/source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.cpp @@ -55,6 +55,8 @@ extern "C" { #include "BLI_ghash.h" #include "BLI_listbase.h" +#include "BLI_math_color.h" +#include "BLI_math_vector.h" #include "BLI_utildefines.h" #include "RE_pipeline.h" @@ -113,7 +115,6 @@ BlenderStrokeRenderer::BlenderStrokeRenderer(Render *re, int render_count) : Str BLI_strncpy(freestyle_scene->r.engine, old_scene->r.engine, sizeof(freestyle_scene->r.engine)); freestyle_scene->r.im_format.planes = R_IMF_PLANES_RGBA; freestyle_scene->r.im_format.imtype = R_IMF_IMTYPE_PNG; - BKE_scene_disable_color_management(freestyle_scene); if (G.debug & G_DEBUG_FREESTYLE) { printf("%s: %d thread(s)\n", __func__, BKE_render_num_threads(&freestyle_scene->r)); @@ -871,38 +872,24 @@ void BlenderStrokeRenderer::GenerateStrokeMesh(StrokeGroup *group, bool hasTex) } } - // colors and alpha transparency + // colors and alpha transparency. vertex colors are in sRGB + // space by convention, so convert from linear + float rgba[3][4]; + + for (int i = 0; i < 3; i++) { + copy_v3fl_v3db(rgba[i], &svRep[i]->color()[0]); + rgba[i][3] = svRep[i]->alpha(); + } + if (is_odd) { - colors[0].r = (short)(255.0f * svRep[2]->color()[0]); - colors[0].g = (short)(255.0f * svRep[2]->color()[1]); - colors[0].b = (short)(255.0f * svRep[2]->color()[2]); - colors[0].a = (short)(255.0f * svRep[2]->alpha()); - - colors[1].r = (short)(255.0f * svRep[0]->color()[0]); - colors[1].g = (short)(255.0f * svRep[0]->color()[1]); - colors[1].b = (short)(255.0f * svRep[0]->color()[2]); - colors[1].a = (short)(255.0f * svRep[0]->alpha()); - - colors[2].r = (short)(255.0f * svRep[1]->color()[0]); - colors[2].g = (short)(255.0f * svRep[1]->color()[1]); - colors[2].b = (short)(255.0f * svRep[1]->color()[2]); - colors[2].a = (short)(255.0f * svRep[1]->alpha()); + linearrgb_to_srgb_uchar4(&colors[0].r, rgba[2]); + linearrgb_to_srgb_uchar4(&colors[1].r, rgba[0]); + linearrgb_to_srgb_uchar4(&colors[2].r, rgba[1]); } else { - colors[0].r = (short)(255.0f * svRep[2]->color()[0]); - colors[0].g = (short)(255.0f * svRep[2]->color()[1]); - colors[0].b = (short)(255.0f * svRep[2]->color()[2]); - colors[0].a = (short)(255.0f * svRep[2]->alpha()); - - colors[1].r = (short)(255.0f * svRep[1]->color()[0]); - colors[1].g = (short)(255.0f * svRep[1]->color()[1]); - colors[1].b = (short)(255.0f * svRep[1]->color()[2]); - colors[1].a = (short)(255.0f * svRep[1]->alpha()); - - colors[2].r = (short)(255.0f * svRep[0]->color()[0]); - colors[2].g = (short)(255.0f * svRep[0]->color()[1]); - colors[2].b = (short)(255.0f * svRep[0]->color()[2]); - colors[2].a = (short)(255.0f * svRep[0]->alpha()); + linearrgb_to_srgb_uchar4(&colors[0].r, rgba[2]); + linearrgb_to_srgb_uchar4(&colors[1].r, rgba[1]); + linearrgb_to_srgb_uchar4(&colors[2].r, rgba[0]); } transp[0].r = transp[0].g = transp[0].b = colors[0].a; transp[1].r = transp[1].g = transp[1].b = colors[1].a; diff --git a/source/blender/freestyle/intern/geometry/GeomUtils.h b/source/blender/freestyle/intern/geometry/GeomUtils.h index 64aa6379e80..5a5d0809083 100644 --- a/source/blender/freestyle/intern/geometry/GeomUtils.h +++ b/source/blender/freestyle/intern/geometry/GeomUtils.h @@ -200,7 +200,7 @@ void fromWorldToCamera(const Vec3r& p, Vec3r& q, const real model_view_matrix[4] void fromCameraToRetina(const Vec3r& p, Vec3r& q, const real projection_matrix[4][4]); /*! From retina to image. - * Returns the coordinates expressed in Image coorinates system. + * Returns the coordinates expressed in Image coordinates system. * p * point's coordinates expressed in retina system * q diff --git a/source/blender/freestyle/intern/geometry/Noise.cpp b/source/blender/freestyle/intern/geometry/Noise.cpp index 8ec56e84f95..dd5f2f6ea4c 100644 --- a/source/blender/freestyle/intern/geometry/Noise.cpp +++ b/source/blender/freestyle/intern/geometry/Noise.cpp @@ -147,7 +147,7 @@ float Noise::smoothNoise2(Vec2f& vec) { int bx0, bx1, by0, by1, b00, b10, b01, b11; float rx0, rx1, ry0, ry1, *q, sx, sy, a, b, t, u, v; - register int i, j; + int i, j; SETUP(vec.x(), bx0, bx1, rx0, rx1); SETUP(vec.y(), by0, by1, ry0, ry1); @@ -186,7 +186,7 @@ float Noise::smoothNoise3(Vec3f& vec) { int bx0, bx1, by0, by1, bz0, bz1, b00, b10, b01, b11; float rx0, rx1, ry0, ry1, rz0, rz1, *q, sy, sz, a, b, c, d, t, u, v; - register int i, j; + int i, j; SETUP(vec.x(), bx0, bx1, rx0, rx1); SETUP(vec.y(), by0, by1, ry0, ry1); diff --git a/source/blender/freestyle/intern/python/Interface0D/BPy_CurvePoint.cpp b/source/blender/freestyle/intern/python/Interface0D/BPy_CurvePoint.cpp index 9f0660baa9b..446587c2388 100644 --- a/source/blender/freestyle/intern/python/Interface0D/BPy_CurvePoint.cpp +++ b/source/blender/freestyle/intern/python/Interface0D/BPy_CurvePoint.cpp @@ -220,8 +220,8 @@ static PyGetSetDef BPy_CurvePoint_getseters[] = { (char *)CurvePoint_first_svertex_doc, NULL}, {(char *)"second_svertex", (getter)CurvePoint_second_svertex_get, (setter)CurvePoint_second_svertex_set, (char *)CurvePoint_second_svertex_doc, NULL}, - {(char *)"fedge", (getter)CurvePoint_fedge_get, NULL, - CurvePoint_fedge_doc, NULL}, + {(char *)"fedge", (getter)CurvePoint_fedge_get, NULL, + CurvePoint_fedge_doc, NULL}, {(char *)"t2d", (getter)CurvePoint_t2d_get, (setter)CurvePoint_t2d_set, (char *)CurvePoint_t2d_doc, NULL}, {NULL, NULL, NULL, NULL, NULL} /* Sentinel */ }; diff --git a/source/blender/freestyle/intern/stroke/Stroke.cpp b/source/blender/freestyle/intern/stroke/Stroke.cpp index b4a3646edef..053015f459d 100644 --- a/source/blender/freestyle/intern/stroke/Stroke.cpp +++ b/source/blender/freestyle/intern/stroke/Stroke.cpp @@ -419,12 +419,7 @@ Stroke::Stroke(const Stroke& iBrother) _textureId = iBrother._textureId; _textureStep = iBrother._textureStep; for (int a = 0; a < MAX_MTEX; a++) { - if (iBrother._mtex) { - _mtex[a] = iBrother._mtex[a]; - } - else { - _mtex[a] = NULL; - } + _mtex[a] = iBrother._mtex[a]; } _nodeTree = iBrother._nodeTree; _tips = iBrother._tips; diff --git a/source/blender/freestyle/intern/winged_edge/WEdge.h b/source/blender/freestyle/intern/winged_edge/WEdge.h index f610f6965aa..8001342775b 100644 --- a/source/blender/freestyle/intern/winged_edge/WEdge.h +++ b/source/blender/freestyle/intern/winged_edge/WEdge.h @@ -989,7 +989,7 @@ public: } /*! For triangles, returns the edge opposite to the vertex in e. - * returns flase if the face is not a triangle or if the vertex is not found + * returns false if the face is not a triangle or if the vertex is not found */ bool getOppositeEdge (const WVertex *v, WOEdge *&e); diff --git a/source/blender/gpu/GPU_extensions.h b/source/blender/gpu/GPU_extensions.h index f3927ba960b..685ae59c47b 100644 --- a/source/blender/gpu/GPU_extensions.h +++ b/source/blender/gpu/GPU_extensions.h @@ -130,6 +130,8 @@ 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, bool is_data, double time, int mipmap); GPUTexture *GPU_texture_from_preview(struct PreviewImage *prv, int mipmap); @@ -179,13 +181,14 @@ void GPU_framebuffer_blur(GPUFrameBuffer *fb, GPUTexture *tex, GPUFrameBuffer *b * - wrapper around framebuffer and texture for simple offscreen drawing * - changes size if graphics card can't support it */ -GPUOffScreen *GPU_offscreen_create(int width, int height, char err_out[256]); +GPUOffScreen *GPU_offscreen_create(int width, int height, int samples, char err_out[256]); void GPU_offscreen_free(GPUOffScreen *ofs); void GPU_offscreen_bind(GPUOffScreen *ofs, bool save); void GPU_offscreen_unbind(GPUOffScreen *ofs, bool restore); void GPU_offscreen_read_pixels(GPUOffScreen *ofs, int type, void *pixels); int GPU_offscreen_width(const GPUOffScreen *ofs); int GPU_offscreen_height(const GPUOffScreen *ofs); +int GPU_offscreen_color_texture(const GPUOffScreen *ofs); /* Builtin/Non-generated shaders */ typedef enum GPUProgramType { @@ -204,6 +207,19 @@ void GPU_program_unbind(GPUProgram *); * - must call texture bind before setting a texture as uniform! */ GPUShader *GPU_shader_create(const char *vertexcode, const char *fragcode, const char *geocode, const char *libcode, const char *defines, int input, int output, int number); +enum { + GPU_SHADER_FLAGS_NONE = 0, + GPU_SHADER_FLAGS_SPECIAL_OPENSUBDIV = (1 << 0), +}; +GPUShader *GPU_shader_create_ex(const char *vertexcode, + const char *fragcode, + const char *geocode, + const char *libcode, + const char *defines, + int input, + int output, + int number, + const int flags); void GPU_shader_free(GPUShader *shader); void GPU_shader_bind(GPUShader *shader); diff --git a/source/blender/gpu/GPU_material.h b/source/blender/gpu/GPU_material.h index dd08ed83e5a..25a4f33b526 100644 --- a/source/blender/gpu/GPU_material.h +++ b/source/blender/gpu/GPU_material.h @@ -160,6 +160,7 @@ typedef enum GPUDynamicType { GPU_DYNAMIC_LAMP_ATT2 = 9 | GPU_DYNAMIC_GROUP_LAMP, GPU_DYNAMIC_LAMP_SPOTSIZE = 10 | GPU_DYNAMIC_GROUP_LAMP, GPU_DYNAMIC_LAMP_SPOTBLEND = 11 | GPU_DYNAMIC_GROUP_LAMP, + GPU_DYNAMIC_LAMP_SPOTSCALE = 12 | GPU_DYNAMIC_GROUP_LAMP, GPU_DYNAMIC_SAMPLER_2DBUFFER = 1 | GPU_DYNAMIC_GROUP_SAMPLER, GPU_DYNAMIC_SAMPLER_2DIMAGE = 2 | GPU_DYNAMIC_GROUP_SAMPLER, @@ -314,13 +315,13 @@ void GPU_mist_update_values(int type, float start, float dist, float inten, floa void GPU_horizon_update_color(float color[3]); void GPU_ambient_update_color(float color[3]); -typedef struct GPUParticleInfo +struct GPUParticleInfo { float scalprops[4]; float location[3]; float velocity[3]; float angular_velocity[3]; -} GPUParticleInfo; +}; #ifdef WITH_OPENSUBDIV struct DerivedMesh; diff --git a/source/blender/gpu/intern/gpu_buffers.c b/source/blender/gpu/intern/gpu_buffers.c index f03632883bb..2c434fb405e 100644 --- a/source/blender/gpu/intern/gpu_buffers.c +++ b/source/blender/gpu/intern/gpu_buffers.c @@ -95,8 +95,6 @@ const GPUBufferTypeSettings gpu_buffer_type_settings[] = { {GL_ELEMENT_ARRAY_BUFFER_ARB, 4}, /* triangles, 1 point since we are allocating from tottriangle points, which account for all points */ {GL_ELEMENT_ARRAY_BUFFER_ARB, 1}, - /* fast triangles */ - {GL_ELEMENT_ARRAY_BUFFER_ARB, 1}, }; #define MAX_GPU_ATTRIB_DATA 32 diff --git a/source/blender/gpu/intern/gpu_codegen.c b/source/blender/gpu/intern/gpu_codegen.c index 12292f4897c..496302bb44e 100644 --- a/source/blender/gpu/intern/gpu_codegen.c +++ b/source/blender/gpu/intern/gpu_codegen.c @@ -718,7 +718,7 @@ static char *code_generate_vertex(ListBase *nodes, const GPUMatType type) GPUNode *node; GPUInput *input; char *code; - char *vertcode; + char *vertcode = NULL; for (node = nodes->first; node; node = node->next) { for (input = node->inputs.first; input; input = input->next) { @@ -1615,7 +1615,16 @@ GPUPass *GPU_generate_pass(ListBase *nodes, GPUNodeLink *outlink, fragmentcode = code_generate_fragment(nodes, outlink->output); vertexcode = code_generate_vertex(nodes, type); geometrycode = code_generate_geometry(nodes, use_opensubdiv); - shader = GPU_shader_create(vertexcode, fragmentcode, geometrycode, glsl_material_library, NULL, 0, 0, 0); + shader = GPU_shader_create_ex(vertexcode, + fragmentcode, + geometrycode, + glsl_material_library, + NULL, + 0, + 0, + 0, + use_opensubdiv ? GPU_SHADER_FLAGS_SPECIAL_OPENSUBDIV + : GPU_SHADER_FLAGS_NONE); /* failed? */ if (!shader) { diff --git a/source/blender/gpu/intern/gpu_compositing.c b/source/blender/gpu/intern/gpu_compositing.c index 2bafee0fb52..da5db73d382 100644 --- a/source/blender/gpu/intern/gpu_compositing.c +++ b/source/blender/gpu/intern/gpu_compositing.c @@ -306,6 +306,9 @@ bool GPU_fx_compositor_initialize_passes( fx->effects = 0; + if (!GPU_non_power_of_two_support() || !GLEW_EXT_framebuffer_object || !GLEW_ARB_fragment_shader) + return false; + if (!fx_settings) { cleanup_fx_gl_data(fx, true); return false; @@ -340,16 +343,18 @@ bool GPU_fx_compositor_initialize_passes( if (fx_flag & GPU_FX_FLAG_SSAO) num_passes++; - if (!fx->gbuffer) + if (!fx->gbuffer) { fx->gbuffer = GPU_framebuffer_create(); + if (!fx->gbuffer) { + return false; + } + } + /* try creating the jitter texture */ if (!fx->jitter_buffer) fx->jitter_buffer = create_jitter_texture(); - if (!fx->gbuffer) - return false; - /* check if color buffers need recreation */ if (!fx->color_buffer || !fx->depth_buffer || w != fx->gbuffer_dim[0] || h != fx->gbuffer_dim[1]) { cleanup_fx_gl_data(fx, false); diff --git a/source/blender/gpu/intern/gpu_debug.c b/source/blender/gpu/intern/gpu_debug.c index 1c194f517aa..29b7ff11586 100644 --- a/source/blender/gpu/intern/gpu_debug.c +++ b/source/blender/gpu/intern/gpu_debug.c @@ -43,7 +43,7 @@ #define CASE_CODE_RETURN_STR(code) case code: return #code; -static const char* gpu_gl_error_symbol(GLenum err) +static const char *gpu_gl_error_symbol(GLenum err) { switch (err) { CASE_CODE_RETURN_STR(GL_NO_ERROR) @@ -81,8 +81,8 @@ static bool gpu_report_gl_errors(const char *file, int line, const char *str) } 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. + * 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(); @@ -92,22 +92,18 @@ static bool gpu_report_gl_errors(const char *file, int line, const char *str) } } - 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)); + 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) +const char *gpuErrorString(GLenum err) { switch (err) { case GL_NO_ERROR: @@ -208,9 +204,9 @@ void gpu_debug_init(void) if (GLEW_KHR_debug) { #ifndef GLEW_ES_ONLY - glDebugMessageCallback(gpu_debug_proc, mxGetCurrentContext()); - glDebugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE, 0, NULL, GL_TRUE); - GPU_string_marker(sizeof(success), success); + glDebugMessageCallback(gpu_debug_proc, mxGetCurrentContext()); + glDebugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE, 0, NULL, GL_TRUE); + GPU_string_marker(sizeof(success), success); #endif return; } @@ -324,7 +320,7 @@ void GPU_print_error_debug(const char *str) } -void GPU_assert_no_gl_errors(const char* file, int line, const char* 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); diff --git a/source/blender/gpu/intern/gpu_extensions.c b/source/blender/gpu/intern/gpu_extensions.c index 74488e5928e..e1dff03d500 100644 --- a/source/blender/gpu/intern/gpu_extensions.c +++ b/source/blender/gpu/intern/gpu_extensions.c @@ -110,6 +110,7 @@ static struct GPUGlobal { int glslsupport; int extdisabled; int colordepth; + int samples_color_texture_max; int npotdisabled; /* ATI 3xx-5xx (and more) chipsets support NPoT partially (== not enough) */ int dlistsdisabled; /* Legacy ATI driver does not support display lists well */ GPUDeviceType device; @@ -180,6 +181,10 @@ void gpu_extensions_init(void) glGetIntegerv(GL_BLUE_BITS, &b); GG.colordepth = r + g + b; /* assumes same depth for RGB */ + if (GLEW_ARB_texture_multisample) { + glGetIntegerv(GL_MAX_COLOR_TEXTURE_SAMPLES , &GG.samples_color_texture_max); + } + vendor = (const char *)glGetString(GL_VENDOR); renderer = (const char *)glGetString(GL_RENDERER); version = (const char *)glGetString(GL_VERSION); @@ -380,15 +385,18 @@ static void GPU_print_framebuffer_error(GLenum status, char err_out[256]) struct GPUTexture { int w, h; /* width/height */ + int w_orig, h_orig; /* width/height (before power of 2 is applied) */ int number; /* number for multitexture binding */ int refcount; /* reference count */ GLenum target; /* GL_TEXTURE_* */ + GLenum target_base; /* same as target, (but no multisample) */ GLuint bindcode; /* opengl identifier for texture */ int fromblender; /* we got the texture from Blender */ 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? */ + int depth_orig; /* depth (before power of 2 is applied) */ }; static unsigned char *GPU_texture_convert_pixels(int length, const float *fpixels) @@ -419,7 +427,8 @@ static void GPU_glTexSubImageEmpty(GLenum target, GLenum format, int x, int y, i } static GPUTexture *GPU_texture_create_nD( - int w, int h, int n, const float *fpixels, int depth, GPUHDRType hdr_type, int components, + int w, int h, int n, const float *fpixels, int depth, + GPUHDRType hdr_type, int components, int samples, char err_out[256]) { GPUTexture *tex; @@ -429,13 +438,18 @@ static GPUTexture *GPU_texture_create_nD( if (depth && !GLEW_ARB_depth_texture) return NULL; + if (samples) { + CLAMP_MAX(samples, GG.samples_color_texture_max); + } + tex = MEM_callocN(sizeof(GPUTexture), "GPUTexture"); - tex->w = w; - tex->h = h; + tex->w = tex->w_orig = w; + tex->h = tex->h_orig = h; tex->number = -1; tex->refcount = 1; - tex->target = (n == 1)? GL_TEXTURE_1D: GL_TEXTURE_2D; - tex->depth = depth; + 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 = tex->depth_orig = depth; tex->fb_attachment = -1; glGenTextures(1, &tex->bindcode); @@ -521,8 +535,13 @@ static GPUTexture *GPU_texture_create_nD( } } else { - glTexImage2D(tex->target, 0, internalformat, tex->w, tex->h, 0, - format, type, NULL); + if (samples) { + glTexImage2DMultisample(tex->target, samples, internalformat, tex->w, tex->h, true); + } + else { + glTexImage2D(tex->target, 0, internalformat, tex->w, tex->h, 0, + format, type, NULL); + } if (fpixels) { glTexSubImage2D(tex->target, 0, 0, 0, w, h, @@ -539,23 +558,23 @@ static GPUTexture *GPU_texture_create_nD( MEM_freeN(pixels); if (depth) { - glTexParameteri(tex->target, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameteri(tex->target, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameteri(tex->target, GL_TEXTURE_COMPARE_MODE_ARB, GL_COMPARE_R_TO_TEXTURE); - glTexParameteri(tex->target, GL_TEXTURE_COMPARE_FUNC_ARB, GL_LEQUAL); - glTexParameteri(tex->target, GL_DEPTH_TEXTURE_MODE_ARB, GL_INTENSITY); + 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_ARB, GL_COMPARE_R_TO_TEXTURE); + glTexParameteri(tex->target_base, GL_TEXTURE_COMPARE_FUNC_ARB, GL_LEQUAL); + glTexParameteri(tex->target_base, GL_DEPTH_TEXTURE_MODE_ARB, GL_INTENSITY); } else { - glTexParameteri(tex->target, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(tex->target, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(tex->target_base, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(tex->target_base, GL_TEXTURE_MAG_FILTER, GL_LINEAR); } - if (tex->target != GL_TEXTURE_1D) { - glTexParameteri(tex->target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(tex->target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + if (tex->target_base != GL_TEXTURE_1D) { + glTexParameteri(tex->target_base, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(tex->target_base, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); } else - glTexParameteri(tex->target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(tex->target_base, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); return tex; } @@ -573,12 +592,13 @@ GPUTexture *GPU_texture_create_3D(int w, int h, int depth, int channels, const f return NULL; tex = MEM_callocN(sizeof(GPUTexture), "GPUTexture"); - tex->w = w; - tex->h = h; - tex->depth = depth; + tex->w = tex->w_orig = w; + tex->h = tex->h_orig = h; + tex->depth = tex->depth_orig = depth; tex->number = -1; tex->refcount = 1; tex->target = GL_TEXTURE_3D; + tex->target_base = GL_TEXTURE_3D; glGenTextures(1, &tex->bindcode); @@ -725,6 +745,7 @@ GPUTexture *GPU_texture_from_blender(Image *ima, ImageUser *iuser, bool is_data, tex->number = -1; tex->refcount = 1; tex->target = GL_TEXTURE_2D; + tex->target_base = GL_TEXTURE_2D; tex->fromblender = 1; ima->gputexture= tex; @@ -738,8 +759,8 @@ GPUTexture *GPU_texture_from_blender(Image *ima, ImageUser *iuser, bool is_data, glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, &h); glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_BORDER, &border); - tex->w = w - border; - tex->h = h - border; + tex->w = tex->w_orig = w - border; + tex->h = tex->h_orig = h - border; } glBindTexture(GL_TEXTURE_2D, lastbindcode); @@ -773,6 +794,7 @@ GPUTexture *GPU_texture_from_preview(PreviewImage *prv, int mipmap) tex->number = -1; tex->refcount = 1; tex->target = GL_TEXTURE_2D; + tex->target_base = GL_TEXTURE_2D; prv->gputexture[0] = tex; @@ -784,8 +806,8 @@ GPUTexture *GPU_texture_from_preview(PreviewImage *prv, int mipmap) glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &w); glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, &h); - tex->w = w; - tex->h = h; + tex->w = tex->w_orig = w; + tex->h = tex->h_orig = h; } glBindTexture(GL_TEXTURE_2D, lastbindcode); @@ -796,7 +818,7 @@ GPUTexture *GPU_texture_from_preview(PreviewImage *prv, int mipmap) GPUTexture *GPU_texture_create_1D(int w, const float *fpixels, char err_out[256]) { - GPUTexture *tex = GPU_texture_create_nD(w, 1, 1, fpixels, 0, GPU_HDR_NONE, 4, err_out); + GPUTexture *tex = GPU_texture_create_nD(w, 1, 1, fpixels, 0, GPU_HDR_NONE, 4, 0, err_out); if (tex) GPU_texture_unbind(tex); @@ -806,30 +828,48 @@ GPUTexture *GPU_texture_create_1D(int w, const float *fpixels, char err_out[256] GPUTexture *GPU_texture_create_2D(int w, int h, const float *fpixels, GPUHDRType hdr, char err_out[256]) { - GPUTexture *tex = GPU_texture_create_nD(w, h, 2, fpixels, 0, hdr, 4, err_out); + GPUTexture *tex = GPU_texture_create_nD(w, h, 2, fpixels, 0, hdr, 4, 0, err_out); if (tex) GPU_texture_unbind(tex); return tex; } +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_depth(int w, int h, char err_out[256]) { - GPUTexture *tex = GPU_texture_create_nD(w, h, 2, NULL, 1, GPU_HDR_NONE, 1, err_out); + 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; } +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; +} /** * 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 *tex = GPU_texture_create_nD(size, size, 2, NULL, 0, GPU_HDR_FULL_FLOAT, 2, err_out); + 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 */ @@ -844,7 +884,7 @@ 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 *tex = GPU_texture_create_nD(w, h, 2, pixels, 0, GPU_HDR_HALF_FLOAT, 2, err_out); + 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 */ @@ -863,7 +903,7 @@ GPUTexture *GPU_texture_create_2D_procedural(int w, int h, const float *pixels, GPUTexture *GPU_texture_create_1D_procedural(int w, const float *pixels, char err_out[256]) { - GPUTexture *tex = GPU_texture_create_nD(w, 0, 1, pixels, 0, GPU_HDR_HALF_FLOAT, 2, err_out); + 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 */ @@ -963,7 +1003,7 @@ void GPU_texture_unbind(GPUTexture *tex) arbnumber = (GLenum)((GLuint)GL_TEXTURE0_ARB + tex->number); if (tex->number != 0) glActiveTextureARB(arbnumber); glBindTexture(tex->target, 0); - glDisable(tex->target); + glDisable(tex->target_base); if (tex->number != 0) glActiveTextureARB(GL_TEXTURE0_ARB); tex->number = -1; @@ -1187,8 +1227,12 @@ void GPU_texture_bind_as_framebuffer(GPUTexture *tex) glReadBuffer(GL_COLOR_ATTACHMENT0_EXT + tex->fb_attachment); } + if (tex->target == GL_TEXTURE_2D_MULTISAMPLE) { + glEnable(GL_MULTISAMPLE_ARB); + } + /* push matrices and set default viewport and matrix */ - glViewport(0, 0, tex->w, tex->h); + glViewport(0, 0, tex->w_orig, tex->h_orig); GG.currentfb = tex->fb->object; glMatrixMode(GL_PROJECTION); @@ -1226,7 +1270,7 @@ void GPU_framebuffer_slots_bind(GPUFrameBuffer *fb, int slot) glReadBuffer(GL_COLOR_ATTACHMENT0_EXT + slot); /* push matrices and set default viewport and matrix */ - glViewport(0, 0, fb->colortex[slot]->w, fb->colortex[slot]->h); + glViewport(0, 0, fb->colortex[slot]->w_orig, fb->colortex[slot]->h_orig); GG.currentfb = fb->object; glMatrixMode(GL_PROJECTION); @@ -1256,7 +1300,7 @@ void GPU_framebuffer_bind_no_save(GPUFrameBuffer *fb, int slot) glReadBuffer(GL_COLOR_ATTACHMENT0_EXT + slot); /* push matrices and set default viewport and matrix */ - glViewport(0, 0, fb->colortex[slot]->w, fb->colortex[slot]->h); + glViewport(0, 0, fb->colortex[slot]->w_orig, fb->colortex[slot]->h_orig); GG.currentfb = fb->object; GG.currentfb = fb->object; } @@ -1316,8 +1360,8 @@ void GPU_framebuffer_restore(void) void GPU_framebuffer_blur(GPUFrameBuffer *fb, GPUTexture *tex, GPUFrameBuffer *blurfb, GPUTexture *blurtex) { - const float scaleh[2] = {1.0f / GPU_texture_opengl_width(blurtex), 0.0f}; - const float scalev[2] = {0.0f, 1.0f / GPU_texture_opengl_height(tex)}; + const float scaleh[2] = {1.0f / blurtex->w_orig, 0.0f}; + const float scalev[2] = {0.0f, 1.0f / tex->h_orig}; GPUShader *blur_shader = GPU_shader_get_builtin_shader(GPU_SHADER_SEP_GAUSSIAN_BLUR); int scale_uniform, texture_source_uniform; @@ -1341,7 +1385,7 @@ void GPU_framebuffer_blur(GPUFrameBuffer *fb, GPUTexture *tex, GPUFrameBuffer *b GPU_shader_bind(blur_shader); GPU_shader_uniform_vector(blur_shader, scale_uniform, 2, 1, scaleh); GPU_shader_uniform_texture(blur_shader, texture_source_uniform, tex); - glViewport(0, 0, GPU_texture_opengl_width(blurtex), GPU_texture_opengl_height(blurtex)); + glViewport(0, 0, blurtex->w_orig, blurtex->h_orig); /* Peparing to draw quad */ glMatrixMode(GL_MODELVIEW); @@ -1370,7 +1414,7 @@ void GPU_framebuffer_blur(GPUFrameBuffer *fb, GPUTexture *tex, GPUFrameBuffer *b GG.currentfb = fb->object; - glViewport(0, 0, GPU_texture_opengl_width(tex), GPU_texture_opengl_height(tex)); + glViewport(0, 0, tex->w_orig, tex->h_orig); GPU_shader_uniform_vector(blur_shader, scale_uniform, 2, 1, scalev); GPU_shader_uniform_texture(blur_shader, texture_source_uniform, blurtex); GPU_texture_bind(blurtex, 0); @@ -1393,7 +1437,7 @@ struct GPUOffScreen { GPUTexture *depth; }; -GPUOffScreen *GPU_offscreen_create(int width, int height, char err_out[256]) +GPUOffScreen *GPU_offscreen_create(int width, int height, int samples, char err_out[256]) { GPUOffScreen *ofs; @@ -1405,7 +1449,22 @@ GPUOffScreen *GPU_offscreen_create(int width, int height, char err_out[256]) return NULL; } - ofs->depth = GPU_texture_create_depth(width, height, err_out); + 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-samle + * offscreen buffers w/o reading their pixels */ + !GLEW_EXT_framebuffer_blit || + /* This is required when blitting from a multi-sampled buffers, + * even though we're not scaling. */ + !GLEW_EXT_framebuffer_multisample_blit_scaled) + { + samples = 0; + } + } + + ofs->depth = GPU_texture_create_depth_multisample(width, height, samples, err_out); if (!ofs->depth) { GPU_offscreen_free(ofs); return NULL; @@ -1416,7 +1475,7 @@ GPUOffScreen *GPU_offscreen_create(int width, int height, char err_out[256]) return NULL; } - ofs->color = GPU_texture_create_2D(width, height, NULL, GPU_HDR_NONE, err_out); + ofs->color = GPU_texture_create_2D_multisample(width, height, NULL, GPU_HDR_NONE, samples, err_out); if (!ofs->color) { GPU_offscreen_free(ofs); return NULL; @@ -1470,17 +1529,96 @@ void GPU_offscreen_unbind(GPUOffScreen *ofs, bool restore) void GPU_offscreen_read_pixels(GPUOffScreen *ofs, int type, void *pixels) { - glReadPixels(0, 0, ofs->color->w, ofs->color->h, GL_RGBA, type, pixels); + const int w = ofs->color->w_orig; + const int h = ofs->color->h_orig; + + if (ofs->color->target == GL_TEXTURE_2D_MULTISAMPLE) { + /* For a multi-sample texture, + * we need to create an intermediate buffer to blit to, + * before its copied using 'glReadPixels' */ + + /* not needed since 'ofs' needs to be bound to the framebuffer already */ +// #define USE_FBO_CTX_SWITCH + + GLuint fbo_blit = 0; + GLuint tex_blit = 0; + GLenum status; + + /* create texture for new 'fbo_blit' */ + glGenTextures(1, &tex_blit); + if (!tex_blit) { + goto finally; + } + + glBindTexture(GL_TEXTURE_2D, tex_blit); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, type, 0); + +#ifdef USE_FBO_CTX_SWITCH + /* read from multi-sample buffer */ + glBindFramebufferEXT(GL_READ_FRAMEBUFFER, ofs->color->fb->object); + glFramebufferTexture2DEXT( + GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + ofs->color->fb_attachment, + GL_TEXTURE_2D_MULTISAMPLE, ofs->color->bindcode, 0); + status = glCheckFramebufferStatus(GL_READ_FRAMEBUFFER); + if (status != GL_FRAMEBUFFER_COMPLETE) { + goto finally; + } +#endif + + /* write into new single-sample buffer */ + glGenFramebuffersEXT(1, &fbo_blit); + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo_blit); + glFramebufferTexture2DEXT( + GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, + GL_TEXTURE_2D, tex_blit, 0); + 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); + + /* read the results */ + glBindFramebufferEXT(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, ofs->color->fb->object); +#undef USE_FBO_CTX_SWITCH +#endif + + +finally: + /* cleanup */ + if (tex_blit) { + glDeleteTextures(1, &tex_blit); + } + if (fbo_blit) { + glDeleteFramebuffersEXT(1, &fbo_blit); + } + + GPU_ASSERT_NO_GL_ERRORS("Read Multi-Sample Pixels"); + } + else { + glReadPixels(0, 0, w, h, GL_RGBA, type, pixels); + } } int GPU_offscreen_width(const GPUOffScreen *ofs) { - return ofs->color->w; + return ofs->color->w_orig; } int GPU_offscreen_height(const GPUOffScreen *ofs) { - return ofs->color->h; + return ofs->color->h_orig; +} + +int GPU_offscreen_color_texture(const GPUOffScreen *ofs) +{ + return ofs->color->bindcode; } /* GPUShader */ @@ -1679,16 +1817,42 @@ void GPU_program_parameter_4f(GPUProgram *program, unsigned int location, float glProgramLocalParameter4fARB(program->type, location, x, y, z, w); } - - -GPUShader *GPU_shader_create(const char *vertexcode, const char *fragcode, const char *geocode, const char *libcode, const char *defines, int input, int output, int number) +GPUShader *GPU_shader_create(const char *vertexcode, + const char *fragcode, + const char *geocode, + const char *libcode, + const char *defines, + int input, + int output, + int number) +{ + return GPU_shader_create_ex(vertexcode, + fragcode, + geocode, + libcode, + defines, + input, + output, + number, + GPU_SHADER_FLAGS_NONE); +} + +GPUShader *GPU_shader_create_ex(const char *vertexcode, + const char *fragcode, + const char *geocode, + const char *libcode, + const char *defines, + int input, + int output, + int number, + const int flags) { #ifdef WITH_OPENSUBDIV /* TODO(sergey): used to add #version 150 to the geometry shader. - * Could safely be renamed to "use_geometry_code" since it's evry much - * liely any of geometry code will want to use GLSL 1.5. + * Could safely be renamed to "use_geometry_code" since it's very + * likely any of geometry code will want to use GLSL 1.5. */ - bool use_opensubdiv = geocode != NULL; + bool use_opensubdiv = (flags & GPU_SHADER_FLAGS_SPECIAL_OPENSUBDIV) != 0; #else bool use_opensubdiv = false; #endif @@ -1699,6 +1863,10 @@ GPUShader *GPU_shader_create(const char *vertexcode, const char *fragcode, const char standard_defines[MAX_DEFINE_LENGTH] = ""; char standard_extensions[MAX_EXT_DEFINE_LENGTH] = ""; +#ifndef WITH_OPENSUBDIV + UNUSED_VARS(flags); +#endif + if (!GLEW_ARB_vertex_shader || !GLEW_ARB_fragment_shader || (geocode && !GPU_geometry_shader_support())) return NULL; diff --git a/source/blender/gpu/intern/gpu_init_exit.c b/source/blender/gpu/intern/gpu_init_exit.c index 3a8a6fca23b..da4dd65d2e1 100644 --- a/source/blender/gpu/intern/gpu_init_exit.c +++ b/source/blender/gpu/intern/gpu_init_exit.c @@ -49,7 +49,7 @@ static bool initialized = false; void GPU_init(void) { - /* can't avoid calling this multiple times, see wm_window_add_ghostwindow */ + /* can't avoid calling this multiple times, see wm_window_ghostwindow_add */ if (initialized) return; diff --git a/source/blender/gpu/intern/gpu_material.c b/source/blender/gpu/intern/gpu_material.c index 5b647232934..82902f8d69c 100644 --- a/source/blender/gpu/intern/gpu_material.c +++ b/source/blender/gpu/intern/gpu_material.c @@ -141,6 +141,7 @@ struct GPULamp { float dynimat[4][4]; float spotsi, spotbl, k; + float spotvec[2]; float dyndist, dynatt1, dynatt2; float dist, att1, att2; float shadow_color[3]; @@ -536,12 +537,15 @@ static GPUNodeLink *lamp_get_visibility(GPUMaterial *mat, GPULamp *lamp, GPUNode if (lamp->type == LA_SPOT) { if (lamp->mode & LA_SQUARE) { - mat->dynproperty |= DYN_LAMP_VEC|DYN_LAMP_IMAT; - GPU_link(mat, "lamp_visibility_spot_square", GPU_dynamic_uniform(lamp->dynvec, GPU_DYNAMIC_LAMP_DYNVEC, lamp->ob), GPU_dynamic_uniform((float*)lamp->dynimat, GPU_DYNAMIC_LAMP_DYNIMAT, lamp->ob), *lv, &inpr); + mat->dynproperty |= DYN_LAMP_VEC | DYN_LAMP_IMAT; + GPU_link(mat, "lamp_visibility_spot_square", GPU_dynamic_uniform(lamp->dynvec, GPU_DYNAMIC_LAMP_DYNVEC, lamp->ob), GPU_dynamic_uniform((float*)lamp->dynimat, GPU_DYNAMIC_LAMP_DYNIMAT, lamp->ob), + GPU_dynamic_uniform((float *)lamp->spotvec, GPU_DYNAMIC_LAMP_SPOTSCALE, lamp->ob), *lv, &inpr); } else { - mat->dynproperty |= DYN_LAMP_VEC; - GPU_link(mat, "lamp_visibility_spot_circle", GPU_dynamic_uniform(lamp->dynvec, GPU_DYNAMIC_LAMP_DYNVEC, lamp->ob), *lv, &inpr); + mat->dynproperty |= DYN_LAMP_VEC | DYN_LAMP_IMAT; + GPU_link(mat, "lamp_visibility_spot_circle", GPU_dynamic_uniform(lamp->dynvec, GPU_DYNAMIC_LAMP_DYNVEC, lamp->ob), + GPU_dynamic_uniform((float *)lamp->dynimat, GPU_DYNAMIC_LAMP_DYNIMAT, lamp->ob), + GPU_dynamic_uniform((float *)lamp->spotvec, GPU_DYNAMIC_LAMP_SPOTSCALE, lamp->ob), *lv, &inpr); } GPU_link(mat, "lamp_visibility_spot", GPU_dynamic_uniform(&lamp->spotsi, GPU_DYNAMIC_LAMP_SPOTSIZE, lamp->ob), GPU_dynamic_uniform(&lamp->spotbl, GPU_DYNAMIC_LAMP_SPOTSIZE, lamp->ob), inpr, visifac, &visifac); @@ -1854,24 +1858,41 @@ static void gpu_lamp_calc_winmat(GPULamp *lamp) temp = 0.5f * lamp->size * cosf(angle) / sinf(angle); pixsize = lamp->d / temp; wsize = pixsize * 0.5f * lamp->size; - perspective_m4(lamp->winmat, -wsize, wsize, -wsize, wsize, lamp->d, lamp->clipend); + if (lamp->type & LA_SPOT) { + /* compute shadows according to X and Y scaling factors */ + perspective_m4( + lamp->winmat, + -wsize * lamp->spotvec[0], wsize * lamp->spotvec[0], + -wsize * lamp->spotvec[1], wsize * lamp->spotvec[1], + lamp->d, lamp->clipend); + } + else { + perspective_m4(lamp->winmat, -wsize, wsize, -wsize, wsize, lamp->d, lamp->clipend); + } } } void GPU_lamp_update(GPULamp *lamp, int lay, int hide, float obmat[4][4]) { float mat[4][4]; + float obmat_scale[3]; lamp->lay = lay; lamp->hide = hide; - copy_m4_m4(mat, obmat); - normalize_m4(mat); + normalize_m4_m4_ex(mat, obmat, obmat_scale); copy_v3_v3(lamp->vec, mat[2]); copy_v3_v3(lamp->co, mat[3]); copy_m4_m4(lamp->obmat, mat); invert_m4_m4(lamp->imat, mat); + + /* update spotlamp scale on X and Y axis */ + lamp->spotvec[0] = obmat_scale[0] / obmat_scale[2]; + lamp->spotvec[1] = obmat_scale[1] / obmat_scale[2]; + + /* makeshadowbuf */ + gpu_lamp_calc_winmat(lamp); } void GPU_lamp_update_colors(GPULamp *lamp, float r, float g, float b, float energy) @@ -1895,8 +1916,6 @@ void GPU_lamp_update_spot(GPULamp *lamp, float spotsize, float spotblend) { lamp->spotsi = cosf(spotsize * 0.5f); lamp->spotbl = (1.0f - lamp->spotsi) * spotblend; - - gpu_lamp_calc_winmat(lamp); } static void gpu_lamp_from_blender(Scene *scene, Object *ob, Object *par, Lamp *la, GPULamp *lamp) @@ -1941,9 +1960,6 @@ static void gpu_lamp_from_blender(Scene *scene, Object *ob, Object *par, Lamp *l /* arbitrary correction for the fact we do no soft transition */ lamp->bias *= 0.25f; - - /* makeshadowbuf */ - gpu_lamp_calc_winmat(lamp); } static void gpu_lamp_shadow_free(GPULamp *lamp) diff --git a/source/blender/gpu/shaders/gpu_shader_material.glsl b/source/blender/gpu/shaders/gpu_shader_material.glsl index 311fcb8ead2..5b62739b0eb 100644 --- a/source/blender/gpu/shaders/gpu_shader_material.glsl +++ b/source/blender/gpu/shaders/gpu_shader_material.glsl @@ -1584,11 +1584,13 @@ void lamp_visibility_sphere(float lampdist, float dist, float visifac, out float outvisifac= visifac*max(t, 0.0)/lampdist; } -void lamp_visibility_spot_square(vec3 lampvec, mat4 lampimat, vec3 lv, out float inpr) +void lamp_visibility_spot_square(vec3 lampvec, mat4 lampimat, vec2 scale, vec3 lv, out float inpr) { if(dot(lv, lampvec) > 0.0) { vec3 lvrot = (lampimat*vec4(lv, 0.0)).xyz; - float x = max(abs(lvrot.x/lvrot.z), abs(lvrot.y/lvrot.z)); + /* without clever non-uniform scale, we could do: */ + // float x = max(abs(lvrot.x / lvrot.z), abs(lvrot.y / lvrot.z)); + float x = max(abs((lvrot.x / scale.x) / lvrot.z), abs((lvrot.y / scale.y) / lvrot.z)); inpr = 1.0/sqrt(1.0 + x*x); } @@ -1596,9 +1598,21 @@ void lamp_visibility_spot_square(vec3 lampvec, mat4 lampimat, vec3 lv, out float inpr = 0.0; } -void lamp_visibility_spot_circle(vec3 lampvec, vec3 lv, out float inpr) +void lamp_visibility_spot_circle(vec3 lampvec, mat4 lampimat, vec2 scale, vec3 lv, out float inpr) { - inpr = dot(lv, lampvec); + /* without clever non-uniform scale, we could do: */ + // inpr = dot(lv, lampvec); + if (dot(lv, lampvec) > 0.0) { + vec3 lvrot = (lampimat * vec4(lv, 0.0)).xyz; + float x = abs(lvrot.x / lvrot.z); + float y = abs(lvrot.y / lvrot.z); + + float ellipse = abs((x * x) / (scale.x * scale.x) + (y * y) / (scale.y * scale.y)); + + inpr = 1.0 / sqrt(1.0 + ellipse); + } + else + inpr = 0.0; } void lamp_visibility_spot(float spotsi, float spotbl, float inpr, float visifac, out float outvisifac) diff --git a/source/blender/imbuf/CMakeLists.txt b/source/blender/imbuf/CMakeLists.txt index bdd8230a6ff..295a48dc245 100644 --- a/source/blender/imbuf/CMakeLists.txt +++ b/source/blender/imbuf/CMakeLists.txt @@ -120,7 +120,7 @@ if(WITH_IMAGE_OPENJPEG) intern/jp2.c ) - add_definitions(-DWITH_OPENJPEG) + add_definitions(-DWITH_OPENJPEG ${OPENJPEG_DEFINES}) endif() if(WITH_IMAGE_REDCODE) diff --git a/source/blender/imbuf/IMB_imbuf_types.h b/source/blender/imbuf/IMB_imbuf_types.h index 08ce9c0469b..e9dcf2da723 100644 --- a/source/blender/imbuf/IMB_imbuf_types.h +++ b/source/blender/imbuf/IMB_imbuf_types.h @@ -67,32 +67,34 @@ typedef struct DDSData { */ /* ibuf->ftype flag, main image types */ +/* Warning: Keep explicit value assignements here, this file is included in areas where not all format defines + * are set (e.g. intern/dds only get WITH_DDS, even if TIFF, HDR etc are also defined). See T46524. */ enum eImbTypes { - IMB_FTYPE_PNG = 1, - IMB_FTYPE_TGA, - IMB_FTYPE_JPG, - IMB_FTYPE_BMP, - IMB_FTYPE_OPENEXR, - IMB_FTYPE_IMAGIC, + IMB_FTYPE_PNG = 1, + IMB_FTYPE_TGA = 2, + IMB_FTYPE_JPG = 3, + IMB_FTYPE_BMP = 4, + IMB_FTYPE_OPENEXR = 5, + IMB_FTYPE_IMAGIC = 6, #ifdef WITH_OPENIMAGEIO - IMB_FTYPE_PSD, + IMB_FTYPE_PSD = 7, #endif #ifdef WITH_OPENJPEG - IMB_FTYPE_JP2, + IMB_FTYPE_JP2 = 8, #endif #ifdef WITH_HDR - IMB_FTYPE_RADHDR, + IMB_FTYPE_RADHDR = 9, #endif #ifdef WITH_TIFF - IMB_FTYPE_TIF, + IMB_FTYPE_TIF = 10, #endif #ifdef WITH_CINEON - IMB_FTYPE_CINEON, - IMB_FTYPE_DPX, + IMB_FTYPE_CINEON = 11, + IMB_FTYPE_DPX = 12, #endif #ifdef WITH_DDS - IMB_FTYPE_DDS, + IMB_FTYPE_DDS = 13, #endif }; @@ -124,12 +126,6 @@ enum eImbTypes { #define RAWTGA 1 -#define JPG_STD 0 -#define JPG_VID 1 -#define JPG_JST 2 -#define JPG_MAX 3 -#define JPG_MSK 0x03 - #ifdef WITH_TIFF #define TIF_16BIT (1 << 8 ) #endif diff --git a/source/blender/imbuf/IMB_thumbs.h b/source/blender/imbuf/IMB_thumbs.h index aaa5eea04ad..6ca4b919c1d 100644 --- a/source/blender/imbuf/IMB_thumbs.h +++ b/source/blender/imbuf/IMB_thumbs.h @@ -63,7 +63,7 @@ typedef enum ThumbSource { #define PREVIEW_RENDER_DEFAULT_HEIGHT 128 -/* Note this can also be used as versionning system, +/* Note this can also be used as versioning system, * to force refreshing all thumbnails if e.g. we change some thumb generating code or so. * Only used by fonts so far. */ #define THUMB_DEFAULT_HASH "00000000000000000000000000000000" diff --git a/source/blender/imbuf/intern/IMB_allocimbuf.h b/source/blender/imbuf/intern/IMB_allocimbuf.h index f4d6d869f1b..a754a4919eb 100644 --- a/source/blender/imbuf/intern/IMB_allocimbuf.h +++ b/source/blender/imbuf/intern/IMB_allocimbuf.h @@ -38,6 +38,18 @@ struct ImBuf; void imb_refcounter_lock_init(void); void imb_refcounter_lock_exit(void); +#ifdef WIN32 +void imb_mmap_lock_init(void); +void imb_mmap_lock_exit(void); +void imb_mmap_lock(void); +void imb_mmap_unlock(void); +#else +# define imb_mmap_lock_init() +# define imb_mmap_lock_exit() +# define imb_mmap_lock() +# define imb_mmap_unlock() +#endif + bool imb_addencodedbufferImBuf(struct ImBuf *ibuf); bool imb_enlargeencodedbufferImBuf(struct ImBuf *ibuf); diff --git a/source/blender/imbuf/intern/allocimbuf.c b/source/blender/imbuf/intern/allocimbuf.c index 9042c4bd09c..19b68b17e70 100644 --- a/source/blender/imbuf/intern/allocimbuf.c +++ b/source/blender/imbuf/intern/allocimbuf.c @@ -62,6 +62,30 @@ void imb_refcounter_lock_exit(void) BLI_spin_end(&refcounter_spin); } +#ifdef WIN32 +static SpinLock mmap_spin; + +void imb_mmap_lock_init(void) +{ + BLI_spin_init(&mmap_spin); +} + +void imb_mmap_lock_exit(void) +{ + BLI_spin_end(&mmap_spin); +} + +void imb_mmap_lock(void) +{ + BLI_spin_lock(&mmap_spin); +} + +void imb_mmap_unlock(void) +{ + BLI_spin_unlock(&mmap_spin); +} +#endif + void imb_freemipmapImBuf(ImBuf *ibuf) { int a; @@ -128,6 +152,13 @@ void imb_freetilesImBuf(ImBuf *ibuf) ibuf->mall &= ~IB_tiles; } +static void imb_free_bitmap_font(ImBuf *ibuf) +{ + if (ibuf->userdata && (ibuf->userflags & IB_BITMAPFONT)) { + MEM_freeN(ibuf->userdata); + } +} + static void freeencodedbufferImBuf(ImBuf *ibuf) { if (ibuf == NULL) return; @@ -181,6 +212,7 @@ void IMB_freeImBuf(ImBuf *ibuf) imb_freerectImBuf(ibuf); imb_freerectfloatImBuf(ibuf); imb_freetilesImBuf(ibuf); + imb_free_bitmap_font(ibuf); IMB_freezbufImBuf(ibuf); IMB_freezbuffloatImBuf(ibuf); freeencodedbufferImBuf(ibuf); @@ -206,7 +238,18 @@ ImBuf *IMB_makeSingleUser(ImBuf *ibuf) { ImBuf *rval; - if (!ibuf || ibuf->refcounter == 0) { return ibuf; } + if (ibuf) { + bool is_single; + BLI_spin_lock(&refcounter_spin); + is_single = (ibuf->refcounter == 0); + BLI_spin_unlock(&refcounter_spin); + if (is_single) { + return ibuf; + } + } + else { + return NULL; + } rval = IMB_dupImBuf(ibuf); diff --git a/source/blender/imbuf/intern/dds/ColorBlock.cpp b/source/blender/imbuf/intern/dds/ColorBlock.cpp index 28f31fcad8b..dd4ae3e518e 100644 --- a/source/blender/imbuf/intern/dds/ColorBlock.cpp +++ b/source/blender/imbuf/intern/dds/ColorBlock.cpp @@ -38,6 +38,7 @@ #include <Image.h> #include <Common.h> +#if 0 // Get approximate luminance. inline static uint colorLuminance(Color32 c) { @@ -49,6 +50,7 @@ { return (c0.r - c1.r) * (c0.r - c1.r) + (c0.g - c1.g) * (c0.g - c1.g) + (c0.b - c1.b) * (c0.b - c1.b); } +#endif /// Default constructor. @@ -86,8 +88,8 @@ void ColorBlock::init(const Image *img, uint x, uint y) void ColorBlock::init(uint w, uint h, const uint *data, uint x, uint y) { - const uint bw = min(w - x, 4U); - const uint bh = min(h - y, 4U); + const uint bw = MIN(w - x, 4U); + const uint bh = MIN(h - y, 4U); // Blocks that are smaller than 4x4 are handled by repeating the pixels. // @@ Thats only correct when block size is 1, 2 or 4, but not with 3. :( @@ -107,8 +109,8 @@ void ColorBlock::init(uint w, uint h, const uint *data, uint x, uint y) void ColorBlock::init(uint w, uint h, const float *data, uint x, uint y) { - const uint bw = min(w - x, 4U); - const uint bh = min(h - y, 4U); + const uint bw = MIN(w - x, 4U); + const uint bh = MIN(h - y, 4U); // Blocks that are smaller than 4x4 are handled by repeating the pixels. // @@ Thats only correct when block size is 1, 2 or 4, but not with 3. :( @@ -124,10 +126,10 @@ void ColorBlock::init(uint w, uint h, const float *data, uint x, uint y) const uint idx = ((y + by) * w + x + bx); Color32 & c = color(e, i); - c.r = uint8(255 * clamp(data[idx + 0 * srcPlane], 0.0f, 1.0f)); // @@ Is this the right way to quantize floats to bytes? - c.g = uint8(255 * clamp(data[idx + 1 * srcPlane], 0.0f, 1.0f)); - c.b = uint8(255 * clamp(data[idx + 2 * srcPlane], 0.0f, 1.0f)); - c.a = uint8(255 * clamp(data[idx + 3 * srcPlane], 0.0f, 1.0f)); + c.r = uint8(255 * CLAMP(data[idx + 0 * srcPlane], 0.0f, 1.0f)); // @@ Is this the right way to quantize floats to bytes? + c.g = uint8(255 * CLAMP(data[idx + 1 * srcPlane], 0.0f, 1.0f)); + c.b = uint8(255 * CLAMP(data[idx + 2 * srcPlane], 0.0f, 1.0f)); + c.a = uint8(255 * CLAMP(data[idx + 3 * srcPlane], 0.0f, 1.0f)); } } } diff --git a/source/blender/imbuf/intern/dds/Common.h b/source/blender/imbuf/intern/dds/Common.h index ab929b82264..b1beb3f3a1b 100644 --- a/source/blender/imbuf/intern/dds/Common.h +++ b/source/blender/imbuf/intern/dds/Common.h @@ -28,14 +28,14 @@ #ifndef __COMMON_H__ #define __COMMON_H__ -#ifndef min -#define min(a,b) ((a) <= (b) ? (a) : (b)) +#ifndef MIN +#define MIN(a,b) ((a) <= (b) ? (a) : (b)) #endif -#ifndef max -#define max(a,b) ((a) >= (b) ? (a) : (b)) +#ifndef MAX +#define MAX(a,b) ((a) >= (b) ? (a) : (b)) #endif -#ifndef clamp -#define clamp(x,a,b) min(max((x), (a)), (b)) +#ifndef CLAMP +#define CLAMP(x,a,b) MIN(MAX((x), (a)), (b)) #endif template<typename T> diff --git a/source/blender/imbuf/intern/dds/DirectDrawSurface.cpp b/source/blender/imbuf/intern/dds/DirectDrawSurface.cpp index 6bf82776afe..a4281514e39 100644 --- a/source/blender/imbuf/intern/dds/DirectDrawSurface.cpp +++ b/source/blender/imbuf/intern/dds/DirectDrawSurface.cpp @@ -83,7 +83,7 @@ static const uint FOURCC_RXGB = DDS_MAKEFOURCC('R', 'X', 'G', 'B'); static const uint FOURCC_ATI1 = DDS_MAKEFOURCC('A', 'T', 'I', '1'); static const uint FOURCC_ATI2 = DDS_MAKEFOURCC('A', 'T', 'I', '2'); -static const uint FOURCC_A2XY = DDS_MAKEFOURCC('A', '2', 'X', 'Y'); +//static const uint FOURCC_A2XY = DDS_MAKEFOURCC('A', '2', 'X', 'Y'); static const uint FOURCC_DX10 = DDS_MAKEFOURCC('D', 'X', '1', '0'); @@ -107,25 +107,25 @@ static const uint D3DFMT_X8B8G8R8 = 33; static const uint D3DFMT_G16R16 = 34; static const uint D3DFMT_A2R10G10B10 = 35; -static const uint D3DFMT_A16B16G16R16 = 36; +//static const uint D3DFMT_A16B16G16R16 = 36; // Palette formats. -static const uint D3DFMT_A8P8 = 40; -static const uint D3DFMT_P8 = 41; +//static const uint D3DFMT_A8P8 = 40; +//static const uint D3DFMT_P8 = 41; // Luminance formats. static const uint D3DFMT_L8 = 50; -static const uint D3DFMT_A8L8 = 51; -static const uint D3DFMT_A4L4 = 52; +//static const uint D3DFMT_A8L8 = 51; +//static const uint D3DFMT_A4L4 = 52; static const uint D3DFMT_L16 = 81; // Floating point formats -static const uint D3DFMT_R16F = 111; -static const uint D3DFMT_G16R16F = 112; -static const uint D3DFMT_A16B16G16R16F = 113; -static const uint D3DFMT_R32F = 114; -static const uint D3DFMT_G32R32F = 115; -static const uint D3DFMT_A32B32G32R32F = 116; +//static const uint D3DFMT_R16F = 111; +//static const uint D3DFMT_G16R16F = 112; +//static const uint D3DFMT_A16B16G16R16F = 113; +//static const uint D3DFMT_R32F = 114; +//static const uint D3DFMT_G32R32F = 115; +//static const uint D3DFMT_A32B32G32R32F = 116; static const uint DDSD_CAPS = 0x00000001U; static const uint DDSD_PIXELFORMAT = 0x00001000U; @@ -1102,8 +1102,8 @@ void DirectDrawSurface::mipmap(Image *img, uint face, uint mipmap) // Compute width and height. for (uint m = 0; m < mipmap; m++) { - w = max(1U, w / 2); - h = max(1U, h / 2); + w = MAX(1U, w / 2); + h = MAX(1U, h / 2); } img->allocate(w, h); @@ -1223,9 +1223,9 @@ void DirectDrawSurface::readBlockImage(Image *img) readBlock(&block); // Write color block. - for (uint y = 0; y < min(4U, h-4*by); y++) + for (uint y = 0; y < MIN(4U, h-4*by); y++) { - for (uint x = 0; x < min(4U, w-4*bx); x++) + for (uint x = 0; x < MIN(4U, w-4*bx); x++) { img->pixel(4*bx+x, 4*by+y) = block.color(x, y); } @@ -1240,7 +1240,7 @@ static Color32 buildNormal(uint8 x, uint8 y) float ny = 2 * (y / 255.0f) - 1; float nz = 0.0f; if (1 - nx*nx - ny*ny > 0) nz = sqrt(1 - nx*nx - ny*ny); - uint8 z = clamp(int(255.0f * (nz + 1) / 2.0f), 0, 255); + uint8 z = CLAMP(int(255.0f * (nz + 1) / 2.0f), 0, 255); return Color32(x, y, z); } @@ -1379,9 +1379,9 @@ uint DirectDrawSurface::mipmapSize(uint mipmap) const for (uint m = 0; m < mipmap; m++) { - w = max(1U, w / 2); - h = max(1U, h / 2); - d = max(1U, d / 2); + w = MAX(1U, w / 2); + h = MAX(1U, h / 2); + d = MAX(1U, d / 2); } if (header.pf.flags & DDPF_FOURCC) diff --git a/source/blender/imbuf/intern/dds/FlipDXT.cpp b/source/blender/imbuf/intern/dds/FlipDXT.cpp index 4f63d17dc90..604796d1705 100644 --- a/source/blender/imbuf/intern/dds/FlipDXT.cpp +++ b/source/blender/imbuf/intern/dds/FlipDXT.cpp @@ -246,8 +246,8 @@ int FlipDXTCImage(unsigned int width, unsigned int height, unsigned int levels, // mip levels are contiguous. data += block_bytes * blocks; - mip_width = max(1U, mip_width >> 1); - mip_height = max(1U, mip_height >> 1); + mip_width = MAX(1U, mip_width >> 1); + mip_height = MAX(1U, mip_height >> 1); } return 1; diff --git a/source/blender/imbuf/intern/jpeg.c b/source/blender/imbuf/intern/jpeg.c index ff2a9767386..35c7b6363a1 100644 --- a/source/blender/imbuf/intern/jpeg.c +++ b/source/blender/imbuf/intern/jpeg.c @@ -54,12 +54,6 @@ #include "IMB_colormanagement.h" #include "IMB_colormanagement_intern.h" -// #define IS_jpg(x) (x->ftype & JPG) // UNUSED -#define IS_stdjpg(x) ((x->foptions.flag & JPG_MSK) == JPG_STD) -// #define IS_vidjpg(x) ((x->foptions & JPG_MSK) == JPG_VID) // UNUSED -#define IS_jstjpg(x) ((x->foptions.flag & JPG_MSK) == JPG_JST) -#define IS_maxjpg(x) ((x->foptions.flag & JPG_MSK) == JPG_MAX) - /* the types are from the jpeg lib */ static void jpeg_error(j_common_ptr cinfo) ATTR_NORETURN; static void init_source(j_decompress_ptr cinfo); @@ -70,22 +64,8 @@ static void memory_source(j_decompress_ptr cinfo, const unsigned char *buffer, s static boolean handle_app1(j_decompress_ptr cinfo); static ImBuf *ibJpegImageFromCinfo(struct jpeg_decompress_struct *cinfo, int flags); - -/* - * In principle there are 4 jpeg formats. - * - * 1. jpeg - standard printing, u & v at quarter of resolution - * 2. jvid - standard video, u & v half resolution, frame not interlaced - * - * type 3 is unsupported as of jul 05 2000 Frank. - * - * 3. jstr - as 2, but written in 2 separate fields - * - * 4. jmax - no scaling in the components - */ - -static int jpeg_default_quality; -static int ibuf_foptions; +static const uchar jpeg_default_quality = 75; +static uchar ibuf_quality; int imb_is_a_jpeg(const unsigned char *mem) { @@ -254,6 +234,13 @@ static void memory_source(j_decompress_ptr cinfo, const unsigned char *buffer, s bytes_in_buffer--; \ V += GETJOCTET(*next_input_byte++); ) +struct NeoGeo_Word { + uchar pad1; + uchar pad2; + uchar pad3; + uchar quality; +} ; +BLI_STATIC_ASSERT(sizeof(struct NeoGeo_Word) == 4, "Must be 4 bytes"); static boolean handle_app1(j_decompress_ptr cinfo) { @@ -267,13 +254,19 @@ static boolean handle_app1(j_decompress_ptr cinfo) length -= 2; if (length < 16) { - for (i = 0; i < length; i++) INPUT_BYTE(cinfo, neogeo[i], return false); + for (i = 0; i < length; i++) { + INPUT_BYTE(cinfo, neogeo[i], return false); + } length = 0; - if (STREQLEN(neogeo, "NeoGeo", 6)) memcpy(&ibuf_foptions, neogeo + 6, 4); - ibuf_foptions = BIG_LONG(ibuf_foptions); + if (STREQLEN(neogeo, "NeoGeo", 6)) { + struct NeoGeo_Word *neogeo_word = (struct NeoGeo_Word *)(neogeo + 6); + ibuf_quality = neogeo_word->quality; + } } INPUT_SYNC(cinfo); /* do before skip_input_data */ - if (length > 0) (*cinfo->src->skip_input_data)(cinfo, length); + if (length > 0) { + (*cinfo->src->skip_input_data)(cinfo, length); + } return true; } @@ -290,7 +283,7 @@ static ImBuf *ibJpegImageFromCinfo(struct jpeg_decompress_struct *cinfo, int fla char *str, *key, *value; /* install own app1 handler */ - ibuf_foptions = 0; + ibuf_quality = jpeg_default_quality; jpeg_set_marker_processor(cinfo, 0xe1, handle_app1); cinfo->dct_method = JDCT_FLOAT; jpeg_save_markers(cinfo, JPEG_COM, 0xffff); @@ -304,14 +297,6 @@ static ImBuf *ibJpegImageFromCinfo(struct jpeg_decompress_struct *cinfo, int fla jpeg_start_decompress(cinfo); - if (ibuf_foptions == 0) { - ibuf_foptions = JPG_STD; - if (cinfo->max_v_samp_factor == 1) { - if (cinfo->max_h_samp_factor == 1) ibuf_foptions = JPG_MAX; - else ibuf_foptions = JPG_VID; - } - } - if (flags & IB_test) { jpeg_abort_decompress(cinfo); ibuf = IMB_allocImBuf(x, y, 8 * depth, 0); @@ -436,7 +421,7 @@ next_stamp_marker: jpeg_destroy((j_common_ptr) cinfo); if (ibuf) { ibuf->ftype = IMB_FTYPE_JPG; - ibuf->foptions.flag = ibuf_foptions; + ibuf->foptions.quality = MIN2(ibuf_quality, 100); } } @@ -481,16 +466,16 @@ static void write_jpeg(struct jpeg_compress_struct *cinfo, struct ImBuf *ibuf) uchar *rect; int x, y; char neogeo[128]; + struct NeoGeo_Word *neogeo_word; char *text; jpeg_start_compress(cinfo, true); strcpy(neogeo, "NeoGeo"); - ibuf_foptions = BIG_LONG((((int)ibuf->foptions.flag) << 8) | (int)ibuf->foptions.quality); - - memcpy(neogeo + 6, &ibuf_foptions, 4); + neogeo_word = (struct NeoGeo_Word *)(neogeo + 6); + memset(neogeo_word, 0, sizeof(*neogeo_word)); + neogeo_word->quality = ibuf->foptions.quality; jpeg_write_marker(cinfo, 0xe1, (JOCTET *) neogeo, 10); - if (ibuf->metadata) { IDProperty *prop; /* key + max value + "Blender" */ @@ -613,113 +598,8 @@ static int save_stdjpeg(const char *name, struct ImBuf *ibuf) struct jpeg_compress_struct _cinfo, *cinfo = &_cinfo; struct my_error_mgr jerr; - if ((outfile = BLI_fopen(name, "wb")) == NULL) return 0; - jpeg_default_quality = 75; - - cinfo->err = jpeg_std_error(&jerr.pub); - jerr.pub.error_exit = jpeg_error; - - /* Establish the setjmp return context for jpeg_error to use. */ - if (setjmp(jerr.setjmp_buffer)) { - /* If we get here, the JPEG code has signaled an error. - * We need to clean up the JPEG object, close the input file, and return. - */ - jpeg_destroy_compress(cinfo); - fclose(outfile); - remove(name); + if ((outfile = BLI_fopen(name, "wb")) == NULL) return 0; - } - - init_jpeg(outfile, cinfo, ibuf); - - write_jpeg(cinfo, ibuf); - - fclose(outfile); - jpeg_destroy_compress(cinfo); - - return 1; -} - - -static int save_vidjpeg(const char *name, struct ImBuf *ibuf) -{ - FILE *outfile; - struct jpeg_compress_struct _cinfo, *cinfo = &_cinfo; - struct my_error_mgr jerr; - - if ((outfile = BLI_fopen(name, "wb")) == NULL) return 0; - jpeg_default_quality = 90; - - cinfo->err = jpeg_std_error(&jerr.pub); - jerr.pub.error_exit = jpeg_error; - - /* Establish the setjmp return context for jpeg_error to use. */ - if (setjmp(jerr.setjmp_buffer)) { - /* If we get here, the JPEG code has signaled an error. - * We need to clean up the JPEG object, close the input file, and return. - */ - jpeg_destroy_compress(cinfo); - fclose(outfile); - remove(name); - return 0; - } - - init_jpeg(outfile, cinfo, ibuf); - - /* adjust scaling factors */ - if (cinfo->in_color_space == JCS_RGB) { - cinfo->comp_info[0].h_samp_factor = 2; - cinfo->comp_info[0].v_samp_factor = 1; - } - - write_jpeg(cinfo, ibuf); - - fclose(outfile); - jpeg_destroy_compress(cinfo); - - return 1; -} - -static int save_jstjpeg(const char *name, struct ImBuf *ibuf) -{ - char fieldname[1024]; - struct ImBuf *tbuf; - int oldy, returnval; - - tbuf = IMB_allocImBuf(ibuf->x, ibuf->y / 2, 24, IB_rect); - tbuf->ftype = ibuf->ftype; - tbuf->foptions = ibuf->foptions; - tbuf->flags = ibuf->flags; - - oldy = ibuf->y; - ibuf->x *= 2; - ibuf->y /= 2; - - IMB_rectcpy(tbuf, ibuf, 0, 0, 0, 0, ibuf->x, ibuf->y); - sprintf(fieldname, "%s.jf0", name); - - returnval = save_vidjpeg(fieldname, tbuf); - if (returnval == 1) { - IMB_rectcpy(tbuf, ibuf, 0, 0, tbuf->x, 0, ibuf->x, ibuf->y); - sprintf(fieldname, "%s.jf1", name); - returnval = save_vidjpeg(fieldname, tbuf); - } - - ibuf->y = oldy; - ibuf->x /= 2; - IMB_freeImBuf(tbuf); - - return returnval; -} - -static int save_maxjpeg(const char *name, struct ImBuf *ibuf) -{ - FILE *outfile; - struct jpeg_compress_struct _cinfo, *cinfo = &_cinfo; - struct my_error_mgr jerr; - - if ((outfile = BLI_fopen(name, "wb")) == NULL) return 0; - jpeg_default_quality = 100; cinfo->err = jpeg_std_error(&jerr.pub); jerr.pub.error_exit = jpeg_error; @@ -737,12 +617,6 @@ static int save_maxjpeg(const char *name, struct ImBuf *ibuf) init_jpeg(outfile, cinfo, ibuf); - /* adjust scaling factors */ - if (cinfo->in_color_space == JCS_RGB) { - cinfo->comp_info[0].h_samp_factor = 1; - cinfo->comp_info[0].v_samp_factor = 1; - } - write_jpeg(cinfo, ibuf); fclose(outfile); @@ -755,9 +629,5 @@ int imb_savejpeg(struct ImBuf *ibuf, const char *name, int flags) { ibuf->flags = flags; - if (IS_stdjpg(ibuf)) return save_stdjpeg(name, ibuf); - if (IS_jstjpg(ibuf)) return save_jstjpeg(name, ibuf); - if (IS_maxjpg(ibuf)) return save_maxjpeg(name, ibuf); - return save_vidjpeg(name, ibuf); + return save_stdjpeg(name, ibuf); } - diff --git a/source/blender/imbuf/intern/module.c b/source/blender/imbuf/intern/module.c index 4097deb00ed..777fe77f032 100644 --- a/source/blender/imbuf/intern/module.c +++ b/source/blender/imbuf/intern/module.c @@ -37,6 +37,7 @@ void IMB_init(void) { imb_refcounter_lock_init(); + imb_mmap_lock_init(); imb_filetypes_init(); imb_tile_cache_init(); colormanagement_init(); @@ -47,6 +48,7 @@ void IMB_exit(void) imb_tile_cache_exit(); imb_filetypes_exit(); colormanagement_exit(); + imb_mmap_lock_exit(); imb_refcounter_lock_exit(); } diff --git a/source/blender/imbuf/intern/radiance_hdr.c b/source/blender/imbuf/intern/radiance_hdr.c index f97860cc66c..71e74928e20 100644 --- a/source/blender/imbuf/intern/radiance_hdr.c +++ b/source/blender/imbuf/intern/radiance_hdr.c @@ -37,13 +37,10 @@ * ---------------------------------------------------------------------- */ -#ifdef WIN32 -# include "BLI_utildefines.h" -#endif - #include "MEM_guardedalloc.h" #include "BLI_fileops.h" +#include "BLI_utildefines.h" #include "imbuf.h" @@ -76,7 +73,7 @@ static const unsigned char *oldreadcolrs(RGBE *scan, const unsigned char *mem, i { int i, rshift = 0, len = xmax; while (len > 0) { - if (mem_eof - mem < 4) { + if (UNLIKELY(mem_eof - mem < 4)) { return NULL; } scan[0][RED] = *mem++; @@ -104,11 +101,11 @@ static const unsigned char *freadcolrs(RGBE *scan, const unsigned char *mem, int { int i, j, code, val; - if (mem_eof - mem < 4) { + if (UNLIKELY(mem_eof - mem < 4)) { return NULL; } - if ((xmax < MINELEN) | (xmax > MAXELEN)) { + if (UNLIKELY((xmax < MINELEN) | (xmax > MAXELEN))) { return oldreadcolrs(scan, mem, xmax, mem_eof); } @@ -128,25 +125,31 @@ static const unsigned char *freadcolrs(RGBE *scan, const unsigned char *mem, int return oldreadcolrs(scan + 1, mem, xmax - 1, mem_eof); } - if (((scan[0][BLU] << 8) | i) != xmax) { + if (UNLIKELY(((scan[0][BLU] << 8) | i) != xmax)) { return NULL; } for (i = 0; i < 4; i++) { - if (mem_eof - mem < 2) { + if (UNLIKELY(mem_eof - mem < 2)) { return NULL; } for (j = 0; j < xmax; ) { code = *mem++; if (code > 128) { code &= 127; + if (UNLIKELY(code + j > xmax)) { + return NULL; + } val = *mem++; while (code--) { scan[j++][i] = (unsigned char)val; } } else { - if (mem_eof - mem < code) { + if (UNLIKELY(mem_eof - mem < code)) { + return NULL; + } + if (UNLIKELY(code + j > xmax)) { return NULL; } while (code--) { @@ -240,13 +243,17 @@ struct ImBuf *imb_loadhdr(const unsigned char *mem, size_t size, int flags, char if (flags & IB_test) ibuf = IMB_allocImBuf(width, height, 32, 0); else ibuf = IMB_allocImBuf(width, height, 32, (flags & IB_rect) | IB_rectfloat); - if (ibuf == NULL) return NULL; + if (UNLIKELY(ibuf == NULL)) { + return NULL; + } ibuf->ftype = IMB_FTYPE_RADHDR; if (flags & IB_alphamode_detect) ibuf->flags |= IB_alphamode_premul; - if (flags & IB_test) return ibuf; + if (flags & IB_test) { + return ibuf; + } /* read in and decode the actual data */ sline = (RGBE *)MEM_mallocN(sizeof(*sline) * width, __func__); @@ -290,7 +297,9 @@ static int fwritecolrs(FILE *file, int width, int channels, unsigned char *ibufs fCOLOR fcol; RGBE rgbe, *rgbe_scan; - if ((ibufscan == NULL) && (fpscan == NULL)) return 0; + if (UNLIKELY((ibufscan == NULL) && (fpscan == NULL))) { + return 0; + } rgbe_scan = (RGBE *)MEM_mallocN(sizeof(RGBE) * width, "radhdr_write_tmpscan"); @@ -381,7 +390,9 @@ int imb_savehdr(struct ImBuf *ibuf, const char *name, int flags) (void)flags; /* unused */ - if (file == NULL) return 0; + if (file == NULL) { + return 0; + } writeHeader(file, width, height); diff --git a/source/blender/imbuf/intern/readimage.c b/source/blender/imbuf/intern/readimage.c index 1c83b33e296..afa3ffb31f3 100644 --- a/source/blender/imbuf/intern/readimage.c +++ b/source/blender/imbuf/intern/readimage.c @@ -46,6 +46,7 @@ #include "BLI_fileops.h" #include "imbuf.h" +#include "IMB_allocimbuf.h" #include "IMB_imbuf_types.h" #include "IMB_imbuf.h" #include "IMB_filetype.h" @@ -174,7 +175,10 @@ ImBuf *IMB_loadifffile(int file, const char *filepath, int flags, char colorspac size = BLI_file_descriptor_size(file); + imb_mmap_lock(); mem = mmap(NULL, size, PROT_READ, MAP_SHARED, file, 0); + imb_mmap_unlock(); + if (mem == (unsigned char *) -1) { fprintf(stderr, "%s: couldn't get mapping %s\n", __func__, descr); return NULL; @@ -182,8 +186,10 @@ ImBuf *IMB_loadifffile(int file, const char *filepath, int flags, char colorspac ibuf = IMB_ibImageFromMemory(mem, size, flags, colorspace, descr); + imb_mmap_lock(); if (munmap(mem, size)) fprintf(stderr, "%s: couldn't unmap file %s\n", __func__, descr); + imb_mmap_unlock(); return ibuf; } @@ -269,7 +275,10 @@ static void imb_loadtilefile(ImBuf *ibuf, int file, int tx, int ty, unsigned int size = BLI_file_descriptor_size(file); + imb_mmap_lock(); mem = mmap(NULL, size, PROT_READ, MAP_SHARED, file, 0); + imb_mmap_unlock(); + if (mem == (unsigned char *) -1) { fprintf(stderr, "Couldn't get memory mapping for %s\n", ibuf->cachename); return; @@ -279,8 +288,10 @@ static void imb_loadtilefile(ImBuf *ibuf, int file, int tx, int ty, unsigned int if (type->load_tile && type->ftype(type, ibuf)) type->load_tile(ibuf, mem, size, tx, ty, rect); + imb_mmap_lock(); if (munmap(mem, size)) fprintf(stderr, "Couldn't unmap memory for %s.\n", ibuf->cachename); + imb_mmap_unlock(); } void imb_loadtile(ImBuf *ibuf, int tx, int ty, unsigned int *rect) diff --git a/source/blender/imbuf/intern/scaling.c b/source/blender/imbuf/intern/scaling.c index 2601fe62c2f..605adffb813 100644 --- a/source/blender/imbuf/intern/scaling.c +++ b/source/blender/imbuf/intern/scaling.c @@ -1555,7 +1555,7 @@ struct ImBuf *IMB_scalefastImBuf(struct ImBuf *ibuf, unsigned int newx, unsigned struct imbufRGBA *rectf, *_newrectf, *newrectf; int x, y; bool do_float = false, do_rect = false; - int ofsx, ofsy, stepx, stepy; + size_t ofsx, ofsy, stepx, stepy; rect = NULL; _newrect = NULL; newrect = NULL; rectf = NULL; _newrectf = NULL; newrectf = NULL; diff --git a/source/blender/imbuf/intern/stereoimbuf.c b/source/blender/imbuf/intern/stereoimbuf.c index 3b9da639a86..13a15f101e7 100644 --- a/source/blender/imbuf/intern/stereoimbuf.c +++ b/source/blender/imbuf/intern/stereoimbuf.c @@ -343,7 +343,7 @@ static void imb_stereo3d_write_interlace(Stereo3DData *s3d, enum eStereo3dInterl }; char i = (char) swap; for (x = 0; x < width; x++, from[0] += 3, from[1] += 3, to += 3) { - copy_v3_v3_char((char *)to, (char *)from[i]); + copy_v3_v3_uchar(to, from[i]); i = !i; } } @@ -357,7 +357,7 @@ static void imb_stereo3d_write_interlace(Stereo3DData *s3d, enum eStereo3dInterl }; char i = (char) swap; for (x = 0; x < width; x++, from[0] += 4, from[1] += 4, to += 4) { - copy_v4_v4_char((char *)to, (char *)from[i]); + copy_v4_v4_uchar(to, from[i]); i = !i; } } @@ -392,7 +392,7 @@ static void imb_stereo3d_write_interlace(Stereo3DData *s3d, enum eStereo3dInterl }; char j = i; for (x = 0; x < width; x++, from[0] += 3, from[1] += 3, to += 3) { - copy_v3_v3_char((char *)to, (char *)from[j]); + copy_v3_v3_uchar(to, from[j]); j = !j; } i = !i; @@ -408,7 +408,7 @@ static void imb_stereo3d_write_interlace(Stereo3DData *s3d, enum eStereo3dInterl }; char j = i; for (x = 0; x < width; x++, from[0] += 4, from[1] += 4, to += 4) { - copy_v4_v4_char((char *)to, (char *)from[j]); + copy_v4_v4_uchar(to, from[j]); j = !j; } i = !i; @@ -1035,7 +1035,7 @@ static void imb_stereo3d_read_interlace(Stereo3DData *s3d, enum eStereo3dInterla }; char i = (char) swap; for (x = 0; x < width; x++, from += 3, to[0] += 3, to[1] += 3) { - copy_v3_v3_char((char *)to[i], (char *)from); + copy_v3_v3_uchar(to[i], from); i = !i; } } @@ -1049,7 +1049,7 @@ static void imb_stereo3d_read_interlace(Stereo3DData *s3d, enum eStereo3dInterla }; char i = (char) swap; for (x = 0; x < width; x++, from += 4, to[0] += 4, to[1] += 4) { - copy_v4_v4_char((char *)to[i], (char *)from); + copy_v4_v4_uchar(to[i], from); i = !i; } } @@ -1084,7 +1084,7 @@ static void imb_stereo3d_read_interlace(Stereo3DData *s3d, enum eStereo3dInterla }; char j = i; for (x = 0; x < width; x++, from += 3, to[0] += 3, to[1] += 3) { - copy_v3_v3_char((char *)to[j], (char *)from); + copy_v3_v3_uchar(to[j], from); j = !j; } i = !i; @@ -1100,7 +1100,7 @@ static void imb_stereo3d_read_interlace(Stereo3DData *s3d, enum eStereo3dInterla }; char j = i; for (x = 0; x < width; x++, from += 4, to[0] += 4, to[1] += 4) { - copy_v4_v4_char((char *)to[j], (char *)from); + copy_v4_v4_uchar(to[j], from); j = !j; } i = !i; diff --git a/source/blender/imbuf/intern/thumbs.c b/source/blender/imbuf/intern/thumbs.c index e7bec7e643c..95d061bcb75 100644 --- a/source/blender/imbuf/intern/thumbs.c +++ b/source/blender/imbuf/intern/thumbs.c @@ -217,7 +217,7 @@ static bool thumbhash_from_path(const char *UNUSED(path), ThumbSource source, ch } } -static int uri_from_filename(const char *path, char *uri) +static bool uri_from_filename(const char *path, char *uri) { char orig_uri[URI_MAX]; const char *dirstart = path; @@ -243,16 +243,9 @@ static int uri_from_filename(const char *path, char *uri) #else BLI_snprintf(orig_uri, URI_MAX, "file://%s", dirstart); #endif - -#ifdef WITH_ICONV - { - char uri_utf8[URI_MAX]; - escape_uri_string(orig_uri, uri_utf8, URI_MAX, UNSAFE_PATH); - BLI_string_to_utf8(uri_utf8, uri, NULL); - } -#else + escape_uri_string(orig_uri, uri, URI_MAX, UNSAFE_PATH); -#endif + return 1; } @@ -489,7 +482,9 @@ ImBuf *IMB_thumb_create(const char *path, ThumbSize size, ThumbSource source, Im char uri[URI_MAX] = ""; char thumb_name[40]; - uri_from_filename(path, uri); + if (!uri_from_filename(path, uri)) { + return NULL; + } thumbname_from_uri(uri, thumb_name, sizeof(thumb_name)); return thumb_create_ex(path, uri, thumb_name, false, THUMB_DEFAULT_HASH, NULL, NULL, size, source, img); diff --git a/source/blender/imbuf/intern/thumbs_blend.c b/source/blender/imbuf/intern/thumbs_blend.c index 17d9f3d0735..b5c6deb6b01 100644 --- a/source/blender/imbuf/intern/thumbs_blend.c +++ b/source/blender/imbuf/intern/thumbs_blend.c @@ -28,8 +28,6 @@ #include <stdlib.h> #include <string.h> -#include "zlib.h" - #include "BLI_utildefines.h" #include "BLI_endian_switch.h" #include "BLI_fileops.h" @@ -41,6 +39,8 @@ #include "BKE_global.h" #include "BKE_idcode.h" #include "BKE_icons.h" +#include "BKE_library.h" +#include "BKE_main.h" #include "DNA_ID.h" /* For preview images... */ @@ -48,97 +48,20 @@ #include "IMB_imbuf.h" #include "IMB_thumbs.h" -/* extracts the thumbnail from between the 'REND' and the 'GLOB' - * chunks of the header, don't use typical blend loader because its too slow */ - -static ImBuf *loadblend_thumb(gzFile gzfile) -{ - char buf[12]; - int bhead[24 / sizeof(int)]; /* max size on 64bit */ - char endian, pointer_size; - char endian_switch; - int sizeof_bhead; - - /* read the blend file header */ - if (gzread(gzfile, buf, 12) != 12) - return NULL; - if (!STREQLEN(buf, "BLENDER", 7)) - return NULL; - - if (buf[7] == '-') - pointer_size = 8; - else if (buf[7] == '_') - pointer_size = 4; - else - return NULL; - - sizeof_bhead = 16 + pointer_size; - - if (buf[8] == 'V') - endian = B_ENDIAN; /* big: PPC */ - else if (buf[8] == 'v') - endian = L_ENDIAN; /* little: x86 */ - else - return NULL; - - endian_switch = ((ENDIAN_ORDER != endian)) ? 1 : 0; - - while (gzread(gzfile, bhead, sizeof_bhead) == sizeof_bhead) { - if (endian_switch) - BLI_endian_switch_int32(&bhead[1]); /* length */ - - if (bhead[0] == REND) { - gzseek(gzfile, bhead[1], SEEK_CUR); /* skip to the next */ - } - else { - break; - } - } - - /* using 'TEST' since new names segfault when loading in old blenders */ - if (bhead[0] == TEST) { - ImBuf *img = NULL; - int size[2]; - - if (gzread(gzfile, size, sizeof(size)) != sizeof(size)) - return NULL; - - if (endian_switch) { - BLI_endian_switch_int32(&size[0]); - BLI_endian_switch_int32(&size[1]); - } - /* length */ - bhead[1] -= sizeof(int) * 2; - - /* inconsistent image size, quit early */ - if (bhead[1] != size[0] * size[1] * sizeof(int)) - return NULL; - - /* finally malloc and read the data */ - img = IMB_allocImBuf(size[0], size[1], 32, IB_rect | IB_metadata); - - if (gzread(gzfile, img->rect, bhead[1]) != bhead[1]) { - IMB_freeImBuf(img); - img = NULL; - } - - return img; - } - - return NULL; -} +#include "MEM_guardedalloc.h" ImBuf *IMB_thumb_load_blend(const char *blen_path, const char *blen_group, const char *blen_id) { + ImBuf *ima = NULL; + if (blen_group && blen_id) { LinkNode *ln, *names, *lp, *previews = NULL; struct BlendHandle *libfiledata = BLO_blendhandle_from_file(blen_path, NULL); - ImBuf *ima = NULL; int idcode = BKE_idcode_from_name(blen_group); int i, nprevs, nnames; if (libfiledata == NULL) { - return NULL; + return ima; } /* Note: we should handle all previews for a same group at once, would avoid reopening .blend file @@ -180,25 +103,19 @@ ImBuf *IMB_thumb_load_blend(const char *blen_path, const char *blen_group, const BLI_linklist_free(previews, BKE_previewimg_freefunc); BLI_linklist_free(names, free); - return ima; } else { - gzFile gzfile; - /* not necessarily a gzip */ - gzfile = BLI_gzopen(blen_path, "rb"); + BlendThumbnail *data; - if (NULL == gzfile) { - return NULL; - } - else { - ImBuf *img = loadblend_thumb(gzfile); - - /* read ok! */ - gzclose(gzfile); + data = BLO_thumbnail_from_file(blen_path); + ima = BKE_main_thumbnail_to_imbuf(NULL, data); - return img; + if (data) { + MEM_freeN(data); } } + + return ima; } /* add a fake passepartout overlay to a byte buffer, use for blend file thumbnails */ diff --git a/source/blender/makesdna/DNA_ID.h b/source/blender/makesdna/DNA_ID.h index 342245fa393..c2901b8b9a5 100644 --- a/source/blender/makesdna/DNA_ID.h +++ b/source/blender/makesdna/DNA_ID.h @@ -261,6 +261,8 @@ typedef struct PreviewImage { #define ID_BLEND_PATH(_bmain, _id) ((_id)->lib ? (_id)->lib->filepath : (_bmain)->name) +#define ID_MISSING(_id) (((_id)->flag & LIB_MISSING) != 0) + #ifdef GS # undef GS #endif @@ -280,6 +282,8 @@ enum { LIB_TESTIND = (LIB_NEED_EXPAND | LIB_INDIRECT), LIB_READ = 1 << 4, LIB_NEED_LINK = 1 << 5, + /* tag datablock as a place-holder (because the real one could not be linked from its library e.g.). */ + LIB_MISSING = 1 << 6, LIB_NEW = 1 << 8, LIB_FAKEUSER = 1 << 9, diff --git a/source/blender/makesdna/DNA_action_types.h b/source/blender/makesdna/DNA_action_types.h index b8688e5e12a..d574694c70d 100644 --- a/source/blender/makesdna/DNA_action_types.h +++ b/source/blender/makesdna/DNA_action_types.h @@ -198,7 +198,8 @@ typedef struct bPoseChannel { short agrp_index; /* index of action-group this bone belongs to (0 = default/no group) */ char constflag; /* for quick detecting which constraints affect this channel */ char selectflag; /* copy of bone flag, so you can work with library armatures, not for runtime use */ - char pad0[6]; + char drawflag; + char pad0[5]; struct Bone *bone; /* set on read file or rebuild pose */ struct bPoseChannel *parent; /* set on read file or rebuild pose */ @@ -212,6 +213,9 @@ typedef struct bPoseChannel { struct bPoseChannel *custom_tx; /* odd feature, display with another bones transform. * needed in rare cases for advanced rigs, * since the alternative is highly complicated - campbell */ + float custom_scale; + + char pad1[4]; /* transforms - written in by actions or transform */ float loc[3]; @@ -306,6 +310,14 @@ typedef enum ePchan_IkFlag { BONE_IK_NO_ZDOF_TEMP = (1 << 12) } ePchan_IkFlag; +/* PoseChannel->drawflag */ +typedef enum ePchan_DrawFlag { + PCHAN_DRAW_NO_CUSTOM_BONE_SIZE = (1 << 0), +} ePchan_DrawFlag; + +#define PCHAN_CUSTOM_DRAW_SIZE(pchan) \ + (pchan)->custom_scale * (((pchan)->drawflag & PCHAN_DRAW_NO_CUSTOM_BONE_SIZE) ? 1.0f : (pchan)->bone->length) + /* PoseChannel->rotmode and Object->rotmode */ typedef enum eRotationModes { /* quaternion rotations (default, and for older Blender versions) */ diff --git a/source/blender/makesdna/DNA_actuator_types.h b/source/blender/makesdna/DNA_actuator_types.h index 9af0c1dac10..59a058925a6 100644 --- a/source/blender/makesdna/DNA_actuator_types.h +++ b/source/blender/makesdna/DNA_actuator_types.h @@ -512,6 +512,7 @@ typedef struct bActuator { #define ACT_GAME_QUIT 3 #define ACT_GAME_SAVECFG 4 #define ACT_GAME_LOADCFG 5 +#define ACT_GAME_SCREENSHOT 6 /* visibilityact->flag */ /* Set means the object will become invisible */ diff --git a/source/blender/makesdna/DNA_image_types.h b/source/blender/makesdna/DNA_image_types.h index 6088dccd4e9..d112790eb47 100644 --- a/source/blender/makesdna/DNA_image_types.h +++ b/source/blender/makesdna/DNA_image_types.h @@ -55,7 +55,8 @@ typedef struct ImageUser { char ok; char multiview_eye; /* multiview current eye - for internal use of drawing routines */ - int passtype; + short pass; + short pad; short multi_index, view, layer; /* listbase indices, for menu browsing or retrieve buffer */ short flag; @@ -171,8 +172,8 @@ enum { IMA_IGNORE_ALPHA = (1 << 12), IMA_DEINTERLACE = (1 << 13), IMA_USE_VIEWS = (1 << 14), - IMA_IS_STEREO = (1 << 15), - IMA_IS_MULTIVIEW = (1 << 16), /* similar to stereo, but a more general case */ + // IMA_IS_STEREO = (1 << 15), /* deprecated */ + // IMA_IS_MULTIVIEW = (1 << 16), /* deprecated */ }; /* Image.tpageflag */ diff --git a/source/blender/makesdna/DNA_meshdata_types.h b/source/blender/makesdna/DNA_meshdata_types.h index b78cd65e913..621807d111c 100644 --- a/source/blender/makesdna/DNA_meshdata_types.h +++ b/source/blender/makesdna/DNA_meshdata_types.h @@ -71,7 +71,7 @@ typedef struct MVert { * at the moment alpha is abused for vertex painting and not used for transparency, note that red and blue are swapped */ typedef struct MCol { - char a, r, g, b; + unsigned char a, r, g, b; } MCol; /* new face structure, replaces MFace, which is now only used for storing tessellations.*/ @@ -224,7 +224,7 @@ enum { * \note red and blue are _not_ swapped, as they are with #MCol */ typedef struct MLoopCol { - char r, g, b, a; + unsigned char r, g, b, a; } MLoopCol; #define MESH_MLOOPCOL_FROM_MCOL(_mloopcol, _mcol) \ @@ -446,6 +446,16 @@ enum { /* number of tri's that make up this polygon once tessellated */ #define ME_POLY_TRI_TOT(mp) ((mp)->totloop - 2) +/** + * Check out-of-bounds material, note that this is nearly always prevented, + * yet its still possible in rare cases. + * So usage such as array lookup needs to check. + */ +#define ME_MAT_NR_TEST(mat_nr, totmat) \ + (CHECK_TYPE_ANY(mat_nr, short, const short), \ + CHECK_TYPE_ANY(totmat, short, const short), \ + (LIKELY(mat_nr < totmat) ? mat_nr : 0)) + /* mselect->type */ enum { ME_VSEL = 0, diff --git a/source/blender/makesdna/DNA_node_types.h b/source/blender/makesdna/DNA_node_types.h index 32f766ecae5..1176ce1c9e6 100644 --- a/source/blender/makesdna/DNA_node_types.h +++ b/source/blender/makesdna/DNA_node_types.h @@ -748,6 +748,8 @@ typedef struct NodeTexEnvironment { ImageUser iuser; int color_space; int projection; + int interpolation; + int pad; } NodeTexEnvironment; typedef struct NodeTexGradient { diff --git a/source/blender/makesdna/DNA_object_fluidsim.h b/source/blender/makesdna/DNA_object_fluidsim.h index aaebdf579f8..a714195dd5d 100644 --- a/source/blender/makesdna/DNA_object_fluidsim.h +++ b/source/blender/makesdna/DNA_object_fluidsim.h @@ -88,11 +88,6 @@ typedef struct FluidsimSettings { /* gravity strength */ float iniVelx, iniVely, iniVelz; - /* store pointer to original mesh (for replacing the current one) */ - struct Mesh *orgMesh; - /* a mesh to display the bounding box used for simulation */ - struct Mesh *meshBB; - /* store output path, and file prefix for baked fluid surface */ /* strlens; 256= FILE_MAXFILE, 768= FILE_MAXDIR */ char surfdataPath[1024]; diff --git a/source/blender/makesdna/DNA_object_types.h b/source/blender/makesdna/DNA_object_types.h index 3d3adec7aae..5ae82b9980e 100644 --- a/source/blender/makesdna/DNA_object_types.h +++ b/source/blender/makesdna/DNA_object_types.h @@ -200,7 +200,7 @@ typedef struct Object { /* did last modifier stack generation need mapping support? */ char lastNeedMapping; /* bool */ - char pad[5]; + char pad; /* dupli-frame settings */ int dupon, dupoff, dupsta, dupend; @@ -233,6 +233,8 @@ typedef struct Object { float step_height; float jump_speed; float fall_speed; + unsigned char max_jumps; + char pad2[3]; /** Collision mask settings */ unsigned short col_group, col_mask; @@ -258,7 +260,7 @@ typedef struct Object { short index; /* custom index, for renderpasses */ unsigned short actdef; /* current deformation group, note: index starts at 1 */ unsigned short actfmap; /* current face map, note: index starts at 1 */ - unsigned short pad2[3]; + unsigned short pad3[3]; float col[4]; /* object color */ int gameflag; diff --git a/source/blender/makesdna/DNA_outliner_types.h b/source/blender/makesdna/DNA_outliner_types.h index 53061b55e2d..984e3334414 100644 --- a/source/blender/makesdna/DNA_outliner_types.h +++ b/source/blender/makesdna/DNA_outliner_types.h @@ -56,7 +56,55 @@ typedef struct TreeStore { #define TSE_CHILDSEARCH 8 #define TSE_SEARCHMATCH 16 -/* TreeStoreElem types in BIF_outliner.h */ +/* TreeStoreElem->types */ +#define TSE_NLA 1 /* NO ID */ +#define TSE_NLA_ACTION 2 +#define TSE_DEFGROUP_BASE 3 +#define TSE_DEFGROUP 4 +#define TSE_BONE 5 +#define TSE_EBONE 6 +#define TSE_CONSTRAINT_BASE 7 +#define TSE_CONSTRAINT 8 +#define TSE_MODIFIER_BASE 9 +#define TSE_MODIFIER 10 +#define TSE_LINKED_OB 11 +/* #define TSE_SCRIPT_BASE 12 */ /* UNUSED */ +#define TSE_POSE_BASE 13 +#define TSE_POSE_CHANNEL 14 +#define TSE_ANIM_DATA 15 +#define TSE_DRIVER_BASE 16 /* NO ID */ +/* #define TSE_DRIVER 17 */ /* UNUSED */ + +#define TSE_PROXY 18 +#define TSE_R_LAYER_BASE 19 +#define TSE_R_LAYER 20 +#define TSE_R_PASS 21 +#define TSE_LINKED_MAT 22 +/* NOTE, is used for light group */ +#define TSE_LINKED_LAMP 23 +#define TSE_POSEGRP_BASE 24 +#define TSE_POSEGRP 25 +#define TSE_SEQUENCE 26 /* NO ID */ +#define TSE_SEQ_STRIP 27 /* NO ID */ +#define TSE_SEQUENCE_DUP 28 /* NO ID */ +#define TSE_LINKED_PSYS 29 +#define TSE_RNA_STRUCT 30 /* NO ID */ +#define TSE_RNA_PROPERTY 31 /* NO ID */ +#define TSE_RNA_ARRAY_ELEM 32 /* NO ID */ +#define TSE_NLA_TRACK 33 /* NO ID */ +#define TSE_KEYMAP 34 /* NO ID */ +#define TSE_KEYMAP_ITEM 35 /* NO ID */ +#define TSE_ID_BASE 36 /* NO ID */ +#define TSE_GP_LAYER 37 /* NO ID */ + + +/* Check whether given TreeStoreElem should have a real ID in its ->id member. */ +#define TSE_IS_REAL_ID(_tse) \ + (!ELEM((_tse)->type, TSE_NLA, TSE_NLA_TRACK, TSE_DRIVER_BASE, \ + TSE_SEQUENCE, TSE_SEQ_STRIP, TSE_SEQUENCE_DUP, \ + TSE_RNA_STRUCT, TSE_RNA_PROPERTY, TSE_RNA_ARRAY_ELEM, \ + TSE_KEYMAP, TSE_KEYMAP_ITEM, TSE_ID_BASE, TSE_GP_LAYER)) + #endif diff --git a/source/blender/makesdna/DNA_sequence_types.h b/source/blender/makesdna/DNA_sequence_types.h index 3f3bfdfe1b1..69e7fb43fb6 100644 --- a/source/blender/makesdna/DNA_sequence_types.h +++ b/source/blender/makesdna/DNA_sequence_types.h @@ -275,9 +275,10 @@ typedef struct TextVars { char text[512]; int text_size; float loc[2]; - short flag; - char align; - char pad; + float wrap_width; + char flag; + char align, align_y; + char pad[5]; } TextVars; /* TextVars.flag */ @@ -287,9 +288,16 @@ enum { /* TextVars.align */ enum { - SEQ_TEXT_ALIGN_LEFT = 0, - SEQ_TEXT_ALIGN_CENTER = 1, - SEQ_TEXT_ALIGN_RIGHT = 2, + SEQ_TEXT_ALIGN_X_LEFT = 0, + SEQ_TEXT_ALIGN_X_CENTER = 1, + SEQ_TEXT_ALIGN_X_RIGHT = 2, +}; + +/* TextVars.align_y */ +enum { + SEQ_TEXT_ALIGN_Y_TOP = 0, + SEQ_TEXT_ALIGN_Y_CENTER = 1, + SEQ_TEXT_ALIGN_Y_BOTTOM = 2, }; /* ***************** Sequence modifiers ****************** */ diff --git a/source/blender/makesdna/DNA_userdef_types.h b/source/blender/makesdna/DNA_userdef_types.h index f10d4131162..e2c7478f5d3 100644 --- a/source/blender/makesdna/DNA_userdef_types.h +++ b/source/blender/makesdna/DNA_userdef_types.h @@ -74,7 +74,8 @@ typedef struct uiFontStyle { short uifont_id; /* saved in file, 0 is default */ short points; /* actual size depends on 'global' dpi */ short kerning; /* unfitted or default kerning value. */ - char pad[6]; + char word_wrap; /* enable word-wrap when drawing */ + char pad[5]; short italic, bold; /* style hint */ short shadow; /* value is amount of pixels blur */ short shadx, shady; /* shadow offset in pixels */ @@ -818,19 +819,23 @@ typedef enum eTimecodeStyles { * with '+' to denote the frames * i.e. HH:MM:SS+FF, MM:SS+FF, SS+FF, or MM:SS */ - USER_TIMECODE_MINIMAL = 0, - + USER_TIMECODE_MINIMAL = 0, + /* reduced SMPTE - (HH:)MM:SS:FF */ - USER_TIMECODE_SMPTE_MSF = 1, - + USER_TIMECODE_SMPTE_MSF = 1, + /* full SMPTE - HH:MM:SS:FF */ - USER_TIMECODE_SMPTE_FULL = 2, - + USER_TIMECODE_SMPTE_FULL = 2, + /* milliseconds for sub-frames - HH:MM:SS.sss */ - USER_TIMECODE_MILLISECONDS = 3, - + USER_TIMECODE_MILLISECONDS = 3, + /* seconds only */ - USER_TIMECODE_SECONDS_ONLY = 4, + USER_TIMECODE_SECONDS_ONLY = 4, + + /* Private (not exposed as generic choices) options. */ + /* milliseconds for sub-frames , SubRip format- HH:MM:SS,sss */ + USER_TIMECODE_SUBRIP = 100, } eTimecodeStyles; /* theme drawtypes */ diff --git a/source/blender/makesdna/intern/CMakeLists.txt b/source/blender/makesdna/intern/CMakeLists.txt index be097c0e51e..52487edfd2b 100644 --- a/source/blender/makesdna/intern/CMakeLists.txt +++ b/source/blender/makesdna/intern/CMakeLists.txt @@ -57,7 +57,7 @@ add_executable(makesdna ${SRC} ${SRC_DNA_INC}) # Output dna.c add_custom_command( OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/dna.c - COMMAND ${CMAKE_BINARY_DIR}/bin/${CMAKE_CFG_INTDIR}/makesdna ${CMAKE_CURRENT_BINARY_DIR}/dna.c ${CMAKE_SOURCE_DIR}/source/blender/makesdna/ + COMMAND "$<TARGET_FILE:makesdna>" ${CMAKE_CURRENT_BINARY_DIR}/dna.c ${CMAKE_SOURCE_DIR}/source/blender/makesdna/ DEPENDS makesdna ) diff --git a/source/blender/makesdna/intern/dna_genfile.c b/source/blender/makesdna/intern/dna_genfile.c index 499c430306b..16fbcbebe50 100644 --- a/source/blender/makesdna/intern/dna_genfile.c +++ b/source/blender/makesdna/intern/dna_genfile.c @@ -311,7 +311,21 @@ int DNA_struct_find_nr(SDNA *sdna, const char *str) } #ifdef WITH_DNA_GHASH - return (intptr_t)BLI_ghash_lookup(sdna->structs_map, str) - 1; + { + void **index_p; + int a; + + index_p = BLI_ghash_lookup_p(sdna->structs_map, str); + + if (index_p) { + a = GET_INT_FROM_POINTER(*index_p); + sdna->lastfind = a; + } + else { + a = -1; + } + return a; + } #else { int a; @@ -525,7 +539,7 @@ static void init_structDNA(SDNA *sdna, bool do_endian_swap) for (nr = 0; nr < sdna->nr_structs; nr++) { sp = sdna->structs[nr]; - BLI_ghash_insert(sdna->structs_map, sdna->types[sp[0]], SET_INT_IN_POINTER(nr + 1)); + BLI_ghash_insert(sdna->structs_map, sdna->types[sp[0]], SET_INT_IN_POINTER(nr)); } #endif } diff --git a/source/blender/makesrna/SConscript b/source/blender/makesrna/SConscript index 260784788db..1ed4982cf94 100644 --- a/source/blender/makesrna/SConscript +++ b/source/blender/makesrna/SConscript @@ -148,6 +148,9 @@ if env['WITH_BF_OPENSUBDIV']: incs += ' #/intern/opensubdiv' defs.append('WITH_OPENSUBDIV') +if env['WITH_BF_AUDASPACE']: + defs.append('WITH_AUDASPACE') + if env['OURPLATFORM'] == 'linux': cflags='-pthread' diff --git a/source/blender/makesrna/intern/CMakeLists.txt b/source/blender/makesrna/intern/CMakeLists.txt index b34763e0ae8..987b594421f 100644 --- a/source/blender/makesrna/intern/CMakeLists.txt +++ b/source/blender/makesrna/intern/CMakeLists.txt @@ -350,7 +350,7 @@ target_link_libraries(makesrna bf_dna_blenlib) # note (linux only): with crashes try add this after COMMAND: valgrind --leak-check=full --track-origins=yes add_custom_command( OUTPUT ${GENSRC} - COMMAND ${CMAKE_BINARY_DIR}/bin/${CMAKE_CFG_INTDIR}/makesrna ${CMAKE_CURRENT_BINARY_DIR}/ + COMMAND "$<TARGET_FILE:makesrna>" ${CMAKE_CURRENT_BINARY_DIR}/ DEPENDS makesrna ) diff --git a/source/blender/makesrna/intern/SConscript b/source/blender/makesrna/intern/SConscript index e8842ae2943..8307e4cec6f 100644 --- a/source/blender/makesrna/intern/SConscript +++ b/source/blender/makesrna/intern/SConscript @@ -163,6 +163,9 @@ if env['WITH_BF_OPENSUBDIV']: defs.append('WITH_OPENSUBDIV') incs += ' #intern/opensubdiv' +if env['WITH_BF_AUDASPACE']: + defs.append('WITH_AUDASPACE') + if env['OURPLATFORM'] == 'linux': cflags='-pthread' diff --git a/source/blender/makesrna/intern/makesrna.c b/source/blender/makesrna/intern/makesrna.c index 0f00dd7a586..e887397f4d7 100644 --- a/source/blender/makesrna/intern/makesrna.c +++ b/source/blender/makesrna/intern/makesrna.c @@ -1079,11 +1079,18 @@ static char *rna_def_property_length_func(FILE *f, StructRNA *srna, PropertyRNA fprintf(f, " return %s(ptr);\n", manualfunc); } else { - rna_print_data_get(f, dp); + if (dp->dnaarraylength <= 1 || dp->dnalengthname) + rna_print_data_get(f, dp); + + if (dp->dnaarraylength > 1) + fprintf(f, " return "); + else + fprintf(f, " return (data->%s == NULL) ? 0 : ", dp->dnaname); + if (dp->dnalengthname) - fprintf(f, " return (data->%s == NULL) ? 0 : data->%s;\n", dp->dnaname, dp->dnalengthname); + fprintf(f, "data->%s;\n", dp->dnalengthname); else - fprintf(f, " return (data->%s == NULL) ? 0 : %d;\n", dp->dnaname, dp->dnalengthfixed); + fprintf(f, "%d;\n", dp->dnalengthfixed); } fprintf(f, "}\n\n"); } diff --git a/source/blender/makesrna/intern/rna_ID.c b/source/blender/makesrna/intern/rna_ID.c index 19b5a1b8219..f0119c7d665 100644 --- a/source/blender/makesrna/intern/rna_ID.c +++ b/source/blender/makesrna/intern/rna_ID.c @@ -126,7 +126,7 @@ static int rna_ID_name_editable(PointerRNA *ptr) return false; } - return true; + return PROP_EDITABLE; } short RNA_type_to_ID_code(StructRNA *type) @@ -484,6 +484,7 @@ static void rna_ImagePreview_size_set(PointerRNA *ptr, const int *values, enum e prv_img->flag[size] |= (PRV_CHANGED | PRV_USER_EDITED); } + static int rna_ImagePreview_pixels_get_length(PointerRNA *ptr, int length[RNA_MAX_ARRAY_DIMENSION], enum eIconSizes size) { ID *id = ptr->id.data; @@ -527,6 +528,70 @@ static void rna_ImagePreview_pixels_set(PointerRNA *ptr, const int *values, enum prv_img->flag[size] |= PRV_USER_EDITED; } + +static int rna_ImagePreview_pixels_float_get_length( + PointerRNA *ptr, int length[RNA_MAX_ARRAY_DIMENSION], enum eIconSizes size) +{ + ID *id = ptr->id.data; + PreviewImage *prv_img = (PreviewImage *)ptr->data; + + BLI_assert(sizeof(unsigned int) == 4); + + if (id != NULL) { + BLI_assert(prv_img == BKE_previewimg_id_ensure(id)); + } + + BKE_previewimg_ensure(prv_img, size); + + length[0] = prv_img->w[size] * prv_img->h[size] * 4; + + return length[0]; +} + +static void rna_ImagePreview_pixels_float_get(PointerRNA *ptr, float *values, enum eIconSizes size) +{ + ID *id = ptr->id.data; + PreviewImage *prv_img = (PreviewImage *)ptr->data; + + unsigned char *data = (unsigned char *)prv_img->rect[size]; + const size_t len = prv_img->w[size] * prv_img->h[size] * 4; + size_t i; + + BLI_assert(sizeof(unsigned int) == 4); + + if (id != NULL) { + BLI_assert(prv_img == BKE_previewimg_id_ensure(id)); + } + + BKE_previewimg_ensure(prv_img, size); + + for (i = 0; i < len; i++) { + values[i] = data[i] * (1.0f / 255.0f); + } +} + +static void rna_ImagePreview_pixels_float_set(PointerRNA *ptr, const float *values, enum eIconSizes size) +{ + ID *id = ptr->id.data; + PreviewImage *prv_img = (PreviewImage *)ptr->data; + + unsigned char *data = (unsigned char *)prv_img->rect[size]; + const size_t len = prv_img->w[size] * prv_img->h[size] * 4; + size_t i; + + BLI_assert(sizeof(unsigned int) == 4); + + if (id != NULL) { + BLI_assert(prv_img == BKE_previewimg_id_ensure(id)); + } + + for (i = 0; i < len; i++) { + data[i] = FTOCHAR(values[i]); + } + prv_img->flag[size] |= PRV_USER_EDITED; +} + + static void rna_ImagePreview_is_image_custom_set(PointerRNA *ptr, int value) { rna_ImagePreview_is_custom_set(ptr, value, ICON_SIZE_PREVIEW); @@ -557,6 +622,22 @@ static void rna_ImagePreview_image_pixels_set(PointerRNA *ptr, const int *values rna_ImagePreview_pixels_set(ptr, values, ICON_SIZE_PREVIEW); } +static int rna_ImagePreview_image_pixels_float_get_length(PointerRNA *ptr, int length[RNA_MAX_ARRAY_DIMENSION]) +{ + return rna_ImagePreview_pixels_float_get_length(ptr, length, ICON_SIZE_PREVIEW); +} + +static void rna_ImagePreview_image_pixels_float_get(PointerRNA *ptr, float *values) +{ + rna_ImagePreview_pixels_float_get(ptr, values, ICON_SIZE_PREVIEW); +} + +static void rna_ImagePreview_image_pixels_float_set(PointerRNA *ptr, const float *values) +{ + rna_ImagePreview_pixels_float_set(ptr, values, ICON_SIZE_PREVIEW); +} + + static void rna_ImagePreview_is_icon_custom_set(PointerRNA *ptr, int value) { rna_ImagePreview_is_custom_set(ptr, value, ICON_SIZE_ICON); @@ -587,6 +668,22 @@ static void rna_ImagePreview_icon_pixels_set(PointerRNA *ptr, const int *values) rna_ImagePreview_pixels_set(ptr, values, ICON_SIZE_ICON); } +static int rna_ImagePreview_icon_pixels_float_get_length(PointerRNA *ptr, int length[RNA_MAX_ARRAY_DIMENSION]) +{ + return rna_ImagePreview_pixels_float_get_length(ptr, length, ICON_SIZE_ICON); +} + +static void rna_ImagePreview_icon_pixels_float_get(PointerRNA *ptr, float *values) +{ + rna_ImagePreview_pixels_float_get(ptr, values, ICON_SIZE_ICON); +} + +static void rna_ImagePreview_icon_pixels_float_set(PointerRNA *ptr, const float *values) +{ + rna_ImagePreview_pixels_float_set(ptr, values, ICON_SIZE_ICON); +} + + static int rna_ImagePreview_icon_id_get(PointerRNA *ptr) { /* Using a callback here allows us to only generate icon matching that preview when icon_id is requested. */ @@ -754,6 +851,15 @@ static void rna_def_image_preview(BlenderRNA *brna) RNA_def_property_dynamic_array_funcs(prop, "rna_ImagePreview_image_pixels_get_length"); RNA_def_property_int_funcs(prop, "rna_ImagePreview_image_pixels_get", "rna_ImagePreview_image_pixels_set", NULL); + prop = RNA_def_property(srna, "image_pixels_float", PROP_FLOAT, PROP_NONE); + RNA_def_property_flag(prop, PROP_DYNAMIC); + RNA_def_property_multi_array(prop, 1, NULL); + RNA_def_property_ui_text(prop, "Float Image Pixels", + "Image pixels components, as floats (RGBA concatenated values)"); + RNA_def_property_dynamic_array_funcs(prop, "rna_ImagePreview_image_pixels_float_get_length"); + RNA_def_property_float_funcs(prop, "rna_ImagePreview_image_pixels_float_get", + "rna_ImagePreview_image_pixels_float_set", NULL); + prop = RNA_def_property(srna, "is_icon_custom", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag[ICON_SIZE_ICON]", PRV_USER_EDITED); @@ -773,6 +879,14 @@ static void rna_def_image_preview(BlenderRNA *brna) RNA_def_property_dynamic_array_funcs(prop, "rna_ImagePreview_icon_pixels_get_length"); RNA_def_property_int_funcs(prop, "rna_ImagePreview_icon_pixels_get", "rna_ImagePreview_icon_pixels_set", NULL); + prop = RNA_def_property(srna, "icon_pixels_float", PROP_FLOAT, PROP_NONE); + RNA_def_property_flag(prop, PROP_DYNAMIC); + RNA_def_property_multi_array(prop, 1, NULL); + RNA_def_property_ui_text(prop, "Float Icon Pixels", "Icon pixels components, as floats (RGBA concatenated values)"); + RNA_def_property_dynamic_array_funcs(prop, "rna_ImagePreview_icon_pixels_float_get_length"); + RNA_def_property_float_funcs(prop, "rna_ImagePreview_icon_pixels_float_get", + "rna_ImagePreview_icon_pixels_float_set", NULL); + prop = RNA_def_int(srna, "icon_id", 0, INT_MIN, INT_MAX, "Icon ID", "Unique integer identifying this preview as an icon (zero means invalid)", INT_MIN, INT_MAX); RNA_def_property_clear_flag(prop, PROP_EDITABLE); diff --git a/source/blender/makesrna/intern/rna_access.c b/source/blender/makesrna/intern/rna_access.c index 41bb0386ce6..b41568d0aba 100644 --- a/source/blender/makesrna/intern/rna_access.c +++ b/source/blender/makesrna/intern/rna_access.c @@ -1570,7 +1570,9 @@ bool RNA_property_editable(PointerRNA *ptr, PropertyRNA *prop) prop = rna_ensure_property(prop); flag = prop->editable ? prop->editable(ptr) : prop->flag; - return (flag & PROP_EDITABLE) && (!id || !id->lib || (prop->flag & PROP_LIB_EXCEPTION)); + return ((flag & PROP_EDITABLE) && + (flag & PROP_REGISTER) == 0 && + (!id || !id->lib || (prop->flag & PROP_LIB_EXCEPTION))); } bool RNA_property_editable_flag(PointerRNA *ptr, PropertyRNA *prop) @@ -4720,6 +4722,7 @@ char *RNA_path_full_struct_py(struct PointerRNA *ptr) char *RNA_path_full_property_py(PointerRNA *ptr, PropertyRNA *prop, int index) { char *id_path; + const char *data_delim; char *data_path; char *ret; @@ -4733,13 +4736,15 @@ char *RNA_path_full_property_py(PointerRNA *ptr, PropertyRNA *prop, int index) data_path = RNA_path_from_ID_to_property(ptr, prop); + data_delim = (data_path && data_path[0] == '[') ? "" : "."; + if ((index == -1) || (RNA_property_array_check(prop) == false)) { - ret = BLI_sprintfN("%s.%s", - id_path, data_path); + ret = BLI_sprintfN("%s%s%s", + id_path, data_delim, data_path); } else { - ret = BLI_sprintfN("%s.%s[%d]", - id_path, data_path, index); + ret = BLI_sprintfN("%s%s%s[%d]", + id_path, data_delim, data_path, index); } MEM_freeN(id_path); if (data_path) { diff --git a/source/blender/makesrna/intern/rna_actuator.c b/source/blender/makesrna/intern/rna_actuator.c index 5dba21dda40..b425a454d33 100644 --- a/source/blender/makesrna/intern/rna_actuator.c +++ b/source/blender/makesrna/intern/rna_actuator.c @@ -1706,6 +1706,7 @@ static void rna_def_game_actuator(BlenderRNA *brna) {ACT_GAME_QUIT, "QUIT", 0, "Quit Game", ""}, {ACT_GAME_SAVECFG, "SAVECFG", 0, "Save bge.logic.globalDict", ""}, {ACT_GAME_LOADCFG, "LOADCFG", 0, "Load bge.logic.globalDict", ""}, + {ACT_GAME_SCREENSHOT, "SCREENSHOT", 0, "Screenshot", ""}, {0, NULL, 0, NULL, NULL} }; @@ -1722,8 +1723,8 @@ static void rna_def_game_actuator(BlenderRNA *brna) /* ACT_GAME_LOAD */ prop = RNA_def_property(srna, "filename", PROP_STRING, PROP_FILEPATH); RNA_def_property_ui_text(prop, "File", - "Load this blend file, use the \"//\" prefix for a path relative to the current " - "blend file"); + "The file to use, depending on the mode (e.g. the blend file to load or a destination " + "for saving a screenshot) - use the \"//\" prefix for a relative path"); RNA_def_property_update(prop, NC_LOGIC, NULL); /*XXX to do: an operator that calls file_browse with relative_path on and blender filtering active */ } diff --git a/source/blender/makesrna/intern/rna_animation.c b/source/blender/makesrna/intern/rna_animation.c index ac30c615438..165c969ebc2 100644 --- a/source/blender/makesrna/intern/rna_animation.c +++ b/source/blender/makesrna/intern/rna_animation.c @@ -97,7 +97,7 @@ static int rna_AnimData_action_editable(PointerRNA *ptr) if ((adt->flag & ADT_NLA_EDIT_ON) || (adt->actstrip) || (adt->tmpact)) return 0; else - return 1; + return PROP_EDITABLE; } static void rna_AnimData_action_set(PointerRNA *ptr, PointerRNA value) @@ -381,7 +381,7 @@ static int rna_KeyingSet_active_ksPath_editable(PointerRNA *ptr) KeyingSet *ks = (KeyingSet *)ptr->data; /* only editable if there are some paths to change to */ - return (BLI_listbase_is_empty(&ks->paths) == false); + return (BLI_listbase_is_empty(&ks->paths) == false) ? PROP_EDITABLE : 0; } static PointerRNA rna_KeyingSet_active_ksPath_get(PointerRNA *ptr) diff --git a/source/blender/makesrna/intern/rna_armature.c b/source/blender/makesrna/intern/rna_armature.c index 93e5ceaa229..3e41ea4134c 100644 --- a/source/blender/makesrna/intern/rna_armature.c +++ b/source/blender/makesrna/intern/rna_armature.c @@ -746,7 +746,7 @@ static void rna_def_edit_bone(BlenderRNA *brna) prop = RNA_def_property(srna, "roll", PROP_FLOAT, PROP_ANGLE); RNA_def_property_float_sdna(prop, NULL, "roll"); - RNA_def_property_ui_range(prop, -M_PI * 2, M_PI * 2, 0.1, 2); + RNA_def_property_ui_range(prop, -M_PI * 2, M_PI * 2, 10, 2); RNA_def_property_ui_text(prop, "Roll", "Bone rotation around head-tail axis"); RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); RNA_def_property_update(prop, 0, "rna_Armature_editbone_transform_update"); diff --git a/source/blender/makesrna/intern/rna_brush.c b/source/blender/makesrna/intern/rna_brush.c index 2c69331f50a..93cbd5fa246 100644 --- a/source/blender/makesrna/intern/rna_brush.c +++ b/source/blender/makesrna/intern/rna_brush.c @@ -510,7 +510,7 @@ static EnumPropertyItem *rna_Brush_direction_itemf(bContext *C, PointerRNA *ptr, Brush *me = (Brush *)(ptr->data); switch (mode) { - case PAINT_SCULPT: + case ePaintSculpt: switch (me->sculpt_tool) { case SCULPT_TOOL_DRAW: case SCULPT_TOOL_CREASE: @@ -550,8 +550,8 @@ static EnumPropertyItem *rna_Brush_direction_itemf(bContext *C, PointerRNA *ptr, } break; - case PAINT_TEXTURE_2D: - case PAINT_TEXTURE_PROJECTIVE: + case ePaintTexture2D: + case ePaintTextureProjective: switch (me->imagepaint_tool) { case PAINT_TOOL_SOFTEN: return prop_soften_sharpen_items; @@ -581,9 +581,9 @@ static EnumPropertyItem *rna_Brush_stroke_itemf(bContext *C, PointerRNA *UNUSED( }; switch (mode) { - case PAINT_SCULPT: - case PAINT_TEXTURE_2D: - case PAINT_TEXTURE_PROJECTIVE: + case ePaintSculpt: + case ePaintTexture2D: + case ePaintTextureProjective: return sculpt_stroke_method_items; default: diff --git a/source/blender/makesrna/intern/rna_constraint.c b/source/blender/makesrna/intern/rna_constraint.c index 6dac2e27f9c..860ed5e49ab 100644 --- a/source/blender/makesrna/intern/rna_constraint.c +++ b/source/blender/makesrna/intern/rna_constraint.c @@ -412,6 +412,7 @@ static void rna_Constraint_followTrack_camera_set(PointerRNA *ptr, PointerRNA va if (ob) { if (ob->type == OB_CAMERA && ob != (Object *)ptr->id.data) { data->camera = ob; + id_lib_extern((ID *)ob); } } else { @@ -428,6 +429,7 @@ static void rna_Constraint_followTrack_depthObject_set(PointerRNA *ptr, PointerR if (ob) { if (ob->type == OB_MESH && ob != (Object *)ptr->id.data) { data->depth_ob = ob; + id_lib_extern((ID *)ob); } } else { @@ -457,6 +459,7 @@ static void rna_Constraint_objectSolver_camera_set(PointerRNA *ptr, PointerRNA v if (ob) { if (ob->type == OB_CAMERA && ob != (Object *)ptr->id.data) { data->camera = ob; + id_lib_extern((ID *)ob); } } else { diff --git a/source/blender/makesrna/intern/rna_curve.c b/source/blender/makesrna/intern/rna_curve.c index cb577c9c97d..65175e37518 100644 --- a/source/blender/makesrna/intern/rna_curve.c +++ b/source/blender/makesrna/intern/rna_curve.c @@ -385,6 +385,7 @@ static void rna_Curve_bevelObject_set(PointerRNA *ptr, PointerRNA value) /* set as bevobj, there could be infinity loop in displist calculation */ if (ob->type == OB_CURVE && ob->data != cu) { cu->bevobj = ob; + id_lib_extern((ID *)ob); } } else { @@ -427,6 +428,7 @@ static void rna_Curve_taperObject_set(PointerRNA *ptr, PointerRNA value) /* set as bevobj, there could be infinity loop in displist calculation */ if (ob->type == OB_CURVE && ob->data != cu) { cu->taperobj = ob; + id_lib_extern((ID *)ob); } } else { @@ -747,11 +749,12 @@ static int rna_Curve_is_editmode_get(PointerRNA *ptr) #else +static const float tilt_limit = DEG2RADF(21600.0f); + static void rna_def_bpoint(BlenderRNA *brna) { StructRNA *srna; PropertyRNA *prop; - const float tilt_limit = DEG2RADF(21600.0f); srna = RNA_def_struct(brna, "SplinePoint", NULL); RNA_def_struct_sdna(srna, "BPoint"); @@ -785,7 +788,7 @@ static void rna_def_bpoint(BlenderRNA *brna) prop = RNA_def_property(srna, "tilt", PROP_FLOAT, PROP_ANGLE); RNA_def_property_float_sdna(prop, NULL, "alfa"); RNA_def_property_range(prop, -tilt_limit, tilt_limit); - RNA_def_property_ui_range(prop, -tilt_limit, tilt_limit, 0.1, 3); + RNA_def_property_ui_range(prop, -tilt_limit, tilt_limit, 10, 3); RNA_def_property_ui_text(prop, "Tilt", "Tilt in 3D View"); RNA_def_property_update(prop, 0, "rna_Curve_update_data"); @@ -872,7 +875,8 @@ static void rna_def_beztriple(BlenderRNA *brna) /* Number values */ prop = RNA_def_property(srna, "tilt", PROP_FLOAT, PROP_ANGLE); RNA_def_property_float_sdna(prop, NULL, "alfa"); - /*RNA_def_property_range(prop, -FLT_MAX, FLT_MAX);*/ + RNA_def_property_range(prop, -tilt_limit, tilt_limit); + RNA_def_property_ui_range(prop, -tilt_limit, tilt_limit, 10, 3); RNA_def_property_ui_text(prop, "Tilt", "Tilt in 3D View"); RNA_def_property_update(prop, 0, "rna_Curve_update_data"); diff --git a/source/blender/makesrna/intern/rna_define.c b/source/blender/makesrna/intern/rna_define.c index 95bd4bca8e6..3b01305110c 100644 --- a/source/blender/makesrna/intern/rna_define.c +++ b/source/blender/makesrna/intern/rna_define.c @@ -1314,8 +1314,10 @@ void RNA_def_property_ui_icon(PropertyRNA *prop, int icon, bool consecutive) /** * The values hare are a little confusing: * - * \param step For floats this is (step / 100), why /100? - nobody knows. - * for int's, whole values are used. + * \param step: Used as the value to increase/decrease when clicking on number buttons, + * \as well as scaling mouse input for click-dragging number buttons. + * For floats this is (step * UI_PRECISION_FLOAT_SCALE), why? - nobody knows. + * For ints, whole values are used. * * \param precision The number of zeros to show * (as a whole number - common range is 1 - 6), see PRECISION_FLOAT_MAX @@ -2857,7 +2859,7 @@ PropertyRNA *RNA_def_float_rotation(StructOrFunctionRNA *cont_, const char *iden ASSERT_SOFT_HARD_LIMITS; - prop = RNA_def_property(cont, identifier, PROP_FLOAT, (len != 0) ? PROP_EULER : PROP_ANGLE); + prop = RNA_def_property(cont, identifier, PROP_FLOAT, (len >= 3) ? PROP_EULER : PROP_ANGLE); if (len != 0) { RNA_def_property_array(prop, len); if (default_value) RNA_def_property_float_array_default(prop, default_value); @@ -2868,7 +2870,7 @@ PropertyRNA *RNA_def_float_rotation(StructOrFunctionRNA *cont_, const char *iden } if (hardmin != hardmax) RNA_def_property_range(prop, hardmin, hardmax); RNA_def_property_ui_text(prop, ui_name, ui_description); - RNA_def_property_ui_range(prop, softmin, softmax, 1, 3); + RNA_def_property_ui_range(prop, softmin, softmax, 10, 3); return prop; } diff --git a/source/blender/makesrna/intern/rna_fluidsim.c b/source/blender/makesrna/intern/rna_fluidsim.c index 01feb3cb748..16e0f17eac5 100644 --- a/source/blender/makesrna/intern/rna_fluidsim.c +++ b/source/blender/makesrna/intern/rna_fluidsim.c @@ -343,12 +343,12 @@ static void rna_def_fluidsim_domain(BlenderRNA *brna) prop = RNA_def_property(srna, "start_time", PROP_FLOAT, PROP_TIME); RNA_def_property_float_sdna(prop, NULL, "animStart"); - RNA_def_property_range(prop, 0, 100); + RNA_def_property_range(prop, 0, FLT_MAX); RNA_def_property_ui_text(prop, "Start Time", "Simulation time of the first blender frame (in seconds)"); prop = RNA_def_property(srna, "end_time", PROP_FLOAT, PROP_TIME); RNA_def_property_float_sdna(prop, NULL, "animEnd"); - RNA_def_property_range(prop, 0, 100); + RNA_def_property_range(prop, 0, FLT_MAX); RNA_def_property_ui_text(prop, "End Time", "Simulation time of the last blender frame (in seconds)"); prop = RNA_def_property(srna, "frame_offset", PROP_INT, PROP_NONE); @@ -627,12 +627,12 @@ static void rna_def_fluidsim_control(BlenderRNA *brna) prop = RNA_def_property(srna, "start_time", PROP_FLOAT, PROP_TIME); RNA_def_property_float_sdna(prop, NULL, "cpsTimeStart"); - RNA_def_property_range(prop, 0.0, 100.0); + RNA_def_property_range(prop, 0.0, FLT_MAX); RNA_def_property_ui_text(prop, "Start Time", "Time when the control particles are activated"); prop = RNA_def_property(srna, "end_time", PROP_FLOAT, PROP_TIME); RNA_def_property_float_sdna(prop, NULL, "cpsTimeEnd"); - RNA_def_property_range(prop, 0.0, 100.0); + RNA_def_property_range(prop, 0.0, FLT_MAX); RNA_def_property_ui_text(prop, "End Time", "Time when the control particles are deactivated"); prop = RNA_def_property(srna, "attraction_strength", PROP_FLOAT, PROP_NONE); diff --git a/source/blender/makesrna/intern/rna_gpencil.c b/source/blender/makesrna/intern/rna_gpencil.c index 333220146d6..80a52a0a3d1 100644 --- a/source/blender/makesrna/intern/rna_gpencil.c +++ b/source/blender/makesrna/intern/rna_gpencil.c @@ -73,7 +73,7 @@ static int rna_GPencilLayer_active_frame_editable(PointerRNA *ptr) if (gpl->flag & GP_LAYER_LOCKED) return 0; else - return 1; + return PROP_EDITABLE; } static void rna_GPencilLayer_line_width_range(PointerRNA *ptr, int *min, int *max, diff --git a/source/blender/makesrna/intern/rna_image.c b/source/blender/makesrna/intern/rna_image.c index 0d0b440ec08..64b4d17b17d 100644 --- a/source/blender/makesrna/intern/rna_image.c +++ b/source/blender/makesrna/intern/rna_image.c @@ -78,6 +78,16 @@ static void rna_Image_animated_update(Main *UNUSED(bmain), Scene *UNUSED(scene), } } +static int rna_Image_is_stereo_3d_get(PointerRNA *ptr) +{ + return BKE_image_is_stereo((Image *)ptr->data); +} + +static int rna_Image_is_multiview_get(PointerRNA *ptr) +{ + return BKE_image_is_multiview((Image *)ptr->data); +} + static int rna_Image_dirty_get(PointerRNA *ptr) { return BKE_image_is_dirty((Image *)ptr->data); @@ -539,6 +549,11 @@ static void rna_def_imageuser(BlenderRNA *brna) RNA_def_property_clear_flag(prop, PROP_EDITABLE); /* image_multi_cb */ RNA_def_property_ui_text(prop, "Layer", "Layer in multilayer image"); + prop = RNA_def_property(srna, "multilayer_pass", PROP_INT, PROP_UNSIGNED); + RNA_def_property_int_sdna(prop, NULL, "pass"); + RNA_def_property_clear_flag(prop, PROP_EDITABLE); /* image_multi_cb */ + RNA_def_property_ui_text(prop, "Pass", "Pass in multilayer image"); + prop = RNA_def_property(srna, "multilayer_view", PROP_INT, PROP_UNSIGNED); RNA_def_property_int_sdna(prop, NULL, "view"); RNA_def_property_clear_flag(prop, PROP_EDITABLE); /* image_multi_cb */ @@ -561,9 +576,9 @@ static void rna_def_image_packed_files(BlenderRNA *brna) prop = RNA_def_property(srna, "filepath", PROP_STRING, PROP_FILEPATH); RNA_def_property_string_sdna(prop, NULL, "filepath"); - RNA_def_property_clear_flag(prop, PROP_EDITABLE); RNA_def_struct_name_property(srna, prop); - RNA_def_property_clear_flag(prop, PROP_EDITABLE); + + RNA_api_image_packed_file(srna); } static void rna_def_render_slot(BlenderRNA *brna) @@ -711,12 +726,12 @@ static void rna_def_image(BlenderRNA *brna) RNA_def_property_update(prop, NC_IMAGE | ND_DISPLAY, "rna_Image_views_format_update"); prop = RNA_def_property(srna, "is_stereo_3d", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_sdna(prop, NULL, "flag", IMA_IS_STEREO); + RNA_def_property_boolean_funcs(prop, "rna_Image_is_stereo_3d_get", NULL); RNA_def_property_ui_text(prop, "Stereo 3D", "Image has left and right views"); RNA_def_property_clear_flag(prop, PROP_EDITABLE); prop = RNA_def_property(srna, "is_multiview", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_sdna(prop, NULL, "flag", IMA_IS_MULTIVIEW); + RNA_def_property_boolean_funcs(prop, "rna_Image_is_multiview_get", NULL); RNA_def_property_ui_text(prop, "Multiple Views", "Image has more than one view"); RNA_def_property_clear_flag(prop, PROP_EDITABLE); diff --git a/source/blender/makesrna/intern/rna_image_api.c b/source/blender/makesrna/intern/rna_image_api.c index f187a0e1804..1efa41d1b00 100644 --- a/source/blender/makesrna/intern/rna_image_api.c +++ b/source/blender/makesrna/intern/rna_image_api.c @@ -63,6 +63,14 @@ #include "MEM_guardedalloc.h" +static void rna_ImagePackedFile_save(ImagePackedFile *imapf, ReportList *reports) +{ + if (writePackedFile(reports, imapf->filepath, imapf->packedfile, 0) != RET_OK) { + BKE_reportf(reports, RPT_ERROR, "Image could not save packed file to '%s'", + imapf->filepath); + } +} + static void rna_Image_save_render(Image *image, bContext *C, ReportList *reports, const char *path, Scene *scene) { ImBuf *ibuf; @@ -115,17 +123,10 @@ static void rna_Image_save(Image *image, Main *bmain, bContext *C, ReportList *r BLI_strncpy(filename, image->name, sizeof(filename)); BLI_path_abs(filename, ID_BLEND_PATH(bmain, &image->id)); - if (BKE_image_has_packedfile(image)) { - ImagePackedFile *imapf; + /* note, we purposefully ignore packed files here, + * developers need to explicitly write them via 'packed_files' */ - for (imapf = image->packedfiles.first; imapf; imapf = imapf->next) { - if (writePackedFile(reports, imapf->filepath, imapf->packedfile, 0) != RET_OK) { - BKE_reportf(reports, RPT_ERROR, "Image '%s' could not save packed file to '%s'", - image->id.name + 2, imapf->filepath); - } - } - } - else if (IMB_saveiff(ibuf, filename, ibuf->flags)) { + if (IMB_saveiff(ibuf, filename, ibuf->flags)) { image->type = IMA_TYPE_IMAGE; if (image->source == IMA_SRC_GENERATED) @@ -295,6 +296,15 @@ static void rna_Image_buffers_free(Image *image) #else +void RNA_api_image_packed_file(StructRNA *srna) +{ + FunctionRNA *func; + + func = RNA_def_function(srna, "save", "rna_ImagePackedFile_save"); + RNA_def_function_ui_description(func, "Save the packed file to its filepath"); + RNA_def_function_flag(func, FUNC_USE_REPORTS); +} + void RNA_api_image(StructRNA *srna) { FunctionRNA *func; diff --git a/source/blender/makesrna/intern/rna_internal.h b/source/blender/makesrna/intern/rna_internal.h index a7e6600314d..0da2f7d1ad4 100644 --- a/source/blender/makesrna/intern/rna_internal.h +++ b/source/blender/makesrna/intern/rna_internal.h @@ -260,6 +260,7 @@ void RNA_api_camera(StructRNA *srna); void RNA_api_curve(StructRNA *srna); void RNA_api_fcurves(StructRNA *srna); void RNA_api_drivers(StructRNA *srna); +void RNA_api_image_packed_file(struct StructRNA *srna); void RNA_api_image(struct StructRNA *srna); void RNA_api_lattice(struct StructRNA *srna); void RNA_api_operator(struct StructRNA *srna); diff --git a/source/blender/makesrna/intern/rna_key.c b/source/blender/makesrna/intern/rna_key.c index 8a3a8a60120..90794ccc211 100644 --- a/source/blender/makesrna/intern/rna_key.c +++ b/source/blender/makesrna/intern/rna_key.c @@ -156,6 +156,112 @@ static void rna_ShapeKey_slider_max_set(PointerRNA *ptr, float value) #undef SHAPEKEY_SLIDER_TOL +/* ***** Normals accessors for shapekeys. ***** */ +/* Note: with this we may recompute several times the same data, should we want to access verts, then polys, then loops + * normals... However, such case looks rather unlikely - and not worth adding some kind of caching in KeyBlocks. + */ + +static Mesh *rna_KeyBlock_normals_get_mesh(PointerRNA *ptr, ID *id) +{ + Key *key = rna_ShapeKey_find_key((id == NULL && ptr != NULL) ? ptr->id.data : id); + id = key ? key->from : NULL; + + if (id != NULL) { + switch (GS(id->name)) { + case ID_ME: + return (Mesh *)id; + case ID_OB: + { + Object *ob = (Object *)id; + if (ob->type == OB_MESH) { + return ob->data; + } + } + } + } + + return NULL; +} + +static int rna_KeyBlock_normals_vert_len(PointerRNA *ptr, int length[RNA_MAX_ARRAY_DIMENSION]) +{ + Mesh *me = rna_KeyBlock_normals_get_mesh(ptr, NULL); + + length[0] = me ? me->totvert : 0; + length[1] = 3; + + return (length[0] * length[1]); +} + +static void rna_KeyBlock_normals_vert_calc(ID *id, KeyBlock *data, int *normals_len, float **normals) +{ + Mesh *me = rna_KeyBlock_normals_get_mesh(NULL, id); + + *normals_len = (me ? me->totvert : 0) * 3; + + if (ELEM(NULL, me, data) || (me->totvert == 0)) { + *normals = NULL; + return; + } + + *normals = MEM_mallocN(sizeof(**normals) * (size_t)(*normals_len), __func__); + + BKE_keyblock_mesh_calc_normals(data, me, (float (*)[3])(*normals), NULL, NULL); +} + +static int rna_KeyBlock_normals_poly_len(PointerRNA *ptr, int length[RNA_MAX_ARRAY_DIMENSION]) +{ + Mesh *me = rna_KeyBlock_normals_get_mesh(ptr, NULL); + + length[0] = me ? me->totpoly : 0; + length[1] = 3; + + return (length[0] * length[1]); +} + +static void rna_KeyBlock_normals_poly_calc(ID *id, KeyBlock *data, int *normals_len, float **normals) +{ + Mesh *me = rna_KeyBlock_normals_get_mesh(NULL, id); + + *normals_len = (me ? me->totpoly : 0) * 3; + + if (ELEM(NULL, me, data) || (me->totpoly == 0)) { + *normals = NULL; + return; + } + + *normals = MEM_mallocN(sizeof(**normals) * (size_t)(*normals_len), __func__); + + BKE_keyblock_mesh_calc_normals(data, me, NULL, (float (*)[3])(*normals), NULL); +} + +static int rna_KeyBlock_normals_loop_len(PointerRNA *ptr, int length[RNA_MAX_ARRAY_DIMENSION]) +{ + Mesh *me = rna_KeyBlock_normals_get_mesh(ptr, NULL); + + length[0] = me ? me->totloop : 0; + length[1] = 3; + + return (length[0] * length[1]); +} + +static void rna_KeyBlock_normals_loop_calc(ID *id, KeyBlock *data, int *normals_len, float **normals) +{ + Mesh *me = rna_KeyBlock_normals_get_mesh(NULL, id); + + *normals_len = (me ? me->totloop : 0) * 3; + + if (ELEM(NULL, me, data) || (me->totloop == 0)) { + *normals = NULL; + return; + } + + *normals = MEM_mallocN(sizeof(**normals) * (size_t)(*normals_len), __func__); + + BKE_keyblock_mesh_calc_normals(data, me, NULL, NULL, (float (*)[3])(*normals)); +} + + PointerRNA rna_object_shapekey_index_get(ID *id, int value) { Key *key = rna_ShapeKey_find_key(id); @@ -558,7 +664,8 @@ static void rna_def_keydata(BlenderRNA *brna) static void rna_def_keyblock(BlenderRNA *brna) { StructRNA *srna; - PropertyRNA *prop; + PropertyRNA *prop, *parm; + FunctionRNA *func; srna = RNA_def_struct(brna, "ShapeKey", NULL); RNA_def_struct_ui_text(srna, "Shape Key", "Shape key in a shape keys datablock"); @@ -638,6 +745,36 @@ static void rna_def_keyblock(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Data", ""); RNA_def_property_collection_funcs(prop, "rna_ShapeKey_data_begin", NULL, NULL, "rna_ShapeKey_data_get", "rna_ShapeKey_data_length", NULL, NULL, NULL); + + /* XXX multi-dim dynamic arrays are very badly supported by (py)rna currently, those are defined for the day + * it works better, for now user will get a 1D tuple... + **/ + func = RNA_def_function(srna, "normals_vertex_get", "rna_KeyBlock_normals_vert_calc"); + RNA_def_function_ui_description(func, "Compute local space vertices' normals for this shape key"); + RNA_def_function_flag(func, FUNC_USE_SELF_ID); + parm = RNA_def_property(func, "normals", PROP_FLOAT, /* PROP_DIRECTION */ PROP_NONE); + RNA_def_property_flag(parm, PROP_DYNAMIC | PROP_OUTPUT); + RNA_def_property_multi_array(parm, 2, NULL); + RNA_def_property_range(parm, -1.0f, 1.0f); + RNA_def_property_dynamic_array_funcs(parm, "rna_KeyBlock_normals_vert_len"); + + func = RNA_def_function(srna, "normals_polygon_get", "rna_KeyBlock_normals_poly_calc"); + RNA_def_function_ui_description(func, "Compute local space faces' normals for this shape key"); + RNA_def_function_flag(func, FUNC_USE_SELF_ID); + parm = RNA_def_property(func, "normals", PROP_FLOAT, /* PROP_DIRECTION */ PROP_NONE); + RNA_def_property_flag(parm, PROP_DYNAMIC | PROP_OUTPUT); + RNA_def_property_multi_array(parm, 2, NULL); + RNA_def_property_range(parm, -1.0f, 1.0f); + RNA_def_property_dynamic_array_funcs(parm, "rna_KeyBlock_normals_poly_len"); + + func = RNA_def_function(srna, "normals_split_get", "rna_KeyBlock_normals_loop_calc"); + RNA_def_function_ui_description(func, "Compute local space face corners' normals for this shape key"); + RNA_def_function_flag(func, FUNC_USE_SELF_ID); + parm = RNA_def_property(func, "normals", PROP_FLOAT, /* PROP_DIRECTION */ PROP_NONE); + RNA_def_property_flag(parm, PROP_DYNAMIC | PROP_OUTPUT); + RNA_def_property_multi_array(parm, 2, NULL); + RNA_def_property_range(parm, -1.0f, 1.0f); + RNA_def_property_dynamic_array_funcs(parm, "rna_KeyBlock_normals_loop_len"); } static void rna_def_key(BlenderRNA *brna) diff --git a/source/blender/makesrna/intern/rna_lattice.c b/source/blender/makesrna/intern/rna_lattice.c index 60e5f6d205c..035e9d15641 100644 --- a/source/blender/makesrna/intern/rna_lattice.c +++ b/source/blender/makesrna/intern/rna_lattice.c @@ -175,7 +175,7 @@ static int rna_Lattice_size_editable(PointerRNA *ptr) { Lattice *lt = (Lattice *)ptr->data; - return lt->key == NULL; + return (lt->key == NULL) ? PROP_EDITABLE : 0; } static void rna_Lattice_points_u_set(PointerRNA *ptr, int value) diff --git a/source/blender/makesrna/intern/rna_main_api.c b/source/blender/makesrna/intern/rna_main_api.c index 9ccff3eb1fa..5a0da0b7651 100644 --- a/source/blender/makesrna/intern/rna_main_api.c +++ b/source/blender/makesrna/intern/rna_main_api.c @@ -36,6 +36,7 @@ #include "DNA_ID.h" #include "DNA_modifier_types.h" #include "DNA_space_types.h" +#include "DNA_object_types.h" #include "BLI_utildefines.h" #include "BLI_path_util.h" @@ -88,7 +89,6 @@ #include "DNA_lamp_types.h" #include "DNA_material_types.h" #include "DNA_mesh_types.h" -#include "DNA_object_types.h" #include "DNA_speaker_types.h" #include "DNA_sound_types.h" #include "DNA_text_types.h" @@ -352,12 +352,17 @@ static Image *rna_Main_images_new(Main *bmain, const char *name, int width, int id_us_min(&image->id); return image; } -static Image *rna_Main_images_load(Main *bmain, ReportList *reports, const char *filepath) +static Image *rna_Main_images_load(Main *bmain, ReportList *reports, const char *filepath, int check_existing) { Image *ima; errno = 0; - ima = BKE_image_load(bmain, filepath); + if (check_existing) { + ima = BKE_image_load_exists(filepath); + } + else { + ima = BKE_image_load(bmain, filepath); + } if (!ima) { BKE_reportf(reports, RPT_ERROR, "Cannot read '%s': %s", filepath, @@ -436,12 +441,17 @@ static void rna_Main_metaballs_remove(Main *bmain, ReportList *reports, PointerR } } -static VFont *rna_Main_fonts_load(Main *bmain, ReportList *reports, const char *filepath) +static VFont *rna_Main_fonts_load(Main *bmain, ReportList *reports, const char *filepath, int check_existing) { VFont *font; - errno = 0; - font = BKE_vfont_load(bmain, filepath); + + if (check_existing) { + font = BKE_vfont_load_exists(bmain, filepath); + } + else { + font = BKE_vfont_load(bmain, filepath); + } if (!font) BKE_reportf(reports, RPT_ERROR, "Cannot read '%s': %s", filepath, @@ -483,12 +493,13 @@ static void rna_Main_textures_remove(Main *bmain, ReportList *reports, PointerRN } } -static Brush *rna_Main_brushes_new(Main *bmain, const char *name) +static Brush *rna_Main_brushes_new(Main *bmain, const char *name, int mode) { - Brush *brush = BKE_brush_add(bmain, name); + Brush *brush = BKE_brush_add(bmain, name, mode); id_us_min(&brush->id); return brush; } + static void rna_Main_brushes_remove(Main *bmain, ReportList *reports, PointerRNA *brush_ptr) { Brush *brush = brush_ptr->data; @@ -552,9 +563,17 @@ static void rna_Main_speakers_remove(Main *bmain, ReportList *reports, PointerRN } } -static bSound *rna_Main_sounds_load(Main *bmain, const char *name) +static bSound *rna_Main_sounds_load(Main *bmain, const char *name, int check_existing) { - bSound *sound = BKE_sound_new_file(bmain, name); + bSound *sound; + + if (check_existing) { + sound = BKE_sound_new_file_exists(bmain, name); + } + else { + sound = BKE_sound_new_file(bmain, name); + } + id_us_min(&sound->id); return sound; } @@ -674,12 +693,18 @@ static void rna_Main_palettes_remove(Main *bmain, ReportList *reports, PointerRN } } -static MovieClip *rna_Main_movieclip_load(Main *bmain, ReportList *reports, const char *filepath) +static MovieClip *rna_Main_movieclip_load(Main *bmain, ReportList *reports, const char *filepath, int check_existing) { MovieClip *clip; errno = 0; - clip = BKE_movieclip_file_add(bmain, filepath); + + if (check_existing) { + clip = BKE_movieclip_file_add_exists(bmain, filepath); + } + else { + clip = BKE_movieclip_file_add(bmain, filepath); + } if (!clip) BKE_reportf(reports, RPT_ERROR, "Cannot read '%s': %s", filepath, @@ -1206,6 +1231,7 @@ void RNA_def_main_images(BlenderRNA *brna, PropertyRNA *cprop) RNA_def_function_ui_description(func, "Load a new image into the main database"); parm = RNA_def_string_file_path(func, "filepath", "File Path", 0, "", "path of the file to load"); RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_boolean(func, "check_existing", false, "", "Using existing data-block if this file is already loaded"); /* return type */ parm = RNA_def_pointer(func, "image", "Image", "", "New image datablock"); RNA_def_function_return(func, parm); @@ -1350,6 +1376,7 @@ void RNA_def_main_fonts(BlenderRNA *brna, PropertyRNA *cprop) RNA_def_function_ui_description(func, "Load a new font into the main database"); parm = RNA_def_string_file_path(func, "filepath", "File Path", 0, "", "path of the font to load"); RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_boolean(func, "check_existing", false, "", "Using existing data-block if this file is already loaded"); /* return type */ parm = RNA_def_pointer(func, "vfont", "VectorFont", "", "New font datablock"); RNA_def_function_return(func, parm); @@ -1422,6 +1449,7 @@ void RNA_def_main_brushes(BlenderRNA *brna, PropertyRNA *cprop) RNA_def_function_ui_description(func, "Add a new brush to the main database"); parm = RNA_def_string(func, "name", "Brush", 0, "", "New name for the datablock"); RNA_def_property_flag(parm, PROP_REQUIRED); + parm = RNA_def_enum(func, "mode", object_mode_items, OB_MODE_TEXTURE_PAINT, "", "Paint Mode for the new brush"); /* return type */ parm = RNA_def_pointer(func, "brush", "Brush", "", "New brush datablock"); RNA_def_function_return(func, parm); @@ -1612,6 +1640,7 @@ void RNA_def_main_sounds(BlenderRNA *brna, PropertyRNA *cprop) RNA_def_function_ui_description(func, "Add a new sound to the main database from a file"); parm = RNA_def_string_file_path(func, "filepath", "Path", FILE_MAX, "", "path for the datablock"); RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_boolean(func, "check_existing", false, "", "Using existing data-block if this file is already loaded"); /* return type */ parm = RNA_def_pointer(func, "sound", "Sound", "", "New text datablock"); RNA_def_function_return(func, parm); @@ -1835,6 +1864,7 @@ void RNA_def_main_movieclips(BlenderRNA *brna, PropertyRNA *cprop) RNA_def_function_ui_description(func, "Add a new movie clip to the main database from a file"); parm = RNA_def_string_file_path(func, "filepath", "Path", FILE_MAX, "", "path for the datablock"); RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_boolean(func, "check_existing", false, "", "Using existing data-block if this file is already loaded"); /* return type */ parm = RNA_def_pointer(func, "clip", "MovieClip", "", "New movie clip datablock"); RNA_def_function_return(func, parm); diff --git a/source/blender/makesrna/intern/rna_material.c b/source/blender/makesrna/intern/rna_material.c index a1fa6ab13be..d7e566ff431 100644 --- a/source/blender/makesrna/intern/rna_material.c +++ b/source/blender/makesrna/intern/rna_material.c @@ -237,7 +237,7 @@ static int rna_Material_active_texture_editable(PointerRNA *ptr) { Material *ma = (Material *)ptr->id.data; - return has_current_material_texture(ma); + return has_current_material_texture(ma) ? PROP_EDITABLE : 0; } static PointerRNA rna_Material_active_node_material_get(PointerRNA *ptr) diff --git a/source/blender/makesrna/intern/rna_mesh_api.c b/source/blender/makesrna/intern/rna_mesh_api.c index 632b07c19ce..1459157112e 100644 --- a/source/blender/makesrna/intern/rna_mesh_api.c +++ b/source/blender/makesrna/intern/rna_mesh_api.c @@ -136,8 +136,9 @@ static void rna_Mesh_normals_split_custom_do(Mesh *mesh, float (*custom_loopnors } else { polynors = MEM_mallocN(sizeof(float[3]) * mesh->totpoly, __func__); - BKE_mesh_calc_normals_poly(mesh->mvert, mesh->totvert, mesh->mloop, mesh->mpoly, mesh->totloop, mesh->totpoly, - polynors, false); + BKE_mesh_calc_normals_poly( + mesh->mvert, NULL, mesh->totvert, + mesh->mloop, mesh->mpoly, mesh->totloop, mesh->totpoly, polynors, false); free_polynors = true; } diff --git a/source/blender/makesrna/intern/rna_modifier.c b/source/blender/makesrna/intern/rna_modifier.c index 694a438333a..6b604728387 100644 --- a/source/blender/makesrna/intern/rna_modifier.c +++ b/source/blender/makesrna/intern/rna_modifier.c @@ -549,9 +549,11 @@ RNA_MOD_OBJECT_SET(Shrinkwrap, auxTarget, OB_MESH); static void rna_HookModifier_object_set(PointerRNA *ptr, PointerRNA value) { HookModifierData *hmd = ptr->data; + Object *ob = (Object *)value.data; - hmd->object = (Object *)value.data; - BKE_object_modifier_hook_reset((Object *)ptr->id.data, hmd); + hmd->object = ob; + id_lib_extern((ID *)ob); + BKE_object_modifier_hook_reset(ob, hmd); } static PointerRNA rna_UVProjector_object_get(PointerRNA *ptr) @@ -562,8 +564,10 @@ static PointerRNA rna_UVProjector_object_get(PointerRNA *ptr) static void rna_UVProjector_object_set(PointerRNA *ptr, PointerRNA value) { - Object **ob = (Object **)ptr->data; - *ob = value.data; + Object **ob_p = (Object **)ptr->data; + Object *ob = (Object *)value.data; + id_lib_extern((ID *)ob); + *ob_p = ob; } #undef RNA_MOD_OBJECT_SET @@ -1493,7 +1497,7 @@ static void rna_def_modifier_decimate(BlenderRNA *brna) prop = RNA_def_property(srna, "angle_limit", PROP_FLOAT, PROP_ANGLE); RNA_def_property_float_sdna(prop, NULL, "angle"); RNA_def_property_range(prop, 0, DEG2RAD(180)); - RNA_def_property_ui_range(prop, 0, DEG2RAD(180), 100, 2); + RNA_def_property_ui_range(prop, 0, DEG2RAD(180), 10, 2); RNA_def_property_ui_text(prop, "Angle Limit", "Only dissolve angles below this (planar only)"); RNA_def_property_update(prop, 0, "rna_Modifier_update"); @@ -1969,7 +1973,7 @@ static void rna_def_modifier_edgesplit(BlenderRNA *brna) prop = RNA_def_property(srna, "split_angle", PROP_FLOAT, PROP_ANGLE); RNA_def_property_range(prop, 0.0f, DEG2RADF(180.0f)); - RNA_def_property_ui_range(prop, 0.0f, DEG2RADF(180.0f), 100, 2); + RNA_def_property_ui_range(prop, 0.0f, DEG2RADF(180.0f), 10, 2); RNA_def_property_ui_text(prop, "Split Angle", "Angle above which to split edges"); RNA_def_property_update(prop, 0, "rna_Modifier_update"); @@ -2806,7 +2810,7 @@ static void rna_def_modifier_bevel(BlenderRNA *brna) prop = RNA_def_property(srna, "angle_limit", PROP_FLOAT, PROP_ANGLE); RNA_def_property_float_sdna(prop, NULL, "bevel_angle"); RNA_def_property_range(prop, 0.0f, DEG2RADF(180.0f)); - RNA_def_property_ui_range(prop, 0.0f, DEG2RADF(180.0f), 100, 2); + RNA_def_property_ui_range(prop, 0.0f, DEG2RADF(180.0f), 10, 2); RNA_def_property_ui_text(prop, "Angle", "Angle above which to bevel edges"); RNA_def_property_update(prop, 0, "rna_Modifier_update"); @@ -3056,7 +3060,7 @@ static void rna_def_modifier_simpledeform(BlenderRNA *brna) prop = RNA_def_property(srna, "factor", PROP_FLOAT, PROP_NONE); RNA_def_property_range(prop, -FLT_MAX, FLT_MAX); - RNA_def_property_ui_range(prop, -10, 10, 1, 3); + RNA_def_property_ui_range(prop, -10.0, 10.0, 1.0, 3); RNA_def_property_ui_text(prop, "Factor", "Amount to deform object"); RNA_def_property_update(prop, 0, "rna_Modifier_update"); @@ -3064,7 +3068,7 @@ static void rna_def_modifier_simpledeform(BlenderRNA *brna) RNA_def_property_float_sdna(prop, NULL, "factor"); RNA_def_property_range(prop, -FLT_MAX, FLT_MAX); RNA_def_property_float_default(prop, DEG2RADF(45.0f)); - RNA_def_property_ui_range(prop, -M_PI, M_PI, DEG2RAD(1), 3); + RNA_def_property_ui_range(prop, DEG2RAD(-360.0), DEG2RAD(360.0), 10.0, 3); RNA_def_property_ui_text(prop, "Angle", "Angle of deformation"); RNA_def_property_update(prop, 0, "rna_Modifier_update"); @@ -3260,7 +3264,7 @@ static void rna_def_modifier_screw(BlenderRNA *brna) RNA_def_property_update(prop, 0, "rna_Modifier_update"); prop = RNA_def_property(srna, "angle", PROP_FLOAT, PROP_ANGLE); - RNA_def_property_ui_range(prop, -M_PI * 2, M_PI * 2, 2, -1); + RNA_def_property_ui_range(prop, -M_PI * 2, M_PI * 2, 10, -1); RNA_def_property_range(prop, -FLT_MAX, FLT_MAX); RNA_def_property_ui_text(prop, "Angle", "Angle of revolution"); RNA_def_property_update(prop, 0, "rna_Modifier_update"); diff --git a/source/blender/makesrna/intern/rna_nla.c b/source/blender/makesrna/intern/rna_nla.c index 4b66313cdd4..0e8ed5eea8d 100644 --- a/source/blender/makesrna/intern/rna_nla.c +++ b/source/blender/makesrna/intern/rna_nla.c @@ -290,7 +290,7 @@ static int rna_NlaStrip_action_editable(PointerRNA *ptr) return 0; /* should be ok, though we may still miss some cases */ - return 1; + return PROP_EDITABLE; } static void rna_NlaStrip_action_start_frame_set(PointerRNA *ptr, float value) @@ -614,7 +614,7 @@ static void rna_def_nlastrip(BlenderRNA *brna) * (minimum should still be > 0 though) if needed... */ RNA_def_property_range(prop, 0.1f, 1000.0f); RNA_def_property_ui_text(prop, "Repeat", "Number of times to repeat the action range"); - RNA_def_property_update(prop, NC_ANIMATION | ND_NLA, NULL); /* this will do? */ + RNA_def_property_update(prop, 0, "rna_NlaStrip_transform_update"); prop = RNA_def_property(srna, "scale", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "scale"); diff --git a/source/blender/makesrna/intern/rna_nodetree.c b/source/blender/makesrna/intern/rna_nodetree.c index 51e611418aa..a51dffb8ca3 100644 --- a/source/blender/makesrna/intern/rna_nodetree.c +++ b/source/blender/makesrna/intern/rna_nodetree.c @@ -792,6 +792,11 @@ static bNodeLink *rna_NodeTree_link_new(bNodeTree *ntree, ReportList *reports, ret = nodeAddLink(ntree, fromnode, fromsock, tonode, tosock); if (ret) { + + /* not an issue from the UI, clear hidden from API to keep valid state. */ + fromsock->flag &= ~SOCK_HIDDEN; + tosock->flag &= ~SOCK_HIDDEN; + if (tonode) nodeUpdate(ntree, tonode); @@ -3011,10 +3016,14 @@ static int point_density_color_source_from_shader(NodeShaderTexPointDensity *sha } } -/* TODO(sergey): This functio nassumes allocated array was passed, +/* TODO(sergey): This function assumes allocated array was passed, * works fine with Cycles via C++ RNA, but fails with call from python. */ -void rna_ShaderNodePointDensity_density_calc(bNode *self, Scene *scene, int *length, float **values) +void rna_ShaderNodePointDensity_density_calc(bNode *self, + Scene *scene, + int settings, + int *length, + float **values) { NodeShaderTexPointDensity *shader_point_density = self->storage; PointDensity pd; @@ -3046,6 +3055,7 @@ void rna_ShaderNodePointDensity_density_calc(bNode *self, Scene *scene, int *len /* Single-threaded sampling of the voxel domain. */ RE_sample_point_density(scene, &pd, shader_point_density->resolution, + settings == 1, *values); /* We're done, time to clean up. */ @@ -3538,17 +3548,29 @@ static void def_sh_tex_sky(StructRNA *srna) RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); } +static const EnumPropertyItem sh_tex_prop_color_space_items[] = { + {SHD_COLORSPACE_COLOR, "COLOR", 0, "Color", + "Image contains color data, and will be converted to linear color for rendering"}, + {SHD_COLORSPACE_NONE, "NONE", 0, "Non-Color Data", + "Image contains non-color data, for example a displacement or normal map, " + "and will not be converted"}, + {0, NULL, 0, NULL, NULL} +}; + +static const EnumPropertyItem sh_tex_prop_interpolation_items[] = { + {SHD_INTERP_LINEAR, "Linear", 0, "Linear", + "Linear interpolation"}, + {SHD_INTERP_CLOSEST, "Closest", 0, "Closest", + "No interpolation (sample closest texel)"}, + {SHD_INTERP_CUBIC, "Cubic", 0, "Cubic", + "Cubic interpolation (CPU only)"}, + {SHD_INTERP_SMART, "Smart", 0, "Smart", + "Bicubic when magnifying, else bilinear (OSL only)"}, + {0, NULL, 0, NULL, NULL} +}; + static void def_sh_tex_environment(StructRNA *srna) { - static const EnumPropertyItem prop_color_space_items[] = { - {SHD_COLORSPACE_COLOR, "COLOR", 0, "Color", - "Image contains color data, and will be converted to linear color for rendering"}, - {SHD_COLORSPACE_NONE, "NONE", 0, "Non-Color Data", - "Image contains non-color data, for example a displacement or normal map, " - "and will not be converted"}, - {0, NULL, 0, NULL, NULL} - }; - static const EnumPropertyItem prop_projection_items[] = { {SHD_PROJ_EQUIRECTANGULAR, "EQUIRECTANGULAR", 0, "Equirectangular", "Equirectangular or latitude-longitude projection"}, @@ -3570,7 +3592,7 @@ static void def_sh_tex_environment(StructRNA *srna) def_sh_tex(srna); prop = RNA_def_property(srna, "color_space", PROP_ENUM, PROP_NONE); - RNA_def_property_enum_items(prop, prop_color_space_items); + RNA_def_property_enum_items(prop, sh_tex_prop_color_space_items); RNA_def_property_enum_default(prop, SHD_COLORSPACE_COLOR); RNA_def_property_ui_text(prop, "Color Space", "Image file color space"); RNA_def_property_update(prop, 0, "rna_Node_update"); @@ -3580,6 +3602,11 @@ static void def_sh_tex_environment(StructRNA *srna) RNA_def_property_ui_text(prop, "Projection", "Projection of the input image"); RNA_def_property_update(prop, 0, "rna_Node_update"); + prop = RNA_def_property(srna, "interpolation", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_items(prop, sh_tex_prop_interpolation_items); + RNA_def_property_ui_text(prop, "Interpolation", "Texture interpolation"); + RNA_def_property_update(prop, 0, "rna_Node_update"); + prop = RNA_def_property(srna, "image_user", PROP_POINTER, PROP_NONE); RNA_def_property_flag(prop, PROP_NEVER_NULL); RNA_def_property_pointer_sdna(prop, NULL, "iuser"); @@ -3590,15 +3617,6 @@ static void def_sh_tex_environment(StructRNA *srna) static void def_sh_tex_image(StructRNA *srna) { - static const EnumPropertyItem prop_color_space_items[] = { - {SHD_COLORSPACE_COLOR, "COLOR", 0, "Color", - "Image contains color data, and will be converted to linear color for rendering"}, - {SHD_COLORSPACE_NONE, "NONE", 0, "Non-Color Data", - "Image contains non-color data, for example a displacement or normal map, " - "and will not be converted"}, - {0, NULL, 0, NULL, NULL} - }; - static const EnumPropertyItem prop_projection_items[] = { {SHD_PROJ_FLAT, "FLAT", 0, "Flat", "Image is projected flat using the X and Y coordinates of the texture vector"}, @@ -3611,18 +3629,6 @@ static void def_sh_tex_image(StructRNA *srna) {0, NULL, 0, NULL, NULL} }; - static const EnumPropertyItem prop_interpolation_items[] = { - {SHD_INTERP_LINEAR, "Linear", 0, "Linear", - "Linear interpolation"}, - {SHD_INTERP_CLOSEST, "Closest", 0, "Closest", - "No interpolation (sample closest texel)"}, - {SHD_INTERP_CUBIC, "Cubic", 0, "Cubic", - "Cubic interpolation (CPU only)"}, - {SHD_INTERP_SMART, "Smart", 0, "Smart", - "Bicubic when magnifying, else bilinear (OSL only)"}, - {0, NULL, 0, NULL, NULL} - }; - static EnumPropertyItem prop_image_extension[] = { {SHD_IMAGE_EXTENSION_REPEAT, "REPEAT", 0, "Repeat", "Cause the image to repeat horizontally and vertically"}, {SHD_IMAGE_EXTENSION_EXTEND, "EXTEND", 0, "Extend", "Extend by repeating edge pixels of the image"}, @@ -3643,7 +3649,7 @@ static void def_sh_tex_image(StructRNA *srna) def_sh_tex(srna); prop = RNA_def_property(srna, "color_space", PROP_ENUM, PROP_NONE); - RNA_def_property_enum_items(prop, prop_color_space_items); + RNA_def_property_enum_items(prop, sh_tex_prop_color_space_items); RNA_def_property_enum_default(prop, SHD_COLORSPACE_COLOR); RNA_def_property_ui_text(prop, "Color Space", "Image file color space"); RNA_def_property_update(prop, 0, "rna_Node_update"); @@ -3654,7 +3660,7 @@ static void def_sh_tex_image(StructRNA *srna) RNA_def_property_update(prop, 0, "rna_Node_update"); prop = RNA_def_property(srna, "interpolation", PROP_ENUM, PROP_NONE); - RNA_def_property_enum_items(prop, prop_interpolation_items); + RNA_def_property_enum_items(prop, sh_tex_prop_interpolation_items); RNA_def_property_ui_text(prop, "Interpolation", "Texture interpolation"); RNA_def_property_update(prop, 0, "rna_Node_update"); @@ -3929,6 +3935,13 @@ static void def_sh_tex_pointdensity(StructRNA *srna) {0, NULL, 0, NULL, NULL} }; + /* TODO(sergey): Use some mnemonic names for the hardcoded values here. */ + static EnumPropertyItem calc_mode_items[] = { + {0, "VIEWPORT", 0, "Viewport", "Canculate density using viewport settings"}, + {1, "RENDER", 0, "Render", "Canculate duplis using render settings"}, + {0, NULL, 0, NULL, NULL} + }; + prop = RNA_def_property(srna, "object", PROP_POINTER, PROP_NONE); RNA_def_property_pointer_sdna(prop, NULL, "id"); RNA_def_property_struct_type(prop, "Object"); @@ -3981,6 +3994,7 @@ static void def_sh_tex_pointdensity(StructRNA *srna) func = RNA_def_function(srna, "calc_point_density", "rna_ShaderNodePointDensity_density_calc"); RNA_def_function_ui_description(func, "Calculate point density"); RNA_def_pointer(func, "scene", "Scene", "", ""); + RNA_def_enum(func, "settings", calc_mode_items, 1, "", "Calculate density for rendering"); /* TODO, See how array size of 0 works, this shouldnt be used. */ prop = RNA_def_float_array(func, "rgba_values", 1, NULL, 0, 0, "", "RGBA Values", 0, 0); RNA_def_property_flag(prop, PROP_DYNAMIC); diff --git a/source/blender/makesrna/intern/rna_object.c b/source/blender/makesrna/intern/rna_object.c index b09a0af63b7..d24c88a74a6 100644 --- a/source/blender/makesrna/intern/rna_object.c +++ b/source/blender/makesrna/intern/rna_object.c @@ -108,13 +108,13 @@ static EnumPropertyItem dupli_items[] = { #endif static EnumPropertyItem collision_bounds_items[] = { - {OB_BOUND_BOX, "BOX", 0, "Box", ""}, - {OB_BOUND_SPHERE, "SPHERE", 0, "Sphere", ""}, - {OB_BOUND_CYLINDER, "CYLINDER", 0, "Cylinder", ""}, - {OB_BOUND_CONE, "CONE", 0, "Cone", ""}, - {OB_BOUND_CONVEX_HULL, "CONVEX_HULL", 0, "Convex Hull", ""}, - {OB_BOUND_TRIANGLE_MESH, "TRIANGLE_MESH", 0, "Triangle Mesh", ""}, - {OB_BOUND_CAPSULE, "CAPSULE", 0, "Capsule", ""}, + {OB_BOUND_BOX, "BOX", ICON_MESH_CUBE, "Box", ""}, + {OB_BOUND_SPHERE, "SPHERE", ICON_MESH_UVSPHERE, "Sphere", ""}, + {OB_BOUND_CYLINDER, "CYLINDER", ICON_MESH_CYLINDER, "Cylinder", ""}, + {OB_BOUND_CONE, "CONE", ICON_MESH_CONE, "Cone", ""}, + {OB_BOUND_CONVEX_HULL, "CONVEX_HULL", ICON_MESH_ICOSPHERE, "Convex Hull", ""}, + {OB_BOUND_TRIANGLE_MESH, "TRIANGLE_MESH", ICON_MESH_MONKEY, "Triangle Mesh", ""}, + {OB_BOUND_CAPSULE, "CAPSULE", ICON_MESH_CAPSULE, "Capsule", ""}, /*{OB_DYN_MESH, "DYNAMIC_MESH", 0, "Dynamic Mesh", ""}, */ {0, NULL, 0, NULL, NULL} }; @@ -536,11 +536,14 @@ static void rna_Object_dup_group_set(PointerRNA *ptr, PointerRNA value) /* must not let this be set if the object belongs in this group already, * thus causing a cycle/infinite-recursion leading to crashes on load [#25298] */ - if (BKE_group_object_exists(grp, ob) == 0) + if (BKE_group_object_exists(grp, ob) == 0) { ob->dup_group = grp; - else + id_lib_extern((ID *)grp); + } + else { BKE_report(NULL, RPT_ERROR, "Cannot set dupli-group as object belongs in group being instanced, thus causing a cycle"); + } } static void rna_VertexGroup_name_set(PointerRNA *ptr, const char *value) @@ -1954,6 +1957,14 @@ static void rna_def_object_game_settings(BlenderRNA *brna) RNA_def_property_float_default(prop, 55.0f); RNA_def_property_ui_text(prop, "Fall Speed Max", "Maximum speed at which the character will fall"); + prop = RNA_def_property(srna, "jump_max", PROP_INT, PROP_NONE); + RNA_def_property_int_sdna(prop, NULL, "max_jumps"); + RNA_def_property_range(prop, 1, CHAR_MAX); + RNA_def_property_ui_range(prop, 1, 10, 1, 1); + RNA_def_property_int_default(prop, 1); + RNA_def_property_ui_text(prop, "Max Jumps", + "The maximum number of jumps the character can make before it hits the ground"); + /* Collision Masks */ prop = RNA_def_property(srna, "collision_group", PROP_BOOLEAN, PROP_LAYER_MEMBER); RNA_def_property_boolean_sdna(prop, NULL, "col_group", 1); diff --git a/source/blender/makesrna/intern/rna_object_force.c b/source/blender/makesrna/intern/rna_object_force.c index 75becb341b9..2766540ab69 100644 --- a/source/blender/makesrna/intern/rna_object_force.c +++ b/source/blender/makesrna/intern/rna_object_force.c @@ -1639,7 +1639,7 @@ static void rna_def_softbody(BlenderRNA *brna) RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); RNA_def_property_range(prop, 0.0f, 1.0f); RNA_def_property_ui_text(prop, "Goal Default", - "Default Goal (vertex target position) value, when no Vertex Group used"); + "Default Goal (vertex target position) value"); RNA_def_property_update(prop, 0, "rna_softbody_update"); prop = RNA_def_property(srna, "goal_spring", PROP_FLOAT, PROP_NONE); diff --git a/source/blender/makesrna/intern/rna_pose.c b/source/blender/makesrna/intern/rna_pose.c index e65023132c9..27ff0a63e75 100644 --- a/source/blender/makesrna/intern/rna_pose.c +++ b/source/blender/makesrna/intern/rna_pose.c @@ -1062,6 +1062,17 @@ static void rna_def_pose_channel(BlenderRNA *brna) RNA_def_property_editable_func(prop, "rna_PoseChannel_proxy_editable"); RNA_def_property_update(prop, NC_OBJECT | ND_POSE, "rna_Pose_update"); + prop = RNA_def_property(srna, "custom_shape_scale", PROP_FLOAT, PROP_NONE); + RNA_def_property_float_sdna(prop, NULL, "custom_scale"); + RNA_def_property_range(prop, 0.0f, 1000.0f); + RNA_def_property_ui_text(prop, "Custom Shape Scale", "Adjust the size of the custom shape"); + RNA_def_property_update(prop, NC_OBJECT | ND_POSE, "rna_Pose_update"); + + prop = RNA_def_property(srna, "use_custom_shape_bone_size", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_negative_sdna(prop, NULL, "drawflag", PCHAN_DRAW_NO_CUSTOM_BONE_SIZE); + RNA_def_property_ui_text(prop, "Use Bone Size", "Scale the custom object by the bone length"); + RNA_def_property_update(prop, NC_OBJECT | ND_POSE, "rna_Pose_update"); + prop = RNA_def_property(srna, "custom_shape_transform", PROP_POINTER, PROP_NONE); RNA_def_property_pointer_sdna(prop, NULL, "custom_tx"); RNA_def_property_struct_type(prop, "PoseBone"); diff --git a/source/blender/makesrna/intern/rna_rigidbody.c b/source/blender/makesrna/intern/rna_rigidbody.c index 58a12f62644..395cb7c443d 100644 --- a/source/blender/makesrna/intern/rna_rigidbody.c +++ b/source/blender/makesrna/intern/rna_rigidbody.c @@ -53,7 +53,7 @@ EnumPropertyItem rigidbody_object_type_items[] = { EnumPropertyItem rigidbody_object_shape_items[] = { {RB_SHAPE_BOX, "BOX", ICON_MESH_CUBE, "Box", "Box-like shapes (i.e. cubes), including planes (i.e. ground planes)"}, {RB_SHAPE_SPHERE, "SPHERE", ICON_MESH_UVSPHERE, "Sphere", ""}, - {RB_SHAPE_CAPSULE, "CAPSULE", ICON_OUTLINER_OB_META, "Capsule", ""}, + {RB_SHAPE_CAPSULE, "CAPSULE", ICON_MESH_CAPSULE, "Capsule", ""}, {RB_SHAPE_CYLINDER, "CYLINDER", ICON_MESH_CYLINDER, "Cylinder", ""}, {RB_SHAPE_CONE, "CONE", ICON_MESH_CONE, "Cone", ""}, {RB_SHAPE_CONVEXH, "CONVEX_HULL", ICON_MESH_ICOSPHERE, "Convex Hull", diff --git a/source/blender/makesrna/intern/rna_scene.c b/source/blender/makesrna/intern/rna_scene.c index 4d7a2c13c1c..5fb6fa19fda 100644 --- a/source/blender/makesrna/intern/rna_scene.c +++ b/source/blender/makesrna/intern/rna_scene.c @@ -156,7 +156,7 @@ EnumPropertyItem mesh_select_mode_items[] = { }; EnumPropertyItem snap_element_items[] = { - {SCE_SNAP_MODE_INCREMENT, "INCREMENT", ICON_ALIGN, "Increment", "Snap to increments of grid"}, + {SCE_SNAP_MODE_INCREMENT, "INCREMENT", ICON_SNAP_INCREMENT, "Increment", "Snap to increments of grid"}, {SCE_SNAP_MODE_VERTEX, "VERTEX", ICON_SNAP_VERTEX, "Vertex", "Snap to vertices"}, {SCE_SNAP_MODE_EDGE, "EDGE", ICON_SNAP_EDGE, "Edge", "Snap to edges"}, {SCE_SNAP_MODE_FACE, "FACE", ICON_SNAP_FACE, "Face", "Snap to faces"}, @@ -165,7 +165,7 @@ EnumPropertyItem snap_element_items[] = { }; EnumPropertyItem snap_node_element_items[] = { - {SCE_SNAP_MODE_GRID, "GRID", ICON_SNAP_INCREMENT, "Grid", "Snap to grid"}, + {SCE_SNAP_MODE_GRID, "GRID", ICON_SNAP_GRID, "Grid", "Snap to grid"}, {SCE_SNAP_MODE_NODE_X, "NODE_X", ICON_SNAP_EDGE, "Node X", "Snap to left/right node border"}, {SCE_SNAP_MODE_NODE_Y, "NODE_Y", ICON_SNAP_EDGE, "Node Y", "Snap to top/bottom node border"}, {SCE_SNAP_MODE_NODE_XY, "NODE_XY", ICON_SNAP_EDGE, "Node X / Y", "Snap to any node border"}, @@ -432,7 +432,7 @@ EnumPropertyItem stereo3d_interlace_type_items[] = { static void rna_SpaceImageEditor_uv_sculpt_update(Main *bmain, Scene *scene, PointerRNA *UNUSED(ptr)) { - ED_space_image_uv_sculpt_update(bmain->wm.first, scene->toolsettings); + ED_space_image_uv_sculpt_update(bmain->wm.first, scene); } static int rna_Scene_object_bases_lookup_string(PointerRNA *ptr, const char *key, PointerRNA *r_ptr) @@ -554,6 +554,7 @@ static void rna_Scene_set_set(PointerRNA *ptr, PointerRNA value) return; } + id_lib_extern((ID *)set); scene->set = set; } @@ -1950,7 +1951,7 @@ static void rna_Stereo3dFormat_update(Main *UNUSED(bmain), Scene *UNUSED(scene), ImBuf *ibuf; void *lock; - if ((ima->flag & IMA_IS_STEREO) == 0) + if (!BKE_image_is_stereo(ima)) return; ibuf = BKE_image_acquire_ibuf(ima, NULL, &lock); @@ -2219,7 +2220,7 @@ static void rna_def_tool_settings(BlenderRNA *brna) RNA_def_property_boolean_sdna(prop, NULL, "snap_flag", SCE_SNAP_ABS_GRID); RNA_def_property_ui_text(prop, "Absolute Grid Snap", "Absolute grid alignment while translating (based on the pivot center)"); - RNA_def_property_ui_icon(prop, ICON_SNAP_INCREMENT, 0); + RNA_def_property_ui_icon(prop, ICON_SNAP_GRID, 0); RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL); /* header redraw */ prop = RNA_def_property(srna, "snap_element", PROP_ENUM, PROP_NONE); @@ -2550,7 +2551,7 @@ static void rna_def_statvis(BlenderRNA *brna) RNA_def_property_float_sdna(prop, NULL, "overhang_max"); RNA_def_property_float_default(prop, 0.5f); RNA_def_property_range(prop, 0.0f, DEG2RADF(180.0f)); - RNA_def_property_ui_range(prop, 0.0f, DEG2RADF(180.0f), 0.001, 3); + RNA_def_property_ui_range(prop, 0.0f, DEG2RADF(180.0f), 10, 3); RNA_def_property_ui_text(prop, "Overhang Max", "Maximum angle to display"); RNA_def_property_update(prop, 0, "rna_EditMesh_update"); @@ -2589,7 +2590,7 @@ static void rna_def_statvis(BlenderRNA *brna) RNA_def_property_float_sdna(prop, NULL, "distort_min"); RNA_def_property_float_default(prop, 0.5f); RNA_def_property_range(prop, 0.0f, DEG2RADF(180.0f)); - RNA_def_property_ui_range(prop, 0.0f, DEG2RADF(180.0f), 0.001, 3); + RNA_def_property_ui_range(prop, 0.0f, DEG2RADF(180.0f), 10, 3); RNA_def_property_ui_text(prop, "Distort Min", "Minimum angle to display"); RNA_def_property_update(prop, 0, "rna_EditMesh_update"); @@ -2597,7 +2598,7 @@ static void rna_def_statvis(BlenderRNA *brna) RNA_def_property_float_sdna(prop, NULL, "distort_max"); RNA_def_property_float_default(prop, 0.5f); RNA_def_property_range(prop, 0.0f, DEG2RADF(180.0f)); - RNA_def_property_ui_range(prop, 0.0f, DEG2RADF(180.0f), 0.001, 3); + RNA_def_property_ui_range(prop, 0.0f, DEG2RADF(180.0f), 10, 3); RNA_def_property_ui_text(prop, "Distort Max", "Maximum angle to display"); RNA_def_property_update(prop, 0, "rna_EditMesh_update"); @@ -2606,7 +2607,7 @@ static void rna_def_statvis(BlenderRNA *brna) RNA_def_property_float_sdna(prop, NULL, "sharp_min"); RNA_def_property_float_default(prop, 0.5f); RNA_def_property_range(prop, -DEG2RADF(180.0f), DEG2RADF(180.0f)); - RNA_def_property_ui_range(prop, -DEG2RADF(180.0f), DEG2RADF(180.0f), 0.001, 3); + RNA_def_property_ui_range(prop, -DEG2RADF(180.0f), DEG2RADF(180.0f), 10, 3); RNA_def_property_ui_text(prop, "Distort Min", "Minimum angle to display"); RNA_def_property_update(prop, 0, "rna_EditMesh_update"); @@ -2614,7 +2615,7 @@ static void rna_def_statvis(BlenderRNA *brna) RNA_def_property_float_sdna(prop, NULL, "sharp_max"); RNA_def_property_float_default(prop, 0.5f); RNA_def_property_range(prop, -DEG2RADF(180.0f), DEG2RADF(180.0f)); - RNA_def_property_ui_range(prop, -DEG2RADF(180.0f), DEG2RADF(180.0f), 0.001, 3); + RNA_def_property_ui_range(prop, -DEG2RADF(180.0f), DEG2RADF(180.0f), 10, 3); RNA_def_property_ui_text(prop, "Distort Max", "Maximum angle to display"); RNA_def_property_update(prop, 0, "rna_EditMesh_update"); } @@ -3814,6 +3815,7 @@ static void rna_def_scene_game_data(BlenderRNA *brna) prop = RNA_def_property(srna, "exit_key", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "exitkey"); RNA_def_property_enum_items(prop, event_type_items); + RNA_def_property_translation_context(prop, BLT_I18NCONTEXT_UI_EVENTS); RNA_def_property_enum_default(prop, ESCKEY); RNA_def_property_enum_funcs(prop, NULL, "rna_GameSettings_exit_key_set", NULL); RNA_def_property_ui_text(prop, "Exit Key", "The key that exits the Game Engine"); diff --git a/source/blender/makesrna/intern/rna_sensor.c b/source/blender/makesrna/intern/rna_sensor.c index baf0ae3ccf5..dec305de192 100644 --- a/source/blender/makesrna/intern/rna_sensor.c +++ b/source/blender/makesrna/intern/rna_sensor.c @@ -458,6 +458,7 @@ static void rna_def_keyboard_sensor(BlenderRNA *brna) prop = RNA_def_property(srna, "key", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "key"); RNA_def_property_enum_items(prop, event_type_items); + RNA_def_property_translation_context(prop, BLT_I18NCONTEXT_UI_EVENTS); RNA_def_property_enum_funcs(prop, NULL, "rna_Sensor_keyboard_key_set", NULL); RNA_def_property_ui_text(prop, "Key", ""); RNA_def_property_translation_context(prop, BLT_I18NCONTEXT_ID_WINDOWMANAGER); @@ -466,6 +467,7 @@ static void rna_def_keyboard_sensor(BlenderRNA *brna) prop = RNA_def_property(srna, "modifier_key_1", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "qual"); RNA_def_property_enum_items(prop, event_type_items); + RNA_def_property_translation_context(prop, BLT_I18NCONTEXT_UI_EVENTS); RNA_def_property_enum_funcs(prop, NULL, "rna_Sensor_keyboard_modifier_set", NULL); RNA_def_property_ui_text(prop, "Modifier Key", "Modifier key code"); RNA_def_property_update(prop, NC_LOGIC, NULL); @@ -473,6 +475,7 @@ static void rna_def_keyboard_sensor(BlenderRNA *brna) prop = RNA_def_property(srna, "modifier_key_2", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "qual2"); RNA_def_property_enum_items(prop, event_type_items); + RNA_def_property_translation_context(prop, BLT_I18NCONTEXT_UI_EVENTS); RNA_def_property_enum_funcs(prop, NULL, "rna_Sensor_keyboard_modifier2_set", NULL); RNA_def_property_ui_text(prop, "Second Modifier Key", "Modifier key code"); RNA_def_property_update(prop, NC_LOGIC, NULL); @@ -813,7 +816,7 @@ static void rna_def_joystick_sensor(BlenderRNA *brna) StructRNA *srna; PropertyRNA *prop; - static EnumPropertyItem event_type_items[] = { + static EnumPropertyItem event_type_joystick_items[] = { {SENS_JOY_BUTTON, "BUTTON", 0, "Button", ""}, {SENS_JOY_AXIS, "AXIS", 0, "Axis", ""}, {SENS_JOY_HAT, "HAT", 0, "Hat", ""}, @@ -854,7 +857,8 @@ static void rna_def_joystick_sensor(BlenderRNA *brna) prop = RNA_def_property(srna, "event_type", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "type"); - RNA_def_property_enum_items(prop, event_type_items); + RNA_def_property_enum_items(prop, event_type_joystick_items); + RNA_def_property_translation_context(prop, BLT_I18NCONTEXT_UI_EVENTS); RNA_def_property_ui_text(prop, "Event Type", "The type of event this joystick sensor is triggered on"); RNA_def_property_update(prop, NC_LOGIC, NULL); diff --git a/source/blender/makesrna/intern/rna_sequencer.c b/source/blender/makesrna/intern/rna_sequencer.c index bfb62395435..2192eae9fe6 100644 --- a/source/blender/makesrna/intern/rna_sequencer.c +++ b/source/blender/makesrna/intern/rna_sequencer.c @@ -2307,10 +2307,16 @@ static void rna_def_gaussian_blur(StructRNA *srna) static void rna_def_text(StructRNA *srna) { - static EnumPropertyItem text_align_items[] = { - {SEQ_TEXT_ALIGN_LEFT, "LEFT", 0, "Left", ""}, - {SEQ_TEXT_ALIGN_CENTER, "CENTER", 0, "Center", ""}, - {SEQ_TEXT_ALIGN_RIGHT, "RIGHT", 0, "Right", ""}, + static EnumPropertyItem text_align_x_items[] = { + {SEQ_TEXT_ALIGN_X_LEFT, "LEFT", 0, "Left", ""}, + {SEQ_TEXT_ALIGN_X_CENTER, "CENTER", 0, "Center", ""}, + {SEQ_TEXT_ALIGN_X_RIGHT, "RIGHT", 0, "Right", ""}, + {0, NULL, 0, NULL, NULL} + }; + static EnumPropertyItem text_align_y_items[] = { + {SEQ_TEXT_ALIGN_Y_TOP, "TOP", 0, "Top", ""}, + {SEQ_TEXT_ALIGN_Y_CENTER, "CENTER", 0, "Center", ""}, + {SEQ_TEXT_ALIGN_Y_BOTTOM, "BOTTOM", 0, "Bottom", ""}, {0, NULL, 0, NULL, NULL} }; @@ -2324,17 +2330,30 @@ static void rna_def_text(StructRNA *srna) RNA_def_property_ui_range(prop, 0.0f, 1000, 1, -1); RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_update"); - prop = RNA_def_property(srna, "location", PROP_FLOAT, PROP_NONE); + prop = RNA_def_property(srna, "location", PROP_FLOAT, PROP_XYZ); RNA_def_property_float_sdna(prop, NULL, "loc"); RNA_def_property_ui_text(prop, "Location", "Location of the text"); RNA_def_property_range(prop, -FLT_MAX, FLT_MAX); RNA_def_property_ui_range(prop, 0.0, 1.0, 1, -1); RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_update"); - prop = RNA_def_property(srna, "align", PROP_ENUM, PROP_NONE); + prop = RNA_def_property(srna, "wrap_width", PROP_FLOAT, PROP_NONE); + RNA_def_property_float_sdna(prop, NULL, "wrap_width"); + RNA_def_property_ui_text(prop, "Wrap Width", "Word wrap width as factor, zero disables"); + RNA_def_property_range(prop, 0, FLT_MAX); + RNA_def_property_ui_range(prop, 0.0, 1.0, 1, -1); + RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_update"); + + prop = RNA_def_property(srna, "align_x", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "align"); - RNA_def_property_enum_items(prop, text_align_items); - RNA_def_property_ui_text(prop, "Align", ""); + RNA_def_property_enum_items(prop, text_align_x_items); + RNA_def_property_ui_text(prop, "Align X", ""); + RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_update"); + + prop = RNA_def_property(srna, "align_y", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_sdna(prop, NULL, "align_y"); + RNA_def_property_enum_items(prop, text_align_y_items); + RNA_def_property_ui_text(prop, "Align Y", ""); RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_update"); prop = RNA_def_property(srna, "text", PROP_STRING, PROP_NONE); diff --git a/source/blender/makesrna/intern/rna_space.c b/source/blender/makesrna/intern/rna_space.c index 4836d93876e..8a7ef7cfac1 100644 --- a/source/blender/makesrna/intern/rna_space.c +++ b/source/blender/makesrna/intern/rna_space.c @@ -740,7 +740,7 @@ static PointerRNA rna_SpaceImageEditor_uvedit_get(PointerRNA *ptr) static void rna_SpaceImageEditor_mode_update(Main *bmain, Scene *scene, PointerRNA *UNUSED(ptr)) { - ED_space_image_paint_update(bmain->wm.first, scene->toolsettings); + ED_space_image_paint_update(bmain->wm.first, scene); } @@ -1627,7 +1627,7 @@ static int rna_FileBrowser_FSMenuEntry_name_get_editable(PointerRNA *ptr) { FSMenuEntry *fsm = ptr->data; - return fsm->save; + return fsm->save ? PROP_EDITABLE : 0; } static void rna_FileBrowser_FSMenu_next(CollectionPropertyIterator *iter) @@ -3774,13 +3774,13 @@ static void rna_def_fileselect_params(BlenderRNA *brna) PropertyRNA *prop; static EnumPropertyItem file_display_items[] = { - {FILE_SHORTDISPLAY, "FILE_SHORTDISPLAY", ICON_SHORTDISPLAY, "Short List", "Display files as short list"}, - {FILE_LONGDISPLAY, "FILE_LONGDISPLAY", ICON_LONGDISPLAY, "Long List", "Display files as a detailed list"}, - {FILE_IMGDISPLAY, "FILE_IMGDISPLAY", ICON_IMGDISPLAY, "Thumbnails", "Display files as thumbnails"}, + {FILE_SHORTDISPLAY, "LIST_SHORT", ICON_SHORTDISPLAY, "Short List", "Display files as short list"}, + {FILE_LONGDISPLAY, "LIST_LONG", ICON_LONGDISPLAY, "Long List", "Display files as a detailed list"}, + {FILE_IMGDISPLAY, "THUMBNAIL", ICON_IMGDISPLAY, "Thumbnails", "Display files as thumbnails"}, {0, NULL, 0, NULL, NULL} }; - static EnumPropertyItem thumbnail_size_items[] = { + static EnumPropertyItem display_size_items[] = { {32, "TINY", 0, "Tiny", ""}, {64, "SMALL", 0, "Small", ""}, {128, "NORMAL", 0, "Normal", ""}, @@ -3979,10 +3979,11 @@ static void rna_def_fileselect_params(BlenderRNA *brna) RNA_def_property_flag(prop, PROP_TEXTEDIT_UPDATE); RNA_def_property_update(prop, NC_SPACE | ND_SPACE_FILE_LIST, NULL); - prop = RNA_def_property(srna, "thumbnail_size", PROP_ENUM, PROP_NONE); + prop = RNA_def_property(srna, "display_size", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "thumbnail_size"); - RNA_def_property_enum_items(prop, thumbnail_size_items); - RNA_def_property_ui_text(prop, "Thumbnails Size", "Change the size of the thumbnails"); + RNA_def_property_enum_items(prop, display_size_items); + RNA_def_property_ui_text(prop, "Display Size", + "Change the size of the display (width of columns or thumbnails size)"); RNA_def_property_update(prop, NC_SPACE | ND_SPACE_FILE_LIST, NULL); } diff --git a/source/blender/makesrna/intern/rna_vfont.c b/source/blender/makesrna/intern/rna_vfont.c index 0879f4d355d..e9ba0c78439 100644 --- a/source/blender/makesrna/intern/rna_vfont.c +++ b/source/blender/makesrna/intern/rna_vfont.c @@ -48,9 +48,9 @@ static int rna_VectorFont_filepath_editable(PointerRNA *ptr) { VFont *vfont = ptr->id.data; if (BKE_vfont_is_builtin(vfont)) { - return false; + return 0; } - return true; + return PROP_EDITABLE; } static void rna_VectorFont_reload_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr) diff --git a/source/blender/makesrna/intern/rna_wm.c b/source/blender/makesrna/intern/rna_wm.c index c982c139a53..37550b1eaed 100644 --- a/source/blender/makesrna/intern/rna_wm.c +++ b/source/blender/makesrna/intern/rna_wm.c @@ -1948,6 +1948,7 @@ static void rna_def_event(BlenderRNA *brna) prop = RNA_def_property(srna, "type", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "type"); RNA_def_property_enum_items(prop, event_type_items); + RNA_def_property_translation_context(prop, BLT_I18NCONTEXT_UI_EVENTS); RNA_def_property_clear_flag(prop, PROP_EDITABLE); RNA_def_property_ui_text(prop, "Type", ""); @@ -2394,6 +2395,7 @@ static void rna_def_keyconfig(BlenderRNA *brna) prop = RNA_def_property(srna, "type", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "type"); RNA_def_property_enum_items(prop, event_type_items); + RNA_def_property_translation_context(prop, BLT_I18NCONTEXT_UI_EVENTS); RNA_def_property_enum_funcs(prop, NULL, NULL, "rna_KeyMapItem_type_itemf"); RNA_def_property_ui_text(prop, "Type", "Type of event"); RNA_def_property_update(prop, 0, "rna_KeyMapItem_update"); @@ -2451,6 +2453,7 @@ static void rna_def_keyconfig(BlenderRNA *brna) prop = RNA_def_property(srna, "key_modifier", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "keymodifier"); RNA_def_property_enum_items(prop, event_type_items); + RNA_def_property_translation_context(prop, BLT_I18NCONTEXT_UI_EVENTS); RNA_def_property_enum_funcs(prop, NULL, "rna_wmKeyMapItem_keymodifier_set", NULL); RNA_def_property_ui_text(prop, "Key Modifier", "Regular key pressed as a modifier"); RNA_def_property_update(prop, 0, "rna_KeyMapItem_update"); diff --git a/source/blender/modifiers/intern/MOD_armature.c b/source/blender/modifiers/intern/MOD_armature.c index 9ce31cebb66..d9ace45453c 100644 --- a/source/blender/modifiers/intern/MOD_armature.c +++ b/source/blender/modifiers/intern/MOD_armature.c @@ -45,6 +45,7 @@ #include "BKE_cdderivedmesh.h" #include "BKE_lattice.h" +#include "BKE_library_query.h" #include "BKE_modifier.h" #include "MEM_guardedalloc.h" @@ -91,12 +92,11 @@ static bool isDisabled(ModifierData *md, int UNUSED(useRenderParams)) static void foreachObjectLink( ModifierData *md, Object *ob, - void (*walk)(void *userData, Object *ob, Object **obpoin), - void *userData) + ObjectWalkFunc walk, void *userData) { ArmatureModifierData *amd = (ArmatureModifierData *) md; - walk(userData, ob, &amd->object); + walk(userData, ob, &amd->object, IDWALK_NOP); } static void updateDepgraph(ModifierData *md, DagForest *forest, diff --git a/source/blender/modifiers/intern/MOD_array.c b/source/blender/modifiers/intern/MOD_array.c index efb77f73ec9..15a7e51e865 100644 --- a/source/blender/modifiers/intern/MOD_array.c +++ b/source/blender/modifiers/intern/MOD_array.c @@ -48,6 +48,7 @@ #include "BKE_cdderivedmesh.h" #include "BKE_displist.h" #include "BKE_curve.h" +#include "BKE_library_query.h" #include "BKE_modifier.h" #include "MOD_util.h" @@ -90,15 +91,14 @@ static void copyData(ModifierData *md, ModifierData *target) static void foreachObjectLink( ModifierData *md, Object *ob, - void (*walk)(void *userData, Object *ob, Object **obpoin), - void *userData) + ObjectWalkFunc walk, void *userData) { ArrayModifierData *amd = (ArrayModifierData *) md; - walk(userData, ob, &amd->start_cap); - walk(userData, ob, &amd->end_cap); - walk(userData, ob, &amd->curve_ob); - walk(userData, ob, &amd->offset_ob); + walk(userData, ob, &amd->start_cap, IDWALK_NOP); + walk(userData, ob, &amd->end_cap, IDWALK_NOP); + walk(userData, ob, &amd->curve_ob, IDWALK_NOP); + walk(userData, ob, &amd->offset_ob, IDWALK_NOP); } static void updateDepgraph(ModifierData *md, DagForest *forest, diff --git a/source/blender/modifiers/intern/MOD_boolean.c b/source/blender/modifiers/intern/MOD_boolean.c index eb54a3c4e9c..3fd2c8a3502 100644 --- a/source/blender/modifiers/intern/MOD_boolean.c +++ b/source/blender/modifiers/intern/MOD_boolean.c @@ -40,6 +40,7 @@ #include "BLI_utildefines.h" #include "BKE_cdderivedmesh.h" +#include "BKE_library_query.h" #include "BKE_modifier.h" #include "depsgraph_private.h" @@ -65,12 +66,11 @@ static bool isDisabled(ModifierData *md, int UNUSED(useRenderParams)) static void foreachObjectLink( ModifierData *md, Object *ob, - void (*walk)(void *userData, Object *ob, Object **obpoin), - void *userData) + ObjectWalkFunc walk, void *userData) { BooleanModifierData *bmd = (BooleanModifierData *) md; - walk(userData, ob, &bmd->object); + walk(userData, ob, &bmd->object, IDWALK_NOP); } static void updateDepgraph(ModifierData *md, DagForest *forest, diff --git a/source/blender/modifiers/intern/MOD_cast.c b/source/blender/modifiers/intern/MOD_cast.c index 7c3d65a5c9a..32c3d41c4b6 100644 --- a/source/blender/modifiers/intern/MOD_cast.c +++ b/source/blender/modifiers/intern/MOD_cast.c @@ -42,6 +42,7 @@ #include "BKE_deform.h" #include "BKE_DerivedMesh.h" +#include "BKE_library_query.h" #include "BKE_modifier.h" @@ -97,12 +98,11 @@ static CustomDataMask requiredDataMask(Object *UNUSED(ob), ModifierData *md) static void foreachObjectLink( ModifierData *md, Object *ob, - void (*walk)(void *userData, Object *ob, Object **obpoin), - void *userData) + ObjectWalkFunc walk, void *userData) { CastModifierData *cmd = (CastModifierData *) md; - walk(userData, ob, &cmd->object); + walk(userData, ob, &cmd->object, IDWALK_NOP); } static void updateDepgraph(ModifierData *md, DagForest *forest, diff --git a/source/blender/modifiers/intern/MOD_cloth.c b/source/blender/modifiers/intern/MOD_cloth.c index dac0e516e0d..6cc2f097be8 100644 --- a/source/blender/modifiers/intern/MOD_cloth.c +++ b/source/blender/modifiers/intern/MOD_cloth.c @@ -49,6 +49,7 @@ #include "BKE_effect.h" #include "BKE_global.h" #include "BKE_key.h" +#include "BKE_library_query.h" #include "BKE_modifier.h" #include "BKE_pointcache.h" @@ -241,11 +242,11 @@ static void foreachIDLink(ModifierData *md, Object *ob, ClothModifierData *clmd = (ClothModifierData *) md; if (clmd->coll_parms) { - walk(userData, ob, (ID **)&clmd->coll_parms->group); + walk(userData, ob, (ID **)&clmd->coll_parms->group, IDWALK_NOP); } if (clmd->sim_parms && clmd->sim_parms->effector_weights) { - walk(userData, ob, (ID **)&clmd->sim_parms->effector_weights->group); + walk(userData, ob, (ID **)&clmd->sim_parms->effector_weights->group, IDWALK_NOP); } } diff --git a/source/blender/modifiers/intern/MOD_curve.c b/source/blender/modifiers/intern/MOD_curve.c index 1488296caf9..6e2d746c858 100644 --- a/source/blender/modifiers/intern/MOD_curve.c +++ b/source/blender/modifiers/intern/MOD_curve.c @@ -42,6 +42,7 @@ #include "BKE_cdderivedmesh.h" #include "BKE_lattice.h" +#include "BKE_library_query.h" #include "BKE_modifier.h" #include "depsgraph_private.h" @@ -84,12 +85,11 @@ static bool isDisabled(ModifierData *md, int UNUSED(userRenderParams)) static void foreachObjectLink( ModifierData *md, Object *ob, - void (*walk)(void *userData, Object *ob, Object **obpoin), - void *userData) + ObjectWalkFunc walk, void *userData) { CurveModifierData *cmd = (CurveModifierData *) md; - walk(userData, ob, &cmd->object); + walk(userData, ob, &cmd->object, IDWALK_NOP); } static void updateDepgraph(ModifierData *md, DagForest *forest, @@ -112,7 +112,7 @@ static void updateDepgraph(ModifierData *md, DagForest *forest, static void updateDepsgraph(ModifierData *md, struct Main *UNUSED(bmain), struct Scene *scene, - Object *UNUSED(ob), + Object *object, struct DepsNodeHandle *node) { CurveModifierData *cmd = (CurveModifierData *)md; @@ -126,6 +126,8 @@ static void updateDepsgraph(ModifierData *md, DEG_add_object_relation(node, cmd->object, DEG_OB_COMP_GEOMETRY, "Curve Modifier"); DEG_add_special_eval_flag(scene->depsgraph, &cmd->object->id, DAG_EVAL_NEED_CURVE_PATH); } + + DEG_add_object_relation(node, object, DEG_OB_COMP_TRANSFORM, "Curve Modifier"); } static void deformVerts(ModifierData *md, Object *ob, diff --git a/source/blender/modifiers/intern/MOD_datatransfer.c b/source/blender/modifiers/intern/MOD_datatransfer.c index 85e9b4ee185..f5ab28d3d88 100644 --- a/source/blender/modifiers/intern/MOD_datatransfer.c +++ b/source/blender/modifiers/intern/MOD_datatransfer.c @@ -41,6 +41,7 @@ #include "BKE_data_transfer.h" #include "BKE_DerivedMesh.h" #include "BKE_library.h" +#include "BKE_library_query.h" #include "BKE_mesh_mapping.h" #include "BKE_mesh_remap.h" #include "BKE_modifier.h" @@ -118,17 +119,12 @@ static bool dependsOnNormals(ModifierData *md) return false; } -static void foreachObjectLink(ModifierData *md, Object *ob, - void (*walk)(void *userData, Object *ob, Object **obpoin), - void *userData) +static void foreachObjectLink( + ModifierData *md, Object *ob, + ObjectWalkFunc walk, void *userData) { DataTransferModifierData *dtmd = (DataTransferModifierData *) md; - walk(userData, ob, &dtmd->ob_source); -} - -static void foreachIDLink(ModifierData *md, Object *ob, IDWalkFunc walk, void *userData) -{ - foreachObjectLink(md, ob, (ObjectWalkFunc)walk, userData); + walk(userData, ob, &dtmd->ob_source, IDWALK_NOP); } static void updateDepgraph(ModifierData *md, DagForest *forest, @@ -260,6 +256,6 @@ ModifierTypeInfo modifierType_DataTransfer = { /* dependsOnTime */ NULL, /* dependsOnNormals */ dependsOnNormals, /* foreachObjectLink */ foreachObjectLink, - /* foreachIDLink */ foreachIDLink, + /* foreachIDLink */ NULL, /* foreachTexLink */ NULL, }; diff --git a/source/blender/modifiers/intern/MOD_displace.c b/source/blender/modifiers/intern/MOD_displace.c index 7523c7c7525..9ba2d214d50 100644 --- a/source/blender/modifiers/intern/MOD_displace.c +++ b/source/blender/modifiers/intern/MOD_displace.c @@ -41,6 +41,7 @@ #include "BKE_cdderivedmesh.h" #include "BKE_library.h" +#include "BKE_library_query.h" #include "BKE_mesh.h" #include "BKE_modifier.h" #include "BKE_texture.h" @@ -129,7 +130,7 @@ static void foreachObjectLink(ModifierData *md, Object *ob, { DisplaceModifierData *dmd = (DisplaceModifierData *) md; - walk(userData, ob, &dmd->map_object); + walk(userData, ob, &dmd->map_object, IDWALK_NOP); } static void foreachIDLink(ModifierData *md, Object *ob, @@ -137,7 +138,7 @@ static void foreachIDLink(ModifierData *md, Object *ob, { DisplaceModifierData *dmd = (DisplaceModifierData *) md; - walk(userData, ob, (ID **)&dmd->texture); + walk(userData, ob, (ID **)&dmd->texture, IDWALK_USER); foreachObjectLink(md, ob, (ObjectWalkFunc)walk, userData); } @@ -235,7 +236,8 @@ static void displaceModifier_do( clnors = CustomData_get_layer(ldata, CD_NORMAL); vert_clnors = MEM_mallocN(sizeof(*vert_clnors) * (size_t)numVerts, __func__); - BKE_mesh_normals_loop_to_vertex(numVerts, dm->getLoopArray(dm), dm->getNumLoops(dm), clnors, vert_clnors); + BKE_mesh_normals_loop_to_vertex(numVerts, dm->getLoopArray(dm), dm->getNumLoops(dm), + (const float (*)[3])clnors, vert_clnors); } else { direction = MOD_DISP_DIR_NOR; diff --git a/source/blender/modifiers/intern/MOD_dynamicpaint.c b/source/blender/modifiers/intern/MOD_dynamicpaint.c index f1b6ceb070c..91af9659d79 100644 --- a/source/blender/modifiers/intern/MOD_dynamicpaint.c +++ b/source/blender/modifiers/intern/MOD_dynamicpaint.c @@ -35,6 +35,7 @@ #include "BKE_cdderivedmesh.h" #include "BKE_dynamicpaint.h" +#include "BKE_library_query.h" #include "BKE_modifier.h" #include "depsgraph_private.h" @@ -170,12 +171,12 @@ static void foreachIDLink(ModifierData *md, Object *ob, DynamicPaintSurface *surface = pmd->canvas->surfaces.first; for (; surface; surface = surface->next) { - walk(userData, ob, (ID **)&surface->brush_group); - walk(userData, ob, (ID **)&surface->init_texture); + walk(userData, ob, (ID **)&surface->brush_group, IDWALK_NOP); + walk(userData, ob, (ID **)&surface->init_texture, IDWALK_USER); } } if (pmd->brush) { - walk(userData, ob, (ID **)&pmd->brush->mat); + walk(userData, ob, (ID **)&pmd->brush->mat, IDWALK_USER); } } diff --git a/source/blender/modifiers/intern/MOD_explode.c b/source/blender/modifiers/intern/MOD_explode.c index 82600421736..d57ace8d7fe 100644 --- a/source/blender/modifiers/intern/MOD_explode.c +++ b/source/blender/modifiers/intern/MOD_explode.c @@ -861,7 +861,7 @@ static DerivedMesh *explodeMesh(ExplodeModifierData *emd, BLI_edgehashIterator_free(ehi); /* the final duplicated vertices */ - explode = CDDM_from_template(dm, totdup, 0, totface - delface, 0, 0); + explode = CDDM_from_template_ex(dm, totdup, 0, totface - delface, 0, 0, CD_MASK_DERIVEDMESH | CD_MASK_FACECORNERS); mtface = CustomData_get_layer_named(&explode->faceData, CD_MTFACE, emd->uvname); /*dupvert = CDDM_get_verts(explode);*/ diff --git a/source/blender/modifiers/intern/MOD_hook.c b/source/blender/modifiers/intern/MOD_hook.c index 3a10fabbb8e..1a27202fb34 100644 --- a/source/blender/modifiers/intern/MOD_hook.c +++ b/source/blender/modifiers/intern/MOD_hook.c @@ -41,6 +41,7 @@ #include "BKE_action.h" #include "BKE_cdderivedmesh.h" +#include "BKE_library_query.h" #include "BKE_modifier.h" #include "BKE_deform.h" #include "BKE_colortools.h" @@ -103,12 +104,11 @@ static bool isDisabled(ModifierData *md, int UNUSED(useRenderParams)) static void foreachObjectLink( ModifierData *md, Object *ob, - void (*walk)(void *userData, Object *ob, Object **obpoin), - void *userData) + ObjectWalkFunc walk, void *userData) { HookModifierData *hmd = (HookModifierData *) md; - walk(userData, ob, &hmd->object); + walk(userData, ob, &hmd->object, IDWALK_NOP); } static void updateDepgraph(ModifierData *md, DagForest *forest, diff --git a/source/blender/modifiers/intern/MOD_lattice.c b/source/blender/modifiers/intern/MOD_lattice.c index 52a4f441b63..0f49ce6cfbf 100644 --- a/source/blender/modifiers/intern/MOD_lattice.c +++ b/source/blender/modifiers/intern/MOD_lattice.c @@ -41,6 +41,7 @@ #include "BKE_cdderivedmesh.h" #include "BKE_lattice.h" +#include "BKE_library_query.h" #include "BKE_modifier.h" #include "depsgraph_private.h" @@ -83,12 +84,11 @@ static bool isDisabled(ModifierData *md, int UNUSED(userRenderParams)) static void foreachObjectLink( ModifierData *md, Object *ob, - void (*walk)(void *userData, Object *ob, Object **obpoin), - void *userData) + ObjectWalkFunc walk, void *userData) { LatticeModifierData *lmd = (LatticeModifierData *) md; - walk(userData, ob, &lmd->object); + walk(userData, ob, &lmd->object, IDWALK_NOP); } static void updateDepgraph(ModifierData *md, DagForest *forest, diff --git a/source/blender/modifiers/intern/MOD_mask.c b/source/blender/modifiers/intern/MOD_mask.c index 06fbab65d7b..5e01a20d93b 100644 --- a/source/blender/modifiers/intern/MOD_mask.c +++ b/source/blender/modifiers/intern/MOD_mask.c @@ -46,6 +46,7 @@ #include "BKE_action.h" /* BKE_pose_channel_find_name */ #include "BKE_cdderivedmesh.h" +#include "BKE_library_query.h" #include "BKE_modifier.h" #include "BKE_deform.h" @@ -70,11 +71,10 @@ static CustomDataMask requiredDataMask(Object *UNUSED(ob), ModifierData *UNUSED( static void foreachObjectLink( ModifierData *md, Object *ob, - void (*walk)(void *userData, Object *ob, Object **obpoin), - void *userData) + ObjectWalkFunc walk, void *userData) { MaskModifierData *mmd = (MaskModifierData *)md; - walk(userData, ob, &mmd->ob_arm); + walk(userData, ob, &mmd->ob_arm, IDWALK_NOP); } static void updateDepgraph(ModifierData *md, DagForest *forest, diff --git a/source/blender/modifiers/intern/MOD_meshdeform.c b/source/blender/modifiers/intern/MOD_meshdeform.c index 5bd33d2a49f..8aa5f281f56 100644 --- a/source/blender/modifiers/intern/MOD_meshdeform.c +++ b/source/blender/modifiers/intern/MOD_meshdeform.c @@ -42,6 +42,7 @@ #include "BKE_cdderivedmesh.h" #include "BKE_global.h" +#include "BKE_library_query.h" #include "BKE_modifier.h" #include "BKE_deform.h" #include "BKE_editmesh.h" @@ -114,12 +115,11 @@ static bool isDisabled(ModifierData *md, int UNUSED(useRenderParams)) static void foreachObjectLink( ModifierData *md, Object *ob, - void (*walk)(void *userData, Object *ob, Object **obpoin), - void *userData) + ObjectWalkFunc walk, void *userData) { MeshDeformModifierData *mmd = (MeshDeformModifierData *) md; - walk(userData, ob, &mmd->object); + walk(userData, ob, &mmd->object, IDWALK_NOP); } static void updateDepgraph(ModifierData *md, DagForest *forest, diff --git a/source/blender/modifiers/intern/MOD_mirror.c b/source/blender/modifiers/intern/MOD_mirror.c index 3e10fa1d77d..88facb22e0e 100644 --- a/source/blender/modifiers/intern/MOD_mirror.c +++ b/source/blender/modifiers/intern/MOD_mirror.c @@ -39,6 +39,7 @@ #include "BLI_math.h" #include "BKE_cdderivedmesh.h" +#include "BKE_library_query.h" #include "BKE_modifier.h" #include "BKE_deform.h" @@ -65,13 +66,13 @@ static void copyData(ModifierData *md, ModifierData *target) modifier_copyData_generic(md, target); } -static void foreachObjectLink(ModifierData *md, Object *ob, - void (*walk)(void *userData, Object *ob, Object **obpoin), - void *userData) +static void foreachObjectLink( + ModifierData *md, Object *ob, + ObjectWalkFunc walk, void *userData) { MirrorModifierData *mmd = (MirrorModifierData *) md; - walk(userData, ob, &mmd->mirror_ob); + walk(userData, ob, &mmd->mirror_ob, IDWALK_NOP); } static void updateDepgraph(ModifierData *md, DagForest *forest, diff --git a/source/blender/modifiers/intern/MOD_normal_edit.c b/source/blender/modifiers/intern/MOD_normal_edit.c index 87d75c6f1a7..a24ed4d6614 100644 --- a/source/blender/modifiers/intern/MOD_normal_edit.c +++ b/source/blender/modifiers/intern/MOD_normal_edit.c @@ -38,6 +38,7 @@ #include "BLI_bitmap.h" #include "BKE_cdderivedmesh.h" +#include "BKE_library_query.h" #include "BKE_mesh.h" #include "BKE_deform.h" @@ -84,7 +85,7 @@ static void generate_vert_coordinates( /* Translate our coordinates so that center of ob_center is at (0, 0, 0). */ /* Get ob_center (world) coordinates in ob local coordinates. - * No need to take into accound ob_center's space here, see T44027. */ + * No need to take into account ob_center's space here, see T44027. */ invert_m4_m4(inv_obmat, ob->obmat); mul_v3_m4v3(diff, inv_obmat, ob_center->obmat[3]); negate_v3(diff); @@ -387,7 +388,7 @@ static DerivedMesh *normalEditModifier_do(NormalEditModifierData *smd, Object *o polynors = dm->getPolyDataArray(dm, CD_NORMAL); if (!polynors) { polynors = MEM_mallocN(sizeof(*polynors) * num_polys, __func__); - BKE_mesh_calc_normals_poly(mvert, num_verts, mloop, mpoly, num_loops, num_polys, polynors, false); + BKE_mesh_calc_normals_poly(mvert, NULL, num_verts, mloop, mpoly, num_loops, num_polys, polynors, false); free_polynors = true; } @@ -450,14 +451,7 @@ static void foreachObjectLink(ModifierData *md, Object *ob, ObjectWalkFunc walk, { NormalEditModifierData *smd = (NormalEditModifierData *) md; - walk(userData, ob, &smd->target); -} - -static void foreachIDLink(ModifierData *md, Object *ob, IDWalkFunc walk, void *userData) -{ - NormalEditModifierData *smd = (NormalEditModifierData *) md; - - walk(userData, ob, (ID **)&smd->target); + walk(userData, ob, &smd->target, IDWALK_NOP); } static bool isDisabled(ModifierData *md, int UNUSED(useRenderParams)) @@ -524,6 +518,6 @@ ModifierTypeInfo modifierType_NormalEdit = { /* dependsOnTime */ NULL, /* dependsOnNormals */ dependsOnNormals, /* foreachObjectLink */ foreachObjectLink, - /* foreachIDLink */ foreachIDLink, + /* foreachIDLink */ NULL, /* foreachTexLink */ NULL, }; diff --git a/source/blender/modifiers/intern/MOD_ocean.c b/source/blender/modifiers/intern/MOD_ocean.c index 913c2f25c15..54a7278be72 100644 --- a/source/blender/modifiers/intern/MOD_ocean.c +++ b/source/blender/modifiers/intern/MOD_ocean.c @@ -585,4 +585,5 @@ ModifierTypeInfo modifierType_Ocean = { /* dependsOnNormals */ dependsOnNormals, /* foreachObjectLink */ NULL, /* foreachIDLink */ NULL, + /* foreachTexLink */ NULL, }; diff --git a/source/blender/modifiers/intern/MOD_particleinstance.c b/source/blender/modifiers/intern/MOD_particleinstance.c index cb6234d50b7..289611ad90a 100644 --- a/source/blender/modifiers/intern/MOD_particleinstance.c +++ b/source/blender/modifiers/intern/MOD_particleinstance.c @@ -46,6 +46,7 @@ #include "BKE_effect.h" #include "BKE_global.h" #include "BKE_lattice.h" +#include "BKE_library_query.h" #include "BKE_modifier.h" #include "BKE_particle.h" #include "BKE_pointcache.h" @@ -144,7 +145,7 @@ static void foreachObjectLink(ModifierData *md, Object *ob, { ParticleInstanceModifierData *pimd = (ParticleInstanceModifierData *) md; - walk(userData, ob, &pimd->ob); + walk(userData, ob, &pimd->ob, IDWALK_NOP); } static int particle_skip(ParticleInstanceModifierData *pimd, ParticleSystem *psys, int p) diff --git a/source/blender/modifiers/intern/MOD_screw.c b/source/blender/modifiers/intern/MOD_screw.c index 2e431884845..41ebd865720 100644 --- a/source/blender/modifiers/intern/MOD_screw.c +++ b/source/blender/modifiers/intern/MOD_screw.c @@ -44,6 +44,7 @@ #include "BLI_utildefines.h" #include "BKE_cdderivedmesh.h" +#include "BKE_library_query.h" #include "depsgraph_private.h" #include "DEG_depsgraph_build.h" @@ -766,7 +767,7 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *ob, } /* we wont be looping on this data again so copy normals here */ - if (angle < 0.0f) + if ((angle < 0.0f) != do_flip) negate_v3(vc->no); normalize_v3(vc->no); @@ -1090,12 +1091,11 @@ static void updateDepsgraph(ModifierData *md, static void foreachObjectLink( ModifierData *md, Object *ob, - void (*walk)(void *userData, Object *ob, Object **obpoin), - void *userData) + ObjectWalkFunc walk, void *userData) { ScrewModifierData *ltmd = (ScrewModifierData *) md; - walk(userData, ob, <md->ob_axis); + walk(userData, ob, <md->ob_axis, IDWALK_NOP); } ModifierTypeInfo modifierType_Screw = { diff --git a/source/blender/modifiers/intern/MOD_shrinkwrap.c b/source/blender/modifiers/intern/MOD_shrinkwrap.c index 91be0c40059..a9919cadd16 100644 --- a/source/blender/modifiers/intern/MOD_shrinkwrap.c +++ b/source/blender/modifiers/intern/MOD_shrinkwrap.c @@ -41,6 +41,7 @@ #include "BLI_utildefines.h" #include "BKE_cdderivedmesh.h" +#include "BKE_library_query.h" #include "BKE_modifier.h" #include "BKE_shrinkwrap.h" @@ -100,8 +101,8 @@ static void foreachObjectLink(ModifierData *md, Object *ob, ObjectWalkFunc walk, { ShrinkwrapModifierData *smd = (ShrinkwrapModifierData *) md; - walk(userData, ob, &smd->target); - walk(userData, ob, &smd->auxTarget); + walk(userData, ob, &smd->target, IDWALK_NOP); + walk(userData, ob, &smd->auxTarget, IDWALK_NOP); } static void deformVerts(ModifierData *md, Object *ob, diff --git a/source/blender/modifiers/intern/MOD_simpledeform.c b/source/blender/modifiers/intern/MOD_simpledeform.c index 706a296f5a1..f4fbfa74076 100644 --- a/source/blender/modifiers/intern/MOD_simpledeform.c +++ b/source/blender/modifiers/intern/MOD_simpledeform.c @@ -40,6 +40,7 @@ #include "BLI_utildefines.h" #include "BKE_cdderivedmesh.h" +#include "BKE_library_query.h" #include "BKE_modifier.h" #include "BKE_deform.h" @@ -279,11 +280,12 @@ static CustomDataMask requiredDataMask(Object *UNUSED(ob), ModifierData *md) return dataMask; } -static void foreachObjectLink(ModifierData *md, Object *ob, - void (*walk)(void *userData, Object *ob, Object **obpoin), void *userData) +static void foreachObjectLink( + ModifierData *md, Object *ob, + ObjectWalkFunc walk, void *userData) { SimpleDeformModifierData *smd = (SimpleDeformModifierData *)md; - walk(userData, ob, &smd->origin); + walk(userData, ob, &smd->origin, IDWALK_NOP); } static void updateDepgraph(ModifierData *md, DagForest *forest, diff --git a/source/blender/modifiers/intern/MOD_smoke.c b/source/blender/modifiers/intern/MOD_smoke.c index 657c4e09d96..f0f235c8ad5 100644 --- a/source/blender/modifiers/intern/MOD_smoke.c +++ b/source/blender/modifiers/intern/MOD_smoke.c @@ -48,6 +48,7 @@ #include "BKE_cdderivedmesh.h" #include "BKE_library.h" +#include "BKE_library_query.h" #include "BKE_main.h" #include "BKE_modifier.h" #include "BKE_smoke.h" @@ -339,17 +340,17 @@ static void foreachIDLink(ModifierData *md, Object *ob, SmokeModifierData *smd = (SmokeModifierData *) md; if (smd->type == MOD_SMOKE_TYPE_DOMAIN && smd->domain) { - walk(userData, ob, (ID **)&smd->domain->coll_group); - walk(userData, ob, (ID **)&smd->domain->fluid_group); - walk(userData, ob, (ID **)&smd->domain->eff_group); + walk(userData, ob, (ID **)&smd->domain->coll_group, IDWALK_NOP); + walk(userData, ob, (ID **)&smd->domain->fluid_group, IDWALK_NOP); + walk(userData, ob, (ID **)&smd->domain->eff_group, IDWALK_NOP); if (smd->domain->effector_weights) { - walk(userData, ob, (ID **)&smd->domain->effector_weights->group); + walk(userData, ob, (ID **)&smd->domain->effector_weights->group, IDWALK_NOP); } } if (smd->type == MOD_SMOKE_TYPE_FLOW && smd->flow) { - walk(userData, ob, (ID **)&smd->flow->noise_texture); + walk(userData, ob, (ID **)&smd->flow->noise_texture, IDWALK_USER); } } diff --git a/source/blender/modifiers/intern/MOD_solidify.c b/source/blender/modifiers/intern/MOD_solidify.c index ca2dcfec3a3..2695f6675c9 100644 --- a/source/blender/modifiers/intern/MOD_solidify.c +++ b/source/blender/modifiers/intern/MOD_solidify.c @@ -272,7 +272,7 @@ static DerivedMesh *applyModifier( /* calculate only face normals */ face_nors = MEM_mallocN(sizeof(*face_nors) * (size_t)numFaces, __func__); BKE_mesh_calc_normals_poly( - orig_mvert, (int)numVerts, + orig_mvert, NULL, (int)numVerts, orig_mloop, orig_mpoly, (int)numLoops, (int)numFaces, face_nors, true); diff --git a/source/blender/modifiers/intern/MOD_subsurf.c b/source/blender/modifiers/intern/MOD_subsurf.c index ab52d798cf8..23ab61821f4 100644 --- a/source/blender/modifiers/intern/MOD_subsurf.c +++ b/source/blender/modifiers/intern/MOD_subsurf.c @@ -108,10 +108,8 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *ob, #ifdef WITH_OPENSUBDIV const bool allow_gpu = (flag & MOD_APPLY_ALLOW_GPU) != 0; - const bool do_cddm_convert = useRenderParams || (!isFinalCalc && !smd->use_opensubdiv); -#else - const bool do_cddm_convert = useRenderParams || !isFinalCalc; #endif + bool do_cddm_convert = useRenderParams || !isFinalCalc; if (useRenderParams) subsurf_flags |= SUBSURF_USE_RENDER_PARAMS; @@ -134,6 +132,7 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *ob, } else if ((DAG_get_eval_flags_for_object(md->scene, ob) & DAG_EVAL_NEED_CPU) == 0) { subsurf_flags |= SUBSURF_USE_GPU_BACKEND; + do_cddm_convert = false; } else { modifier_setError(md, "OpenSubdiv is disabled due to dependencies"); @@ -164,11 +163,8 @@ static DerivedMesh *applyModifierEM(ModifierData *md, Object *UNUSED(ob), SubsurfFlags ss_flags = (flag & MOD_APPLY_ORCO) ? 0 : (SUBSURF_FOR_EDIT_MODE | SUBSURF_IN_EDIT_MODE); #ifdef WITH_OPENSUBDIV const bool allow_gpu = (flag & MOD_APPLY_ALLOW_GPU) != 0; - /* TODO(sergey): Not entirely correct, modifiers on top of subsurf - * could be disabled. - */ if (md->next == NULL && allow_gpu && smd->use_opensubdiv) { - ss_flags |= SUBSURF_USE_GPU_BACKEND; + modifier_setError(md, "OpenSubdiv is not supported in edit mode"); } #endif diff --git a/source/blender/modifiers/intern/MOD_surface.c b/source/blender/modifiers/intern/MOD_surface.c index ff5e5f643a7..68987a1d28e 100644 --- a/source/blender/modifiers/intern/MOD_surface.c +++ b/source/blender/modifiers/intern/MOD_surface.c @@ -190,6 +190,6 @@ ModifierTypeInfo modifierType_Surface = { /* dependsOnTime */ dependsOnTime, /* dependsOnNormals */ NULL, /* foreachObjectLink */ NULL, - /* foreachIDLink */ NULL, - /* foreachTexLink */ NULL, + /* foreachIDLink */ NULL, + /* foreachTexLink */ NULL, }; diff --git a/source/blender/modifiers/intern/MOD_uvproject.c b/source/blender/modifiers/intern/MOD_uvproject.c index 1b1474ee666..fb7668d16e0 100644 --- a/source/blender/modifiers/intern/MOD_uvproject.c +++ b/source/blender/modifiers/intern/MOD_uvproject.c @@ -45,6 +45,7 @@ #include "BKE_camera.h" +#include "BKE_library_query.h" #include "BKE_mesh.h" #include "BKE_DerivedMesh.h" @@ -91,7 +92,7 @@ static void foreachObjectLink(ModifierData *md, Object *ob, int i; for (i = 0; i < MOD_UVPROJECT_MAXPROJECTORS; ++i) - walk(userData, ob, &umd->projectors[i]); + walk(userData, ob, &umd->projectors[i], IDWALK_NOP); } static void foreachIDLink(ModifierData *md, Object *ob, @@ -99,10 +100,9 @@ static void foreachIDLink(ModifierData *md, Object *ob, { UVProjectModifierData *umd = (UVProjectModifierData *) md; - walk(userData, ob, (ID **)&umd->image); + walk(userData, ob, (ID **)&umd->image, IDWALK_USER); - foreachObjectLink(md, ob, (ObjectWalkFunc)walk, - userData); + foreachObjectLink(md, ob, (ObjectWalkFunc)walk, userData); } static void updateDepgraph(ModifierData *md, DagForest *forest, diff --git a/source/blender/modifiers/intern/MOD_uvwarp.c b/source/blender/modifiers/intern/MOD_uvwarp.c index 3c4ca66485d..5418c222d13 100644 --- a/source/blender/modifiers/intern/MOD_uvwarp.c +++ b/source/blender/modifiers/intern/MOD_uvwarp.c @@ -36,6 +36,7 @@ #include "BKE_action.h" /* BKE_pose_channel_find_name */ #include "BKE_cdderivedmesh.h" #include "BKE_deform.h" +#include "BKE_library_query.h" #include "BKE_modifier.h" #include "depsgraph_private.h" @@ -200,8 +201,8 @@ static void foreachObjectLink(ModifierData *md, Object *ob, ObjectWalkFunc walk, { UVWarpModifierData *umd = (UVWarpModifierData *) md; - walk(userData, ob, &umd->object_dst); - walk(userData, ob, &umd->object_src); + walk(userData, ob, &umd->object_dst, IDWALK_NOP); + walk(userData, ob, &umd->object_src, IDWALK_NOP); } static void uv_warp_deps_object_bone(DagForest *forest, DagNode *obNode, diff --git a/source/blender/modifiers/intern/MOD_warp.c b/source/blender/modifiers/intern/MOD_warp.c index ae2dbd4a37c..27d3bac59ec 100644 --- a/source/blender/modifiers/intern/MOD_warp.c +++ b/source/blender/modifiers/intern/MOD_warp.c @@ -36,6 +36,7 @@ #include "BLI_utildefines.h" #include "BKE_cdderivedmesh.h" +#include "BKE_library_query.h" #include "BKE_modifier.h" #include "BKE_deform.h" #include "BKE_texture.h" @@ -115,20 +116,18 @@ static void foreachObjectLink(ModifierData *md, Object *ob, ObjectWalkFunc walk, { WarpModifierData *wmd = (WarpModifierData *) md; - walk(userData, ob, &wmd->object_from); - walk(userData, ob, &wmd->object_to); - walk(userData, ob, &wmd->map_object); + walk(userData, ob, &wmd->object_from, IDWALK_NOP); + walk(userData, ob, &wmd->object_to, IDWALK_NOP); + walk(userData, ob, &wmd->map_object, IDWALK_NOP); } static void foreachIDLink(ModifierData *md, Object *ob, IDWalkFunc walk, void *userData) { WarpModifierData *wmd = (WarpModifierData *) md; - walk(userData, ob, (ID **)&wmd->texture); + walk(userData, ob, (ID **)&wmd->texture, IDWALK_USER); - walk(userData, ob, (ID **)&wmd->object_from); - walk(userData, ob, (ID **)&wmd->object_to); - walk(userData, ob, (ID **)&wmd->map_object); + foreachObjectLink(md, ob, (ObjectWalkFunc)walk, userData); } static void foreachTexLink(ModifierData *md, Object *ob, TexWalkFunc walk, void *userData) diff --git a/source/blender/modifiers/intern/MOD_wave.c b/source/blender/modifiers/intern/MOD_wave.c index 5b98f221489..f13eeb3185e 100644 --- a/source/blender/modifiers/intern/MOD_wave.c +++ b/source/blender/modifiers/intern/MOD_wave.c @@ -45,6 +45,7 @@ #include "BKE_deform.h" #include "BKE_DerivedMesh.h" #include "BKE_library.h" +#include "BKE_library_query.h" #include "BKE_scene.h" #include "BKE_texture.h" @@ -110,8 +111,8 @@ static void foreachObjectLink( { WaveModifierData *wmd = (WaveModifierData *) md; - walk(userData, ob, &wmd->objectcenter); - walk(userData, ob, &wmd->map_object); + walk(userData, ob, &wmd->objectcenter, IDWALK_NOP); + walk(userData, ob, &wmd->map_object, IDWALK_NOP); } static void foreachIDLink(ModifierData *md, Object *ob, @@ -119,7 +120,7 @@ static void foreachIDLink(ModifierData *md, Object *ob, { WaveModifierData *wmd = (WaveModifierData *) md; - walk(userData, ob, (ID **)&wmd->texture); + walk(userData, ob, (ID **)&wmd->texture, IDWALK_USER); foreachObjectLink(md, ob, (ObjectWalkFunc)walk, userData); } diff --git a/source/blender/modifiers/intern/MOD_weightvgedit.c b/source/blender/modifiers/intern/MOD_weightvgedit.c index cba077a2f8d..93567aed2c4 100644 --- a/source/blender/modifiers/intern/MOD_weightvgedit.c +++ b/source/blender/modifiers/intern/MOD_weightvgedit.c @@ -42,6 +42,7 @@ #include "BKE_colortools.h" /* CurveMapping. */ #include "BKE_deform.h" #include "BKE_library.h" +#include "BKE_library_query.h" #include "BKE_modifier.h" #include "BKE_texture.h" /* Texture masking. */ @@ -122,19 +123,17 @@ static bool dependsOnTime(ModifierData *md) return false; } -static void foreachObjectLink(ModifierData *md, Object *ob, - void (*walk)(void *userData, Object *ob, Object **obpoin), - void *userData) +static void foreachObjectLink(ModifierData *md, Object *ob, ObjectWalkFunc walk, void *userData) { WeightVGEditModifierData *wmd = (WeightVGEditModifierData *) md; - walk(userData, ob, &wmd->mask_tex_map_obj); + walk(userData, ob, &wmd->mask_tex_map_obj, IDWALK_NOP); } static void foreachIDLink(ModifierData *md, Object *ob, IDWalkFunc walk, void *userData) { WeightVGEditModifierData *wmd = (WeightVGEditModifierData *) md; - walk(userData, ob, (ID **)&wmd->mask_texture); + walk(userData, ob, (ID **)&wmd->mask_texture, IDWALK_USER); foreachObjectLink(md, ob, (ObjectWalkFunc)walk, userData); } diff --git a/source/blender/modifiers/intern/MOD_weightvgmix.c b/source/blender/modifiers/intern/MOD_weightvgmix.c index 0649998e42d..01a219d1457 100644 --- a/source/blender/modifiers/intern/MOD_weightvgmix.c +++ b/source/blender/modifiers/intern/MOD_weightvgmix.c @@ -39,6 +39,7 @@ #include "BKE_cdderivedmesh.h" #include "BKE_deform.h" #include "BKE_library.h" +#include "BKE_library_query.h" #include "BKE_modifier.h" #include "BKE_texture.h" /* Texture masking. */ @@ -171,19 +172,17 @@ static bool dependsOnTime(ModifierData *md) return false; } -static void foreachObjectLink(ModifierData *md, Object *ob, - void (*walk)(void *userData, Object *ob, Object **obpoin), - void *userData) +static void foreachObjectLink(ModifierData *md, Object *ob, ObjectWalkFunc walk, void *userData) { WeightVGMixModifierData *wmd = (WeightVGMixModifierData *) md; - walk(userData, ob, &wmd->mask_tex_map_obj); + walk(userData, ob, &wmd->mask_tex_map_obj, IDWALK_NOP); } static void foreachIDLink(ModifierData *md, Object *ob, IDWalkFunc walk, void *userData) { WeightVGMixModifierData *wmd = (WeightVGMixModifierData *) md; - walk(userData, ob, (ID **)&wmd->mask_texture); + walk(userData, ob, (ID **)&wmd->mask_texture, IDWALK_USER); foreachObjectLink(md, ob, (ObjectWalkFunc)walk, userData); } diff --git a/source/blender/modifiers/intern/MOD_weightvgproximity.c b/source/blender/modifiers/intern/MOD_weightvgproximity.c index 08d7d77c74e..51c6f5cab3c 100644 --- a/source/blender/modifiers/intern/MOD_weightvgproximity.c +++ b/source/blender/modifiers/intern/MOD_weightvgproximity.c @@ -42,6 +42,7 @@ #include "BKE_cdderivedmesh.h" #include "BKE_deform.h" #include "BKE_library.h" +#include "BKE_library_query.h" #include "BKE_modifier.h" #include "BKE_texture.h" /* Texture masking. */ @@ -123,7 +124,7 @@ static void get_vert2geom_distance(int numVerts, float (*v_cos)[3], * If we already had an hit before, we assume this vertex is going to have a close hit to * that other vertex, so we can initiate the "nearest.dist" with the expected value to that * last hit. - * This will lead in prunning of the search tree. + * This will lead in pruning of the search tree. */ if (dist_v) { nearest_v.dist_sq = nearest_v.index != -1 ? len_squared_v3v3(tmp_co, nearest_v.co) : FLT_MAX; @@ -287,20 +288,18 @@ static bool dependsOnTime(ModifierData *md) return 0; } -static void foreachObjectLink(ModifierData *md, Object *ob, - void (*walk)(void *userData, Object *ob, Object **obpoin), - void *userData) +static void foreachObjectLink(ModifierData *md, Object *ob, ObjectWalkFunc walk, void *userData) { WeightVGProximityModifierData *wmd = (WeightVGProximityModifierData *) md; - walk(userData, ob, &wmd->proximity_ob_target); - walk(userData, ob, &wmd->mask_tex_map_obj); + walk(userData, ob, &wmd->proximity_ob_target, IDWALK_NOP); + walk(userData, ob, &wmd->mask_tex_map_obj, IDWALK_NOP); } static void foreachIDLink(ModifierData *md, Object *ob, IDWalkFunc walk, void *userData) { WeightVGProximityModifierData *wmd = (WeightVGProximityModifierData *) md; - walk(userData, ob, (ID **)&wmd->mask_texture); + walk(userData, ob, (ID **)&wmd->mask_texture, IDWALK_USER); foreachObjectLink(md, ob, (ObjectWalkFunc)walk, userData); } diff --git a/source/blender/nodes/shader/node_shader_util.c b/source/blender/nodes/shader/node_shader_util.c index 49881381253..92b244bae55 100644 --- a/source/blender/nodes/shader/node_shader_util.c +++ b/source/blender/nodes/shader/node_shader_util.c @@ -141,7 +141,7 @@ void node_gpu_stack_from_data(struct GPUNodeStack *gs, int type, bNodeStack *ns) { memset(gs, 0, sizeof(*gs)); - copy_v4_v4(gs->vec, ns->vec); + nodestack_get_vec(gs->vec, type, ns); gs->link = ns->data; if (type == SOCK_FLOAT) diff --git a/source/blender/nodes/shader/nodes/node_shader_bsdf_hair.c b/source/blender/nodes/shader/nodes/node_shader_bsdf_hair.c index dbc8807a845..25be59f091d 100644 --- a/source/blender/nodes/shader/nodes/node_shader_bsdf_hair.c +++ b/source/blender/nodes/shader/nodes/node_shader_bsdf_hair.c @@ -33,7 +33,9 @@ static bNodeSocketTemplate sh_node_bsdf_hair_in[] = { { SOCK_RGBA, 1, N_("Color"), 0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f}, { SOCK_FLOAT, 1, N_("Offset"), 0.0f, 0.0f, 0.0f, 0.0f, -M_PI_2, M_PI_2, PROP_ANGLE}, { SOCK_FLOAT, 1, N_("RoughnessU"), 0.1f, 0.1f, 0.1f, 0.0f, 0.0f, 1.0f, PROP_FACTOR}, - { SOCK_FLOAT, 1, N_("RoughnessV"), 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR}, { -1, 0, "" } + { SOCK_FLOAT, 1, N_("RoughnessV"), 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR}, + { SOCK_VECTOR, 1, N_("Tangent"), 0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f, PROP_NONE, SOCK_HIDE_VALUE}, + { -1, 0, "" }, }; static bNodeSocketTemplate sh_node_bsdf_hair_out[] = { diff --git a/source/blender/nodes/shader/nodes/node_shader_math.c b/source/blender/nodes/shader/nodes/node_shader_math.c index be2e3dcd311..2a1e936570d 100644 --- a/source/blender/nodes/shader/nodes/node_shader_math.c +++ b/source/blender/nodes/shader/nodes/node_shader_math.c @@ -230,10 +230,12 @@ static void node_shader_exec_math(void *UNUSED(data), int UNUSED(thread), bNode static int gpu_shader_math(GPUMaterial *mat, bNode *node, bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out) { - static const char *names[] = {"math_add", "math_subtract", "math_multiply", - "math_divide", "math_sine", "math_cosine", "math_tangent", "math_asin", - "math_acos", "math_atan", "math_pow", "math_log", "math_min", "math_max", - "math_round", "math_less_than", "math_greater_than", "math_modulo", "math_abs"}; + static const char *names[] = { + "math_add", "math_subtract", "math_multiply", + "math_divide", "math_sine", "math_cosine", "math_tangent", "math_asin", + "math_acos", "math_atan", "math_pow", "math_log", "math_min", "math_max", + "math_round", "math_less_than", "math_greater_than", "math_modulo", "math_abs", + }; switch (node->custom1) { case NODE_MATH_ADD: diff --git a/source/blender/python/SConscript b/source/blender/python/SConscript index f7b01259ead..79c53760302 100644 --- a/source/blender/python/SConscript +++ b/source/blender/python/SConscript @@ -93,8 +93,8 @@ if env['WITH_BF_PYTHON_SAFETY']: if env['BF_BUILDINFO']: defs.append('BUILD_DATE') - -# Audaspace is always on currently +if env['WITH_BF_AUDASPACE']: + defs += env['BF_AUDASPACE_DEF'] if env['WITH_BF_BULLET']: defs.append('WITH_BULLET') diff --git a/source/blender/python/bmesh/bmesh_py_ops_call.c b/source/blender/python/bmesh/bmesh_py_ops_call.c index a4c057acac2..1dc70c3d288 100644 --- a/source/blender/python/bmesh/bmesh_py_ops_call.c +++ b/source/blender/python/bmesh/bmesh_py_ops_call.c @@ -27,7 +27,7 @@ * \ingroup pybmesh * * This file provides __call__ aka BPy_BMO_call for - * the bmesh operatorand has been given its own file + * the bmesh operator and has been given its own file * because argument conversion is involved. */ diff --git a/source/blender/python/bmesh/bmesh_py_types.c b/source/blender/python/bmesh/bmesh_py_types.c index 728332d755a..bf773d3d9c3 100644 --- a/source/blender/python/bmesh/bmesh_py_types.c +++ b/source/blender/python/bmesh/bmesh_py_types.c @@ -27,9 +27,8 @@ * \ingroup pybmesh */ -#include <Python.h> - #include "BLI_math.h" +#include "BLI_sort.h" #include "DNA_mesh_types.h" #include "DNA_object_types.h" @@ -41,6 +40,8 @@ #include "bmesh.h" +#include <Python.h> + #include "../mathutils/mathutils.h" #include "../generic/py_capi_utils.h" @@ -2442,6 +2443,9 @@ PyDoc_STRVAR(bpy_bmelemseq_sort_doc, " When the 'key' argument is not provided, the elements are reordered following their current index value.\n" " In particular this can be used by setting indices manually before calling this method.\n" "\n" +" .. warning::\n" +"\n" +" Existing references to the N'th element, will continue to point the data at that index.\n" ); /* Use a static variable here because there is the need to sort some array @@ -2455,10 +2459,10 @@ PyDoc_STRVAR(bpy_bmelemseq_sort_doc, * Note: the functions below assumes the keys array has been allocated and it * has enough elements to complete the task. */ -static double *keys = NULL; -static int bpy_bmelemseq_sort_cmp_by_keys_ascending(const void *index1_v, const void *index2_v) +static int bpy_bmelemseq_sort_cmp_by_keys_ascending(const void *index1_v, const void *index2_v, void *keys_v) { + const double *keys = keys_v; const int *index1 = (int *)index1_v; const int *index2 = (int *)index2_v; @@ -2467,9 +2471,9 @@ static int bpy_bmelemseq_sort_cmp_by_keys_ascending(const void *index1_v, const else return 0; } -static int bpy_bmelemseq_sort_cmp_by_keys_descending(const void *index1_v, const void *index2_v) +static int bpy_bmelemseq_sort_cmp_by_keys_descending(const void *index1_v, const void *index2_v, void *keys_v) { - return -bpy_bmelemseq_sort_cmp_by_keys_ascending(index1_v, index2_v); + return -bpy_bmelemseq_sort_cmp_by_keys_ascending(index1_v, index2_v, keys_v); } static PyObject *bpy_bmelemseq_sort(BPy_BMElemSeq *self, PyObject *args, PyObject *kw) @@ -2484,9 +2488,10 @@ static PyObject *bpy_bmelemseq_sort(BPy_BMElemSeq *self, PyObject *args, PyObjec BMIter iter; BMElem *ele; + double *keys; int *elem_idx; unsigned int *elem_map_idx; - int (*elem_idx_compare_by_keys)(const void *, const void *); + int (*elem_idx_compare_by_keys)(const void *, const void *, void *); unsigned int *vert_idx = NULL; unsigned int *edge_idx = NULL; @@ -2577,7 +2582,7 @@ static PyObject *bpy_bmelemseq_sort(BPy_BMElemSeq *self, PyObject *args, PyObjec else elem_idx_compare_by_keys = bpy_bmelemseq_sort_cmp_by_keys_ascending; - qsort(elem_idx, n_elem, sizeof(*elem_idx), elem_idx_compare_by_keys); + BLI_qsort_r(elem_idx, n_elem, sizeof(*elem_idx), elem_idx_compare_by_keys, keys); elem_map_idx = PyMem_MALLOC(sizeof(*elem_map_idx) * n_elem); if (elem_map_idx == NULL) { diff --git a/source/blender/python/bmesh/bmesh_py_types_customdata.c b/source/blender/python/bmesh/bmesh_py_types_customdata.c index 3adf37f78f0..908f6b5a734 100644 --- a/source/blender/python/bmesh/bmesh_py_types_customdata.c +++ b/source/blender/python/bmesh/bmesh_py_types_customdata.c @@ -149,10 +149,9 @@ static PyObject *bpy_bmlayercollection_active_get(BPy_BMLayerItem *self, void *U BPY_BM_CHECK_OBJ(self); data = bpy_bm_customdata_get(self->bm, self->htype); - index = CustomData_get_active_layer_index(data, self->type); /* absolute */ + index = CustomData_get_active_layer(data, self->type); /* type relative */ if (index != -1) { - index -= CustomData_get_layer_index(data, self->type); /* make relative */ return BPy_BMLayerItem_CreatePyObject(self->bm, self->htype, self->type, index); } else { @@ -330,15 +329,12 @@ static PyObject *bpy_bmlayercollection_verify(BPy_BMLayerCollection *self) data = bpy_bm_customdata_get(self->bm, self->htype); - index = CustomData_get_layer_index(data, self->type); + index = CustomData_get_active_layer(data, self->type); /* type relative */ if (index == -1) { BM_data_layer_add(self->bm, data, self->type); index = 0; } - else { - index = CustomData_get_active_layer_index(data, self->type) - index; /* make relative */ - } BLI_assert(index >= 0); @@ -490,7 +486,7 @@ static PyObject *bpy_bmlayercollection_items(BPy_BMLayerCollection *self) item = PyTuple_New(2); PyTuple_SET_ITEMS(item, PyUnicode_FromString(data->layers[index].name), - BPy_BMLayerItem_CreatePyObject(self->bm, self->htype, self->type, index)); + BPy_BMLayerItem_CreatePyObject(self->bm, self->htype, self->type, i)); PyList_SET_ITEM(ret, i++, item); } @@ -523,7 +519,7 @@ static PyObject *bpy_bmlayercollection_values(BPy_BMLayerCollection *self) ret = PyList_New(tot); for (i = 0; tot-- > 0; index++) { - item = BPy_BMLayerItem_CreatePyObject(self->bm, self->htype, self->type, index); + item = BPy_BMLayerItem_CreatePyObject(self->bm, self->htype, self->type, i); PyList_SET_ITEM(ret, i++, item); } @@ -557,10 +553,9 @@ static PyObject *bpy_bmlayercollection_get(BPy_BMLayerCollection *self, PyObject int index; data = bpy_bm_customdata_get(self->bm, self->htype); - index = CustomData_get_named_layer_index(data, self->type, key); /* absolute index */ + index = CustomData_get_named_layer(data, self->type, key); /* type relative */ if (index != -1) { - index -= CustomData_get_layer_index(data, self->type); /* make relative */ return BPy_BMLayerItem_CreatePyObject(self->bm, self->htype, self->type, index); } } @@ -607,10 +602,9 @@ static PyObject *bpy_bmlayercollection_subscript_str(BPy_BMLayerCollection *self BPY_BM_CHECK_OBJ(self); data = bpy_bm_customdata_get(self->bm, self->htype); - index = CustomData_get_named_layer_index(data, self->type, keyname); /* absolute */ + index = CustomData_get_named_layer(data, self->type, keyname); /* type relative */ if (index != -1) { - index -= CustomData_get_layer_index(data, self->type); /* make relative */ return BPy_BMLayerItem_CreatePyObject(self->bm, self->htype, self->type, index); } else { diff --git a/source/blender/python/generic/bgl.c b/source/blender/python/generic/bgl.c index e949972220b..cd6ef3f16a4 100644 --- a/source/blender/python/generic/bgl.c +++ b/source/blender/python/generic/bgl.c @@ -1667,6 +1667,13 @@ static void py_module_dict_add_int(PyObject *dict, const char *name, int value) Py_DECREF(item); } +static void py_module_dict_add_int64(PyObject *dict, const char *name, int64_t value) +{ + PyObject *item; + PyDict_SetItemString(dict, name, item = PyLong_FromLongLong(value)); + Py_DECREF(item); +} + static void py_module_dict_add_method(PyObject *submodule, PyObject *dict, PyMethodDef *method_def, bool is_valid) { if (is_valid) { @@ -1696,7 +1703,9 @@ PyObject *BPyInit_bgl(void) Py_INCREF((PyObject *)&BGL_bufferType); /* needed since some function pointers won't be NULL */ -#pragma GCC diagnostic ignored "-Waddress" +#ifdef __GNUC__ +# pragma GCC diagnostic ignored "-Waddress" +#endif #define PY_MOD_ADD_METHOD(func) \ { \ @@ -2330,6 +2339,7 @@ PyObject *BPyInit_bgl(void) } #define PY_DICT_ADD_INT(x) py_module_dict_add_int(dict, #x, x) +#define PY_DICT_ADD_INT64(x) py_module_dict_add_int64(dict, #x, x) /* GL_VERSION_1_1 */ { @@ -3022,15 +3032,57 @@ PyObject *BPyInit_bgl(void) /* GL_VERSION_1_4 */ { + PY_DICT_ADD_INT(GL_BLEND_DST_ALPHA); + PY_DICT_ADD_INT(GL_BLEND_DST_RGB); + PY_DICT_ADD_INT(GL_BLEND_SRC_ALPHA); + PY_DICT_ADD_INT(GL_BLEND_SRC_RGB); PY_DICT_ADD_INT(GL_CONSTANT_ALPHA); PY_DICT_ADD_INT(GL_CONSTANT_COLOR); + PY_DICT_ADD_INT(GL_DECR_WRAP); + PY_DICT_ADD_INT(GL_DEPTH_COMPONENT16); + PY_DICT_ADD_INT(GL_DEPTH_COMPONENT24); + PY_DICT_ADD_INT(GL_DEPTH_COMPONENT32); PY_DICT_ADD_INT(GL_FUNC_ADD); PY_DICT_ADD_INT(GL_FUNC_REVERSE_SUBTRACT); PY_DICT_ADD_INT(GL_FUNC_SUBTRACT); + PY_DICT_ADD_INT(GL_INCR_WRAP); PY_DICT_ADD_INT(GL_MAX); + PY_DICT_ADD_INT(GL_MAX_TEXTURE_LOD_BIAS); PY_DICT_ADD_INT(GL_MIN); + PY_DICT_ADD_INT(GL_MIRRORED_REPEAT); PY_DICT_ADD_INT(GL_ONE_MINUS_CONSTANT_ALPHA); PY_DICT_ADD_INT(GL_ONE_MINUS_CONSTANT_COLOR); + PY_DICT_ADD_INT(GL_POINT_FADE_THRESHOLD_SIZE); + PY_DICT_ADD_INT(GL_TEXTURE_COMPARE_FUNC); + PY_DICT_ADD_INT(GL_TEXTURE_COMPARE_MODE); + 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); } @@ -3214,23 +3266,262 @@ PyObject *BPyInit_bgl(void) PY_DICT_ADD_INT(GL_SLUMINANCE_ALPHA); } - /* GL_VERSION_3_0 */ { + PY_DICT_ADD_INT(GL_BGRA_INTEGER); + PY_DICT_ADD_INT(GL_BGR_INTEGER); + PY_DICT_ADD_INT(GL_BLUE_INTEGER); + PY_DICT_ADD_INT(GL_BUFFER_ACCESS_FLAGS); + PY_DICT_ADD_INT(GL_BUFFER_MAP_LENGTH); + PY_DICT_ADD_INT(GL_BUFFER_MAP_OFFSET); + PY_DICT_ADD_INT(GL_CLAMP_READ_COLOR); + PY_DICT_ADD_INT(GL_CLIP_DISTANCE0); + PY_DICT_ADD_INT(GL_CLIP_DISTANCE1); + PY_DICT_ADD_INT(GL_CLIP_DISTANCE2); + PY_DICT_ADD_INT(GL_CLIP_DISTANCE3); + PY_DICT_ADD_INT(GL_CLIP_DISTANCE4); + PY_DICT_ADD_INT(GL_CLIP_DISTANCE5); +#if 0 + PY_DICT_ADD_INT(GL_CLIP_DISTANCE6); + PY_DICT_ADD_INT(GL_CLIP_DISTANCE7); +#endif + PY_DICT_ADD_INT(GL_COLOR_ATTACHMENT0); + PY_DICT_ADD_INT(GL_COLOR_ATTACHMENT1); + PY_DICT_ADD_INT(GL_COLOR_ATTACHMENT2); + PY_DICT_ADD_INT(GL_COLOR_ATTACHMENT3); + PY_DICT_ADD_INT(GL_COLOR_ATTACHMENT4); + PY_DICT_ADD_INT(GL_COLOR_ATTACHMENT5); + PY_DICT_ADD_INT(GL_COLOR_ATTACHMENT6); + PY_DICT_ADD_INT(GL_COLOR_ATTACHMENT7); + PY_DICT_ADD_INT(GL_COLOR_ATTACHMENT8); + PY_DICT_ADD_INT(GL_COLOR_ATTACHMENT9); + PY_DICT_ADD_INT(GL_COLOR_ATTACHMENT10); + PY_DICT_ADD_INT(GL_COLOR_ATTACHMENT11); + PY_DICT_ADD_INT(GL_COLOR_ATTACHMENT12); + PY_DICT_ADD_INT(GL_COLOR_ATTACHMENT13); + PY_DICT_ADD_INT(GL_COLOR_ATTACHMENT14); + PY_DICT_ADD_INT(GL_COLOR_ATTACHMENT15); +#if 0 + PY_DICT_ADD_INT(GL_COLOR_ATTACHMENT16); + PY_DICT_ADD_INT(GL_COLOR_ATTACHMENT17); + PY_DICT_ADD_INT(GL_COLOR_ATTACHMENT18); + PY_DICT_ADD_INT(GL_COLOR_ATTACHMENT19); + PY_DICT_ADD_INT(GL_COLOR_ATTACHMENT20); + PY_DICT_ADD_INT(GL_COLOR_ATTACHMENT21); + PY_DICT_ADD_INT(GL_COLOR_ATTACHMENT22); + PY_DICT_ADD_INT(GL_COLOR_ATTACHMENT23); + PY_DICT_ADD_INT(GL_COLOR_ATTACHMENT24); + PY_DICT_ADD_INT(GL_COLOR_ATTACHMENT25); + PY_DICT_ADD_INT(GL_COLOR_ATTACHMENT26); + PY_DICT_ADD_INT(GL_COLOR_ATTACHMENT27); + PY_DICT_ADD_INT(GL_COLOR_ATTACHMENT28); + PY_DICT_ADD_INT(GL_COLOR_ATTACHMENT29); + PY_DICT_ADD_INT(GL_COLOR_ATTACHMENT30); + PY_DICT_ADD_INT(GL_COLOR_ATTACHMENT31); +#endif + PY_DICT_ADD_INT(GL_COMPARE_REF_TO_TEXTURE); + PY_DICT_ADD_INT(GL_COMPRESSED_RED); + PY_DICT_ADD_INT(GL_COMPRESSED_RED_RGTC1); + PY_DICT_ADD_INT(GL_COMPRESSED_RG); + PY_DICT_ADD_INT(GL_COMPRESSED_RG_RGTC2); + PY_DICT_ADD_INT(GL_COMPRESSED_SIGNED_RED_RGTC1); + PY_DICT_ADD_INT(GL_COMPRESSED_SIGNED_RG_RGTC2); + PY_DICT_ADD_INT(GL_CONTEXT_FLAGS); + PY_DICT_ADD_INT(GL_CONTEXT_FLAG_FORWARD_COMPATIBLE_BIT); + PY_DICT_ADD_INT(GL_DEPTH24_STENCIL8); + PY_DICT_ADD_INT(GL_DEPTH32F_STENCIL8); + PY_DICT_ADD_INT(GL_DEPTH_ATTACHMENT); + PY_DICT_ADD_INT(GL_DEPTH_COMPONENT32F); + PY_DICT_ADD_INT(GL_DEPTH_STENCIL); + PY_DICT_ADD_INT(GL_DEPTH_STENCIL_ATTACHMENT); + PY_DICT_ADD_INT(GL_DRAW_FRAMEBUFFER); + PY_DICT_ADD_INT(GL_DRAW_FRAMEBUFFER_BINDING); + PY_DICT_ADD_INT(GL_FIXED_ONLY); + PY_DICT_ADD_INT(GL_FLOAT_32_UNSIGNED_INT_24_8_REV); + PY_DICT_ADD_INT(GL_FRAMEBUFFER); + PY_DICT_ADD_INT(GL_FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE); + PY_DICT_ADD_INT(GL_FRAMEBUFFER_ATTACHMENT_BLUE_SIZE); + PY_DICT_ADD_INT(GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING); + PY_DICT_ADD_INT(GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE); + PY_DICT_ADD_INT(GL_FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE); + PY_DICT_ADD_INT(GL_FRAMEBUFFER_ATTACHMENT_GREEN_SIZE); + PY_DICT_ADD_INT(GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME); + PY_DICT_ADD_INT(GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE); + PY_DICT_ADD_INT(GL_FRAMEBUFFER_ATTACHMENT_RED_SIZE); + PY_DICT_ADD_INT(GL_FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE); + PY_DICT_ADD_INT(GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE); + PY_DICT_ADD_INT(GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LAYER); + PY_DICT_ADD_INT(GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL); + PY_DICT_ADD_INT(GL_FRAMEBUFFER_BINDING); + PY_DICT_ADD_INT(GL_FRAMEBUFFER_COMPLETE); + PY_DICT_ADD_INT(GL_FRAMEBUFFER_DEFAULT); + PY_DICT_ADD_INT(GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT); + PY_DICT_ADD_INT(GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER); + PY_DICT_ADD_INT(GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT); + PY_DICT_ADD_INT(GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE); + PY_DICT_ADD_INT(GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER); + PY_DICT_ADD_INT(GL_FRAMEBUFFER_SRGB); + PY_DICT_ADD_INT(GL_FRAMEBUFFER_UNDEFINED); + PY_DICT_ADD_INT(GL_FRAMEBUFFER_UNSUPPORTED); + PY_DICT_ADD_INT(GL_GREEN_INTEGER); + PY_DICT_ADD_INT(GL_HALF_FLOAT); + PY_DICT_ADD_INT(GL_INDEX); + PY_DICT_ADD_INT(GL_INTERLEAVED_ATTRIBS); + PY_DICT_ADD_INT(GL_INT_SAMPLER_1D); + PY_DICT_ADD_INT(GL_INT_SAMPLER_1D_ARRAY); + PY_DICT_ADD_INT(GL_INT_SAMPLER_2D); + PY_DICT_ADD_INT(GL_INT_SAMPLER_2D_ARRAY); + PY_DICT_ADD_INT(GL_INT_SAMPLER_3D); + PY_DICT_ADD_INT(GL_INT_SAMPLER_CUBE); + PY_DICT_ADD_INT(GL_INVALID_FRAMEBUFFER_OPERATION); + PY_DICT_ADD_INT(GL_MAJOR_VERSION); + PY_DICT_ADD_INT(GL_MAP_FLUSH_EXPLICIT_BIT); + PY_DICT_ADD_INT(GL_MAP_INVALIDATE_BUFFER_BIT); + PY_DICT_ADD_INT(GL_MAP_INVALIDATE_RANGE_BIT); + PY_DICT_ADD_INT(GL_MAP_READ_BIT); + PY_DICT_ADD_INT(GL_MAP_UNSYNCHRONIZED_BIT); + PY_DICT_ADD_INT(GL_MAP_WRITE_BIT); + PY_DICT_ADD_INT(GL_MAX_ARRAY_TEXTURE_LAYERS); + PY_DICT_ADD_INT(GL_MAX_CLIP_DISTANCES); + PY_DICT_ADD_INT(GL_MAX_COLOR_ATTACHMENTS); + PY_DICT_ADD_INT(GL_MAX_PROGRAM_TEXEL_OFFSET); + PY_DICT_ADD_INT(GL_MAX_RENDERBUFFER_SIZE); + PY_DICT_ADD_INT(GL_MAX_SAMPLES); + PY_DICT_ADD_INT(GL_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS); + PY_DICT_ADD_INT(GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS); + PY_DICT_ADD_INT(GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS); + PY_DICT_ADD_INT(GL_MAX_VARYING_COMPONENTS); + PY_DICT_ADD_INT(GL_MINOR_VERSION); + PY_DICT_ADD_INT(GL_MIN_PROGRAM_TEXEL_OFFSET); + PY_DICT_ADD_INT(GL_NUM_EXTENSIONS); + PY_DICT_ADD_INT(GL_PRIMITIVES_GENERATED); + PY_DICT_ADD_INT(GL_PROXY_TEXTURE_1D_ARRAY); + PY_DICT_ADD_INT(GL_PROXY_TEXTURE_2D_ARRAY); + PY_DICT_ADD_INT(GL_QUERY_BY_REGION_NO_WAIT); + PY_DICT_ADD_INT(GL_QUERY_BY_REGION_WAIT); + PY_DICT_ADD_INT(GL_QUERY_NO_WAIT); + PY_DICT_ADD_INT(GL_QUERY_WAIT); + PY_DICT_ADD_INT(GL_R11F_G11F_B10F); + PY_DICT_ADD_INT(GL_R16); + PY_DICT_ADD_INT(GL_R16F); + PY_DICT_ADD_INT(GL_R16I); + PY_DICT_ADD_INT(GL_R16UI); + PY_DICT_ADD_INT(GL_R32F); + PY_DICT_ADD_INT(GL_R32I); + PY_DICT_ADD_INT(GL_R32UI); + PY_DICT_ADD_INT(GL_R8); + PY_DICT_ADD_INT(GL_R8I); + PY_DICT_ADD_INT(GL_R8UI); + PY_DICT_ADD_INT(GL_RASTERIZER_DISCARD); + PY_DICT_ADD_INT(GL_READ_FRAMEBUFFER); + PY_DICT_ADD_INT(GL_READ_FRAMEBUFFER_BINDING); + PY_DICT_ADD_INT(GL_RED_INTEGER); + PY_DICT_ADD_INT(GL_RENDERBUFFER); + PY_DICT_ADD_INT(GL_RENDERBUFFER_ALPHA_SIZE); + PY_DICT_ADD_INT(GL_RENDERBUFFER_BINDING); + PY_DICT_ADD_INT(GL_RENDERBUFFER_BLUE_SIZE); + PY_DICT_ADD_INT(GL_RENDERBUFFER_DEPTH_SIZE); + PY_DICT_ADD_INT(GL_RENDERBUFFER_GREEN_SIZE); + PY_DICT_ADD_INT(GL_RENDERBUFFER_HEIGHT); + PY_DICT_ADD_INT(GL_RENDERBUFFER_INTERNAL_FORMAT); + PY_DICT_ADD_INT(GL_RENDERBUFFER_RED_SIZE); + PY_DICT_ADD_INT(GL_RENDERBUFFER_SAMPLES); + PY_DICT_ADD_INT(GL_RENDERBUFFER_STENCIL_SIZE); + PY_DICT_ADD_INT(GL_RENDERBUFFER_WIDTH); + PY_DICT_ADD_INT(GL_RG); + PY_DICT_ADD_INT(GL_RG16); + PY_DICT_ADD_INT(GL_RG16F); + PY_DICT_ADD_INT(GL_RG16I); + PY_DICT_ADD_INT(GL_RG16UI); + PY_DICT_ADD_INT(GL_RG32F); + PY_DICT_ADD_INT(GL_RG32I); + PY_DICT_ADD_INT(GL_RG32UI); + PY_DICT_ADD_INT(GL_RG8); + PY_DICT_ADD_INT(GL_RG8I); + PY_DICT_ADD_INT(GL_RG8UI); + PY_DICT_ADD_INT(GL_RGB16F); + PY_DICT_ADD_INT(GL_RGB16I); + PY_DICT_ADD_INT(GL_RGB16UI); + PY_DICT_ADD_INT(GL_RGB32F); + PY_DICT_ADD_INT(GL_RGB32I); + PY_DICT_ADD_INT(GL_RGB32UI); + PY_DICT_ADD_INT(GL_RGB8I); + PY_DICT_ADD_INT(GL_RGB8UI); + PY_DICT_ADD_INT(GL_RGB9_E5); + PY_DICT_ADD_INT(GL_RGBA16F); + PY_DICT_ADD_INT(GL_RGBA16I); + PY_DICT_ADD_INT(GL_RGBA16UI); + PY_DICT_ADD_INT(GL_RGBA32F); + PY_DICT_ADD_INT(GL_RGBA32I); + PY_DICT_ADD_INT(GL_RGBA32UI); + PY_DICT_ADD_INT(GL_RGBA8I); + PY_DICT_ADD_INT(GL_RGBA8UI); + PY_DICT_ADD_INT(GL_RGBA_INTEGER); + PY_DICT_ADD_INT(GL_RGB_INTEGER); + PY_DICT_ADD_INT(GL_RG_INTEGER); + PY_DICT_ADD_INT(GL_SAMPLER_1D_ARRAY); + PY_DICT_ADD_INT(GL_SAMPLER_1D_ARRAY_SHADOW); + PY_DICT_ADD_INT(GL_SAMPLER_2D_ARRAY); + PY_DICT_ADD_INT(GL_SAMPLER_2D_ARRAY_SHADOW); + PY_DICT_ADD_INT(GL_SAMPLER_CUBE_SHADOW); + PY_DICT_ADD_INT(GL_SEPARATE_ATTRIBS); + PY_DICT_ADD_INT(GL_STENCIL_ATTACHMENT); + PY_DICT_ADD_INT(GL_STENCIL_INDEX1); + PY_DICT_ADD_INT(GL_STENCIL_INDEX16); + PY_DICT_ADD_INT(GL_STENCIL_INDEX4); + PY_DICT_ADD_INT(GL_STENCIL_INDEX8); + PY_DICT_ADD_INT(GL_TEXTURE_1D_ARRAY); + PY_DICT_ADD_INT(GL_TEXTURE_2D_ARRAY); + PY_DICT_ADD_INT(GL_TEXTURE_ALPHA_TYPE); + PY_DICT_ADD_INT(GL_TEXTURE_BINDING_1D_ARRAY); + PY_DICT_ADD_INT(GL_TEXTURE_BINDING_2D_ARRAY); + PY_DICT_ADD_INT(GL_TEXTURE_BLUE_TYPE); + PY_DICT_ADD_INT(GL_TEXTURE_DEPTH_TYPE); + PY_DICT_ADD_INT(GL_TEXTURE_GREEN_TYPE); + PY_DICT_ADD_INT(GL_TEXTURE_RED_TYPE); + PY_DICT_ADD_INT(GL_TEXTURE_SHARED_SIZE); + PY_DICT_ADD_INT(GL_TEXTURE_STENCIL_SIZE); + PY_DICT_ADD_INT(GL_TRANSFORM_FEEDBACK_BUFFER); + PY_DICT_ADD_INT(GL_TRANSFORM_FEEDBACK_BUFFER_BINDING); + PY_DICT_ADD_INT(GL_TRANSFORM_FEEDBACK_BUFFER_MODE); + PY_DICT_ADD_INT(GL_TRANSFORM_FEEDBACK_BUFFER_SIZE); + PY_DICT_ADD_INT(GL_TRANSFORM_FEEDBACK_BUFFER_START); + PY_DICT_ADD_INT(GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN); + PY_DICT_ADD_INT(GL_TRANSFORM_FEEDBACK_VARYINGS); + PY_DICT_ADD_INT(GL_TRANSFORM_FEEDBACK_VARYING_MAX_LENGTH); + PY_DICT_ADD_INT(GL_UNSIGNED_INT_10F_11F_11F_REV); + PY_DICT_ADD_INT(GL_UNSIGNED_INT_24_8); + PY_DICT_ADD_INT(GL_UNSIGNED_INT_5_9_9_9_REV); + PY_DICT_ADD_INT(GL_UNSIGNED_INT_SAMPLER_1D); + PY_DICT_ADD_INT(GL_UNSIGNED_INT_SAMPLER_1D_ARRAY); + PY_DICT_ADD_INT(GL_UNSIGNED_INT_SAMPLER_2D); + PY_DICT_ADD_INT(GL_UNSIGNED_INT_SAMPLER_2D_ARRAY); + PY_DICT_ADD_INT(GL_UNSIGNED_INT_SAMPLER_3D); + PY_DICT_ADD_INT(GL_UNSIGNED_INT_SAMPLER_CUBE); + PY_DICT_ADD_INT(GL_UNSIGNED_INT_VEC2); + PY_DICT_ADD_INT(GL_UNSIGNED_INT_VEC3); + PY_DICT_ADD_INT(GL_UNSIGNED_INT_VEC4); + PY_DICT_ADD_INT(GL_UNSIGNED_NORMALIZED); 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 */ { PY_DICT_ADD_INT(GL_ACTIVE_UNIFORM_BLOCKS); PY_DICT_ADD_INT(GL_ACTIVE_UNIFORM_BLOCK_MAX_NAME_LENGTH); + PY_DICT_ADD_INT(GL_COPY_READ_BUFFER); + PY_DICT_ADD_INT(GL_COPY_WRITE_BUFFER); + PY_DICT_ADD_INT(GL_INT_SAMPLER_2D_RECT); + PY_DICT_ADD_INT(GL_INT_SAMPLER_BUFFER); PY_DICT_ADD_INT(GL_INVALID_INDEX); PY_DICT_ADD_INT(GL_MAX_COMBINED_FRAGMENT_UNIFORM_COMPONENTS); PY_DICT_ADD_INT(GL_MAX_COMBINED_GEOMETRY_UNIFORM_COMPONENTS); @@ -3238,9 +3529,31 @@ PyObject *BPyInit_bgl(void) PY_DICT_ADD_INT(GL_MAX_COMBINED_VERTEX_UNIFORM_COMPONENTS); PY_DICT_ADD_INT(GL_MAX_FRAGMENT_UNIFORM_BLOCKS); PY_DICT_ADD_INT(GL_MAX_GEOMETRY_UNIFORM_BLOCKS); + PY_DICT_ADD_INT(GL_MAX_RECTANGLE_TEXTURE_SIZE); + PY_DICT_ADD_INT(GL_MAX_TEXTURE_BUFFER_SIZE); PY_DICT_ADD_INT(GL_MAX_UNIFORM_BLOCK_SIZE); PY_DICT_ADD_INT(GL_MAX_UNIFORM_BUFFER_BINDINGS); PY_DICT_ADD_INT(GL_MAX_VERTEX_UNIFORM_BLOCKS); + PY_DICT_ADD_INT(GL_PRIMITIVE_RESTART); + PY_DICT_ADD_INT(GL_PRIMITIVE_RESTART_INDEX); + PY_DICT_ADD_INT(GL_PROXY_TEXTURE_RECTANGLE); + PY_DICT_ADD_INT(GL_R16_SNORM); + PY_DICT_ADD_INT(GL_R8_SNORM); + PY_DICT_ADD_INT(GL_RG16_SNORM); + PY_DICT_ADD_INT(GL_RG8_SNORM); + PY_DICT_ADD_INT(GL_RGB16_SNORM); + PY_DICT_ADD_INT(GL_RGB8_SNORM); + PY_DICT_ADD_INT(GL_RGBA16_SNORM); + PY_DICT_ADD_INT(GL_RGBA8_SNORM); + PY_DICT_ADD_INT(GL_SAMPLER_2D_RECT); + PY_DICT_ADD_INT(GL_SAMPLER_2D_RECT_SHADOW); + PY_DICT_ADD_INT(GL_SAMPLER_BUFFER); + PY_DICT_ADD_INT(GL_SIGNED_NORMALIZED); + PY_DICT_ADD_INT(GL_TEXTURE_BINDING_BUFFER); + PY_DICT_ADD_INT(GL_TEXTURE_BINDING_RECTANGLE); + PY_DICT_ADD_INT(GL_TEXTURE_BUFFER); + PY_DICT_ADD_INT(GL_TEXTURE_BUFFER_DATA_STORE_BINDING); + PY_DICT_ADD_INT(GL_TEXTURE_RECTANGLE); PY_DICT_ADD_INT(GL_UNIFORM_ARRAY_STRIDE); PY_DICT_ADD_INT(GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS); PY_DICT_ADD_INT(GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES); @@ -3262,34 +3575,98 @@ PyObject *BPyInit_bgl(void) PY_DICT_ADD_INT(GL_UNIFORM_OFFSET); PY_DICT_ADD_INT(GL_UNIFORM_SIZE); PY_DICT_ADD_INT(GL_UNIFORM_TYPE); + PY_DICT_ADD_INT(GL_UNSIGNED_INT_SAMPLER_2D_RECT); + PY_DICT_ADD_INT(GL_UNSIGNED_INT_SAMPLER_BUFFER); } /* GL_VERSION_3_2 */ { + PY_DICT_ADD_INT(GL_ALREADY_SIGNALED); + PY_DICT_ADD_INT(GL_CONDITION_SATISFIED); + PY_DICT_ADD_INT(GL_CONTEXT_COMPATIBILITY_PROFILE_BIT); + PY_DICT_ADD_INT(GL_CONTEXT_CORE_PROFILE_BIT); + PY_DICT_ADD_INT(GL_CONTEXT_PROFILE_MASK); + PY_DICT_ADD_INT(GL_DEPTH_CLAMP); + PY_DICT_ADD_INT(GL_FIRST_VERTEX_CONVENTION); + PY_DICT_ADD_INT(GL_FRAMEBUFFER_ATTACHMENT_LAYERED); + PY_DICT_ADD_INT(GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS); + PY_DICT_ADD_INT(GL_GEOMETRY_INPUT_TYPE); + PY_DICT_ADD_INT(GL_GEOMETRY_OUTPUT_TYPE); + PY_DICT_ADD_INT(GL_GEOMETRY_SHADER); + PY_DICT_ADD_INT(GL_GEOMETRY_VERTICES_OUT); PY_DICT_ADD_INT(GL_INT_SAMPLER_2D_MULTISAMPLE); PY_DICT_ADD_INT(GL_INT_SAMPLER_2D_MULTISAMPLE_ARRAY); + PY_DICT_ADD_INT(GL_LAST_VERTEX_CONVENTION); + PY_DICT_ADD_INT(GL_LINES_ADJACENCY); + PY_DICT_ADD_INT(GL_LINE_STRIP_ADJACENCY); PY_DICT_ADD_INT(GL_MAX_COLOR_TEXTURE_SAMPLES); PY_DICT_ADD_INT(GL_MAX_DEPTH_TEXTURE_SAMPLES); + PY_DICT_ADD_INT(GL_MAX_FRAGMENT_INPUT_COMPONENTS); + PY_DICT_ADD_INT(GL_MAX_GEOMETRY_INPUT_COMPONENTS); + PY_DICT_ADD_INT(GL_MAX_GEOMETRY_OUTPUT_COMPONENTS); + PY_DICT_ADD_INT(GL_MAX_GEOMETRY_OUTPUT_VERTICES); + PY_DICT_ADD_INT(GL_MAX_GEOMETRY_TEXTURE_IMAGE_UNITS); + PY_DICT_ADD_INT(GL_MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS); + PY_DICT_ADD_INT(GL_MAX_GEOMETRY_UNIFORM_COMPONENTS); PY_DICT_ADD_INT(GL_MAX_INTEGER_SAMPLES); PY_DICT_ADD_INT(GL_MAX_SAMPLE_MASK_WORDS); + PY_DICT_ADD_INT(GL_MAX_SERVER_WAIT_TIMEOUT); + PY_DICT_ADD_INT(GL_MAX_VERTEX_OUTPUT_COMPONENTS); + PY_DICT_ADD_INT(GL_OBJECT_TYPE); + PY_DICT_ADD_INT(GL_PROGRAM_POINT_SIZE); + PY_DICT_ADD_INT(GL_PROVOKING_VERTEX); PY_DICT_ADD_INT(GL_PROXY_TEXTURE_2D_MULTISAMPLE); PY_DICT_ADD_INT(GL_PROXY_TEXTURE_2D_MULTISAMPLE_ARRAY); + PY_DICT_ADD_INT(GL_QUADS_FOLLOW_PROVOKING_VERTEX_CONVENTION); PY_DICT_ADD_INT(GL_SAMPLER_2D_MULTISAMPLE); PY_DICT_ADD_INT(GL_SAMPLER_2D_MULTISAMPLE_ARRAY); PY_DICT_ADD_INT(GL_SAMPLE_MASK); PY_DICT_ADD_INT(GL_SAMPLE_MASK_VALUE); PY_DICT_ADD_INT(GL_SAMPLE_POSITION); + PY_DICT_ADD_INT(GL_SIGNALED); + PY_DICT_ADD_INT(GL_SYNC_CONDITION); + PY_DICT_ADD_INT(GL_SYNC_FENCE); + PY_DICT_ADD_INT(GL_SYNC_FLAGS); + PY_DICT_ADD_INT(GL_SYNC_FLUSH_COMMANDS_BIT); + PY_DICT_ADD_INT(GL_SYNC_GPU_COMMANDS_COMPLETE); + PY_DICT_ADD_INT(GL_SYNC_STATUS); PY_DICT_ADD_INT(GL_TEXTURE_2D_MULTISAMPLE); PY_DICT_ADD_INT(GL_TEXTURE_2D_MULTISAMPLE_ARRAY); PY_DICT_ADD_INT(GL_TEXTURE_BINDING_2D_MULTISAMPLE); PY_DICT_ADD_INT(GL_TEXTURE_BINDING_2D_MULTISAMPLE_ARRAY); + PY_DICT_ADD_INT(GL_TEXTURE_CUBE_MAP_SEAMLESS); PY_DICT_ADD_INT(GL_TEXTURE_FIXED_SAMPLE_LOCATIONS); PY_DICT_ADD_INT(GL_TEXTURE_SAMPLES); + PY_DICT_ADD_INT(GL_TIMEOUT_EXPIRED); + PY_DICT_ADD_INT64(GL_TIMEOUT_IGNORED); + PY_DICT_ADD_INT(GL_TRIANGLES_ADJACENCY); + PY_DICT_ADD_INT(GL_TRIANGLE_STRIP_ADJACENCY); + PY_DICT_ADD_INT(GL_UNSIGNALED); PY_DICT_ADD_INT(GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE); PY_DICT_ADD_INT(GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE_ARRAY); + PY_DICT_ADD_INT(GL_WAIT_FAILED); } + /* GL_VERSION_3_3 */ + { + PY_DICT_ADD_INT(GL_ANY_SAMPLES_PASSED); + PY_DICT_ADD_INT(GL_INT_2_10_10_10_REV); + PY_DICT_ADD_INT(GL_MAX_DUAL_SOURCE_DRAW_BUFFERS); + PY_DICT_ADD_INT(GL_ONE_MINUS_SRC1_ALPHA); + PY_DICT_ADD_INT(GL_ONE_MINUS_SRC1_COLOR); + PY_DICT_ADD_INT(GL_RGB10_A2UI); + PY_DICT_ADD_INT(GL_SAMPLER_BINDING); + PY_DICT_ADD_INT(GL_SRC1_COLOR); + PY_DICT_ADD_INT(GL_TEXTURE_SWIZZLE_A); + PY_DICT_ADD_INT(GL_TEXTURE_SWIZZLE_B); + PY_DICT_ADD_INT(GL_TEXTURE_SWIZZLE_G); + PY_DICT_ADD_INT(GL_TEXTURE_SWIZZLE_R); + PY_DICT_ADD_INT(GL_TEXTURE_SWIZZLE_RGBA); + PY_DICT_ADD_INT(GL_TIMESTAMP); + PY_DICT_ADD_INT(GL_TIME_ELAPSED); + PY_DICT_ADD_INT(GL_VERTEX_ATTRIB_ARRAY_DIVISOR); + } return submodule; } diff --git a/source/blender/python/generic/blf_py_api.c b/source/blender/python/generic/blf_py_api.c index 5364c3bbb9e..0dfff9b4a7b 100644 --- a/source/blender/python/generic/blf_py_api.c +++ b/source/blender/python/generic/blf_py_api.c @@ -221,6 +221,29 @@ static PyObject *py_blf_clipping(PyObject *UNUSED(self), PyObject *args) Py_RETURN_NONE; } +PyDoc_STRVAR(py_blf_word_wrap_doc, +".. function:: word_wrap(fontid, wrap_width)\n" +"\n" +" Set the wrap width, enable/disable using WORD_WRAP.\n" +"\n" +" :arg fontid: The id of the typeface as returned by :func:`blf.load`, for default font use 0.\n" +" :type fontid: int\n" +" :arg wrap_width: The width (in pixels) to wrap words at.\n" +" :type wrap_width: int\n" +); +static PyObject *py_blf_word_wrap(PyObject *UNUSED(self), PyObject *args) +{ + int wrap_width; + int fontid; + + if (!PyArg_ParseTuple(args, "ii:blf.word_wrap", &fontid, &wrap_width)) + return NULL; + + BLF_wordwrap(fontid, wrap_width); + + Py_RETURN_NONE; +} + PyDoc_STRVAR(py_blf_disable_doc, ".. function:: disable(fontid, option)\n" "\n" @@ -393,6 +416,7 @@ static PyMethodDef BLF_methods[] = { {"aspect", (PyCFunction) py_blf_aspect, METH_VARARGS, py_blf_aspect_doc}, {"blur", (PyCFunction) py_blf_blur, METH_VARARGS, py_blf_blur_doc}, {"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}, {"dimensions", (PyCFunction) py_blf_dimensions, METH_VARARGS, py_blf_dimensions_doc}, {"draw", (PyCFunction) py_blf_draw, METH_VARARGS, py_blf_draw_doc}, @@ -432,6 +456,7 @@ PyObject *BPyInit_blf(void) PyModule_AddIntConstant(submodule, "CLIPPING", BLF_CLIPPING); PyModule_AddIntConstant(submodule, "SHADOW", BLF_SHADOW); PyModule_AddIntConstant(submodule, "KERNING_DEFAULT", BLF_KERNING_DEFAULT); + PyModule_AddIntConstant(submodule, "WORD_WRAP", BLF_WORD_WRAP); return submodule; } diff --git a/source/blender/python/generic/bpy_threads.c b/source/blender/python/generic/bpy_threads.c index 63a47ff0b20..fbc145660f3 100644 --- a/source/blender/python/generic/bpy_threads.c +++ b/source/blender/python/generic/bpy_threads.c @@ -27,11 +27,6 @@ * these functions are slightly different from the original Python API, * don't throw SIGABRT even if the thread state is NULL. */ -/* grr, python redefines */ -#ifdef _POSIX_C_SOURCE -# undef _POSIX_C_SOURCE -#endif - #include <Python.h> #include "BLI_utildefines.h" diff --git a/source/blender/python/generic/py_capi_utils.c b/source/blender/python/generic/py_capi_utils.c index 9e6ffe91848..e833dba04c8 100644 --- a/source/blender/python/generic/py_capi_utils.c +++ b/source/blender/python/generic/py_capi_utils.c @@ -29,7 +29,6 @@ * BLI_string_utf8() for unicode conversion. */ - #include <Python.h> #include <frameobject.h> @@ -666,7 +665,8 @@ void PyC_SetHomePath(const char *py_path_bundle) bool PyC_IsInterpreterActive(void) { - return (((PyThreadState *)_Py_atomic_load_relaxed(&_PyThreadState_Current)) != NULL); + /* instead of PyThreadState_Get, which calls Py_FatalError */ + return (PyThreadState_GetDict() != NULL); } /* Would be nice if python had this built in diff --git a/source/blender/python/intern/CMakeLists.txt b/source/blender/python/intern/CMakeLists.txt index cd2a9fd8584..f04bca75a8c 100644 --- a/source/blender/python/intern/CMakeLists.txt +++ b/source/blender/python/intern/CMakeLists.txt @@ -46,6 +46,7 @@ set(INC_SYS set(SRC gpu.c + gpu_offscreen.c bpy.c bpy_app.c bpy_app_build_options.c diff --git a/source/blender/python/intern/bpy_interface.c b/source/blender/python/intern/bpy_interface.c index 274b33558d3..d10816b809f 100644 --- a/source/blender/python/intern/bpy_interface.c +++ b/source/blender/python/intern/bpy_interface.c @@ -29,12 +29,6 @@ * be accesses from scripts. */ - -/* grr, python redefines */ -#ifdef _POSIX_C_SOURCE -# undef _POSIX_C_SOURCE -#endif - #include <Python.h> #ifdef WIN32 @@ -491,7 +485,9 @@ static int python_script_exec(bContext *C, const char *fn, struct Text *text, * incompatible'. * So now we load the script file data to a buffer */ { - const char *pystring = "with open(__file__, 'r') as f: exec(f.read())"; + const char *pystring = + "ns = globals().copy()\n" + "with open(__file__, 'rb') as f: exec(compile(f.read(), __file__, 'exec'), ns)"; fclose(fp); @@ -826,7 +822,7 @@ static void bpy_module_delay_init(PyObject *bpy_proxy) char filename_abs[1024]; BLI_strncpy(filename_abs, filename_rel, sizeof(filename_abs)); - BLI_path_cwd(filename_abs); + BLI_path_cwd(filename_abs, sizeof(filename_abs)); argv[0] = filename_abs; argv[1] = NULL; diff --git a/source/blender/python/intern/bpy_library.c b/source/blender/python/intern/bpy_library.c index a5879f11e51..0912ac0b637 100644 --- a/source/blender/python/intern/bpy_library.c +++ b/source/blender/python/intern/bpy_library.c @@ -335,7 +335,7 @@ static PyObject *bpy_lib_exit(BPy_Library *self, PyObject *UNUSED(args)) BKE_main_id_flag_all(bmain, LIB_PRE_EXISTING, true); /* here appending/linking starts */ - mainl = BLO_library_append_begin(bmain, &(self->blo_handle), self->relpath); + mainl = BLO_library_link_begin(bmain, &(self->blo_handle), self->relpath); { int idcode_step = 0, idcode; @@ -358,7 +358,7 @@ static PyObject *bpy_lib_exit(BPy_Library *self, PyObject *UNUSED(args)) // printf(" %s\n", item_str); if (item_str) { - ID *id = BLO_library_append_named_part(mainl, &(self->blo_handle), item_str, idcode); + ID *id = BLO_library_link_named_part(mainl, &(self->blo_handle), idcode, item_str); if (id) { #ifdef USE_RNA_DATABLOCKS /* swap name for pointer to the id */ @@ -405,7 +405,7 @@ static PyObject *bpy_lib_exit(BPy_Library *self, PyObject *UNUSED(args)) } else { Library *lib = mainl->curlib; /* newly added lib, assign before append end */ - BLO_library_append_end(NULL, mainl, &(self->blo_handle), 0, self->flag); + BLO_library_link_end(mainl, &(self->blo_handle), self->flag, NULL, NULL); BLO_blendhandle_close(self->blo_handle); self->blo_handle = NULL; diff --git a/source/blender/python/intern/bpy_rna.c b/source/blender/python/intern/bpy_rna.c index bd07c7370a4..5414c4e4204 100644 --- a/source/blender/python/intern/bpy_rna.c +++ b/source/blender/python/intern/bpy_rna.c @@ -988,15 +988,16 @@ static PyObject *pyrna_prop_repr(BPy_PropertyRNA *self) path = RNA_path_from_ID_to_property(&self->ptr, self->prop); if (path) { + const char *data_delim = (path[0] == '[') ? "" : "."; if (GS(id->name) == ID_NT) { /* nodetree paths are not accurate */ ret = PyUnicode_FromFormat("bpy.data...%s", path); } else { - ret = PyUnicode_FromFormat("bpy.data.%s[%R].%s", + ret = PyUnicode_FromFormat("bpy.data.%s[%R]%s%s", BKE_idcode_to_name_plural(GS(id->name)), tmp_str, - path); + data_delim, path); } MEM_freeN((void *)path); @@ -3388,6 +3389,21 @@ static PyObject *pyrna_prop_as_bytes(BPy_PropertyRNA *self) } } +PyDoc_STRVAR(pyrna_prop_update_doc, +".. method:: update()\n" +"\n" +" Execute the properties update callback.\n" +"\n" +" .. note::\n" +" This is called when assigning a property,\n" +" however in rare cases its useful to call explicitly.\n" +); +static PyObject *pyrna_prop_update(BPy_PropertyRNA *self) +{ + RNA_property_update(BPy_GetContext(), &self->ptr, self->prop); + Py_RETURN_NONE; +} + PyDoc_STRVAR(pyrna_struct_type_recast_doc, ".. method:: type_recast()\n" "\n" @@ -4721,6 +4737,7 @@ static struct PyMethodDef pyrna_struct_methods[] = { static struct PyMethodDef pyrna_prop_methods[] = { {"path_from_id", (PyCFunction)pyrna_prop_path_from_id, METH_NOARGS, pyrna_prop_path_from_id_doc}, {"as_bytes", (PyCFunction)pyrna_prop_as_bytes, METH_NOARGS, pyrna_prop_as_bytes_doc}, + {"update", (PyCFunction)pyrna_prop_update, METH_NOARGS, pyrna_prop_update_doc}, {"__dir__", (PyCFunction)pyrna_prop_dir, METH_NOARGS, NULL}, {NULL, NULL, 0, NULL} }; diff --git a/source/blender/python/intern/bpy_rna_callback.c b/source/blender/python/intern/bpy_rna_callback.c index 87c3a6eb4ef..4ae739407eb 100644 --- a/source/blender/python/intern/bpy_rna_callback.c +++ b/source/blender/python/intern/bpy_rna_callback.c @@ -174,7 +174,7 @@ static eSpace_Type rna_Space_refine_reverse(StructRNA *srna) if (srna == &RNA_SpaceConsole) return SPACE_CONSOLE; if (srna == &RNA_SpaceUserPreferences) return SPACE_USERPREF; if (srna == &RNA_SpaceClipEditor) return SPACE_CLIP; - return -1; + return SPACE_EMPTY; } PyObject *pyrna_callback_classmethod_add(PyObject *UNUSED(self), PyObject *args) @@ -220,7 +220,7 @@ PyObject *pyrna_callback_classmethod_add(PyObject *UNUSED(self), PyObject *args) } else { const eSpace_Type spaceid = rna_Space_refine_reverse(srna); - if (spaceid == -1) { + if (spaceid == SPACE_EMPTY) { PyErr_Format(PyExc_TypeError, "unknown space type '%.200s'", RNA_struct_identifier(srna)); return NULL; } @@ -283,7 +283,7 @@ PyObject *pyrna_callback_classmethod_remove(PyObject *UNUSED(self), PyObject *ar } else { const eSpace_Type spaceid = rna_Space_refine_reverse(srna); - if (spaceid == -1) { + if (spaceid == SPACE_EMPTY) { PyErr_Format(PyExc_TypeError, "unknown space type '%.200s'", RNA_struct_identifier(srna)); return NULL; } diff --git a/source/blender/python/intern/gpu.c b/source/blender/python/intern/gpu.c index f933c02390c..aada3f6fc80 100644 --- a/source/blender/python/intern/gpu.c +++ b/source/blender/python/intern/gpu.c @@ -32,11 +32,6 @@ * from blender materials. */ -/* python redefines */ -#ifdef _POSIX_C_SOURCE -#undef _POSIX_C_SOURCE -#endif - #include <Python.h> #include "DNA_scene_types.h" @@ -60,7 +55,7 @@ #define PY_MODULE_ADD_CONSTANT(module, name) PyModule_AddIntConstant(module, # name, name) PyDoc_STRVAR(M_gpu_doc, -"This module provides access to the GLSL shader." +"This module provides access to the GLSL shader and Offscreen rendering functionalities." ); static struct PyModuleDef gpumodule = { PyModuleDef_HEAD_INIT, @@ -79,6 +74,13 @@ static PyObject *PyInit_gpu(void) if (m == NULL) return NULL; + + /* Take care to update docs when editing: 'doc/python_api/rst/gpu.rst' */ + + + /* -------------------------------------------------------------------- */ + /* GPUDynamicType */ + /* device constant groups */ PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_GROUP_MISC); PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_GROUP_LAMP); @@ -90,12 +92,14 @@ static PyObject *PyInit_gpu(void) /* device constants */ PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_NONE); + /* GPU_DYNAMIC_GROUP_OBJECT */ PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_OBJECT_VIEWMAT); PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_OBJECT_MAT); PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_OBJECT_VIEWIMAT); PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_OBJECT_IMAT); PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_OBJECT_COLOR); PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_OBJECT_AUTOBUMPSCALE); + /* GPU_DYNAMIC_GROUP_LAMP */ PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_LAMP_DYNVEC); PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_LAMP_DYNCO); PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_LAMP_DYNIMAT); @@ -105,27 +109,36 @@ static PyObject *PyInit_gpu(void) PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_LAMP_ATT1); PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_LAMP_ATT2); PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_LAMP_DISTANCE); - PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_LAMP_SPOTBLEND); PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_LAMP_SPOTSIZE); + PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_LAMP_SPOTBLEND); + PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_LAMP_SPOTSCALE); + /* GPU_DYNAMIC_GROUP_SAMPLER */ PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_SAMPLER_2DBUFFER); PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_SAMPLER_2DIMAGE); PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_SAMPLER_2DSHADOW); + /* GPU_DYNAMIC_GROUP_MIST */ PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_MIST_ENABLE); PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_MIST_START); PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_MIST_DISTANCE); PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_MIST_INTENSITY); PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_MIST_TYPE); PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_MIST_COLOR); + /* GPU_DYNAMIC_GROUP_WORLD */ PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_HORIZON_COLOR); PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_AMBIENT_COLOR); - PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_MAT_ALPHA); - PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_MAT_AMB); + /* GPU_DYNAMIC_GROUP_MAT */ PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_MAT_DIFFRGB); - PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_MAT_EMIT); - PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_MAT_HARD); PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_MAT_REF); - PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_MAT_SPEC); PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_MAT_SPECRGB); + PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_MAT_SPEC); + PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_MAT_HARD); + PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_MAT_EMIT); + PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_MAT_AMB); + PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_MAT_ALPHA); + + + /* -------------------------------------------------------------------- */ + /* GPUDataType */ PY_MODULE_ADD_CONSTANT(m, GPU_DATA_1I); PY_MODULE_ADD_CONSTANT(m, GPU_DATA_1F); @@ -136,6 +149,12 @@ static PyObject *PyInit_gpu(void) PY_MODULE_ADD_CONSTANT(m, GPU_DATA_16F); PY_MODULE_ADD_CONSTANT(m, GPU_DATA_4UB); + + /* -------------------------------------------------------------------- */ + /* CustomDataType + * + * Intentionally only include the subset used by the GPU API. + */ PY_MODULE_ADD_CONSTANT(m, CD_MTFACE); PY_MODULE_ADD_CONSTANT(m, CD_ORCO); PY_MODULE_ADD_CONSTANT(m, CD_TANGENT); @@ -290,12 +309,25 @@ static PyMethodDef meth_export_shader[] = { {"export_shader", (PyCFunction)GPU_export_shader, METH_VARARGS | METH_KEYWORDS, GPU_export_shader_doc} }; +/* -------------------------------------------------------------------- */ +/* Initialize Module */ + PyObject *GPU_initPython(void) { - PyObject *module = PyInit_gpu(); + PyObject *module; + PyObject *submodule; + PyObject *sys_modules = PyThreadState_GET()->interp->modules; + + module = PyInit_gpu(); + PyModule_AddObject(module, "export_shader", (PyObject *)PyCFunction_New(meth_export_shader, NULL)); - PyDict_SetItemString(PyImport_GetModuleDict(), "gpu", module); + /* gpu.offscreen */ + PyModule_AddObject(module, "offscreen", (submodule = BPyInit_gpu_offscreen())); + PyDict_SetItemString(sys_modules, PyModule_GetName(submodule), submodule); + Py_INCREF(submodule); + + PyDict_SetItemString(PyImport_GetModuleDict(), "gpu", module); return module; } diff --git a/source/blender/python/intern/gpu.h b/source/blender/python/intern/gpu.h index 82338869b9d..0da44a4eb87 100644 --- a/source/blender/python/intern/gpu.h +++ b/source/blender/python/intern/gpu.h @@ -36,4 +36,6 @@ PyObject *GPU_initPython(void); +PyObject *BPyInit_gpu_offscreen(void); + #endif /* __GPU_H__ */ diff --git a/source/blender/python/intern/gpu_offscreen.c b/source/blender/python/intern/gpu_offscreen.c new file mode 100644 index 00000000000..f8285c6139f --- /dev/null +++ b/source/blender/python/intern/gpu_offscreen.c @@ -0,0 +1,424 @@ +/* + * ***** 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. + * + * Copyright 2015, Blender Foundation. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/python/intern/gpu_offscreen.c + * \ingroup pythonintern + * + * This file defines the offscreen functionalities of the 'gpu' module + * used for off-screen OpenGL rendering. + */ + +#include <Python.h> + +#include "BLI_utildefines.h" + +#include "WM_types.h" + +#include "ED_screen.h" + +#include "GPU_extensions.h" +#include "GPU_compositing.h" + +#include "../mathutils/mathutils.h" + +#include "../generic/py_capi_utils.h" + +#include "gpu.h" + +#include "ED_view3d.h" + +/* -------------------------------------------------------------------- */ +/* GPU Offscreen PyObject */ + +typedef struct { + PyObject_HEAD + GPUOffScreen *ofs; +} BPy_GPUOffScreen; + +static int bpy_gpu_offscreen_valid_check(BPy_GPUOffScreen *py_gpu_ofs) +{ + if (UNLIKELY(py_gpu_ofs->ofs == NULL)) { + PyErr_SetString(PyExc_ReferenceError, "GPU offscreen was freed, no further access is valid"); + return -1; + } + return 0; +} + +#define BPY_GPU_OFFSCREEN_CHECK_OBJ(pygpu) { \ + if (UNLIKELY(bpy_gpu_offscreen_valid_check(pygpu) == -1)) { \ + return NULL; \ + } \ +} ((void)0) + +PyDoc_STRVAR(pygpu_offscreen_width_doc, "Texture width.\n\n:type: int"); +static PyObject *pygpu_offscreen_width_get(BPy_GPUOffScreen *self, void *UNUSED(type)) +{ + BPY_GPU_OFFSCREEN_CHECK_OBJ(self); + return PyLong_FromLong(GPU_offscreen_width(self->ofs)); +} + +PyDoc_STRVAR(pygpu_offscreen_height_doc, "Texture height.\n\n:type: int"); +static PyObject *pygpu_offscreen_height_get(BPy_GPUOffScreen *self, void *UNUSED(type)) +{ + BPY_GPU_OFFSCREEN_CHECK_OBJ(self); + return PyLong_FromLong(GPU_offscreen_height(self->ofs)); +} + +PyDoc_STRVAR(pygpu_offscreen_color_texture_doc, "Color texture.\n\n:type: int"); +static PyObject *pygpu_offscreen_color_texture_get(BPy_GPUOffScreen *self, void *UNUSED(type)) +{ + BPY_GPU_OFFSCREEN_CHECK_OBJ(self); + return PyLong_FromLong(GPU_offscreen_color_texture(self->ofs)); +} + +PyDoc_STRVAR(pygpu_offscreen_bind_doc, +"bind(save=True)\n" +"\n" +" Bind the offscreen object.\n" +"\n" +" :param save: save OpenGL current states.\n" +" :type save: bool\n" +); +static PyObject *pygpu_offscreen_bind(BPy_GPUOffScreen *self, PyObject *args, PyObject *kwds) +{ + static const char *kwlist[] = {"save", NULL}; + bool save = true; + + BPY_GPU_OFFSCREEN_CHECK_OBJ(self); + + if (!PyArg_ParseTupleAndKeywords( + args, kwds, "|O&:bind", (char **)(kwlist), + PyC_ParseBool, &save)) + { + return NULL; + } + + GPU_offscreen_bind(self->ofs, save); + Py_RETURN_NONE; +} + +PyDoc_STRVAR(pygpu_offscreen_unbind_doc, +"unbind(restore=True)\n" +"\n" +" Unbind the offscreen object.\n" +"\n" +" :param restore: restore OpenGL previous states.\n" +" :type restore: bool\n" +); +static PyObject *pygpu_offscreen_unbind(BPy_GPUOffScreen *self, PyObject *args, PyObject *kwds) +{ + static const char *kwlist[] = {"restore", NULL}; + bool restore = true; + + BPY_GPU_OFFSCREEN_CHECK_OBJ(self); + + if (!PyArg_ParseTupleAndKeywords( + args, kwds, "|O&:unbind", (char **)(kwlist), + PyC_ParseBool, &restore)) + { + return NULL; + } + + GPU_offscreen_unbind(self->ofs, restore); + Py_RETURN_NONE; +} + +/** + * Use with PyArg_ParseTuple's "O&" formatting. + */ +static int pygpu_offscreen_check_matrix(PyObject *o, void *p) +{ + MatrixObject **pymat_p = p; + MatrixObject *pymat = (MatrixObject *)o; + + if (!MatrixObject_Check(pymat)) { + PyErr_Format(PyExc_TypeError, + "expected a mathutils.Matrix, not a %.200s", + Py_TYPE(o)->tp_name); + return 0; + } + + if (BaseMath_ReadCallback(pymat) == -1) { + return 0; + } + + if ((pymat->num_col != 4) || + (pymat->num_row != 4)) + { + PyErr_SetString(PyExc_ValueError, "matrix must be 4x4"); + return 0; + } + + *pymat_p = pymat; + return 1; +} + +PyDoc_STRVAR(pygpu_offscreen_draw_view3d_doc, +"draw_view3d(scene, view3d, region, modelview_matrix, projection_matrix)\n" +"\n" +" Draw the 3d viewport in the offscreen object.\n" +"\n" +" :param scene: Scene to draw.\n" +" :type scene: :class:`bpy.types.Scene`\n" +" :param view3d: 3D View to get the drawing settings from.\n" +" :type view3d: :class:`bpy.types.SpaceView3D`\n" +" :param region: Region of the 3D View.\n" +" :type region: :class:`bpy.types.Region`\n" +" :param modelview_matrix: ModelView Matrix.\n" +" :type modelview_matrix: :class:`mathutils.Matrix`\n" +" :param projection_matrix: Projection Matrix.\n" +" :type projection_matrix: :class:`mathutils.Matrix`\n" +); +static PyObject *pygpu_offscreen_draw_view3d(BPy_GPUOffScreen *self, PyObject *args, PyObject *kwds) +{ + static const char *kwlist[] = {"scene", "view3d", "region", "projection_matrix", "modelview_matrix", NULL}; + + MatrixObject *py_mat_modelview, *py_mat_projection; + PyObject *py_scene, *py_region, *py_view3d; + + Scene *scene; + View3D *v3d; + ARegion *ar; + GPUFX *fx; + GPUFXSettings fx_settings; + + BPY_GPU_OFFSCREEN_CHECK_OBJ(self); + + if (!PyArg_ParseTupleAndKeywords( + args, kwds, "OOOO&O&:draw_view3d", (char **)(kwlist), + &py_scene, &py_view3d, &py_region, + pygpu_offscreen_check_matrix, &py_mat_projection, + pygpu_offscreen_check_matrix, &py_mat_modelview) || + (!(scene = PyC_RNA_AsPointer(py_scene, "Scene")) || + !(v3d = PyC_RNA_AsPointer(py_view3d, "SpaceView3D")) || + !(ar = PyC_RNA_AsPointer(py_region, "Region")))) + { + return NULL; + } + + fx = GPU_fx_compositor_create(); + + fx_settings = v3d->fx_settings; /* full copy */ + + ED_view3d_draw_offscreen_init(scene, v3d); + + GPU_offscreen_bind(self->ofs, true); /* bind */ + + ED_view3d_draw_offscreen( + scene, v3d, ar, GPU_offscreen_width(self->ofs), GPU_offscreen_height(self->ofs), + (float(*)[4])py_mat_modelview->matrix, (float(*)[4])py_mat_projection->matrix, + false, true, true, "", + fx, &fx_settings, + self->ofs); + + GPU_fx_compositor_destroy(fx); + GPU_offscreen_unbind(self->ofs, true); /* unbind */ + + Py_RETURN_NONE; +} + +PyDoc_STRVAR(pygpu_offscreen_free_doc, +"free()\n" +"\n" +" Free the offscreen object\n" +" The framebuffer, texture and render objects will no longer be accessible.\n" +); +static PyObject *pygpu_offscreen_free(BPy_GPUOffScreen *self) +{ + BPY_GPU_OFFSCREEN_CHECK_OBJ(self); + + GPU_offscreen_free(self->ofs); + self->ofs = NULL; + Py_RETURN_NONE; +} + +static void BPy_GPUOffScreen__tp_dealloc(BPy_GPUOffScreen *self) +{ + if (self->ofs) + GPU_offscreen_free(self->ofs); + Py_TYPE(self)->tp_free((PyObject *)self); +} + +static PyGetSetDef bpy_gpu_offscreen_getseters[] = { + {(char *)"color_texture", (getter)pygpu_offscreen_color_texture_get, (setter)NULL, pygpu_offscreen_color_texture_doc, NULL}, + {(char *)"width", (getter)pygpu_offscreen_width_get, (setter)NULL, pygpu_offscreen_width_doc, NULL}, + {(char *)"height", (getter)pygpu_offscreen_height_get, (setter)NULL, pygpu_offscreen_height_doc, NULL}, + {NULL, NULL, NULL, NULL, NULL} /* Sentinel */ +}; + +static struct PyMethodDef bpy_gpu_offscreen_methods[] = { + {"bind", (PyCFunction)pygpu_offscreen_bind, METH_VARARGS | METH_KEYWORDS, pygpu_offscreen_bind_doc}, + {"unbind", (PyCFunction)pygpu_offscreen_unbind, METH_VARARGS | METH_KEYWORDS, pygpu_offscreen_unbind_doc}, + {"draw_view3d", (PyCFunction)pygpu_offscreen_draw_view3d, METH_VARARGS | METH_KEYWORDS, pygpu_offscreen_draw_view3d_doc}, + {"free", (PyCFunction)pygpu_offscreen_free, METH_NOARGS, pygpu_offscreen_free_doc}, + {NULL, NULL, 0, NULL} +}; + +PyDoc_STRVAR(py_gpu_offscreen_doc, +".. class:: GPUOffscreen" +"\n" +" This object gives access to off screen buffers.\n" +); +static PyTypeObject BPy_GPUOffScreen_Type = { + PyVarObject_HEAD_INIT(NULL, 0) + "GPUOffScreen", /* tp_name */ + sizeof(BPy_GPUOffScreen), /* tp_basicsize */ + 0, /* tp_itemsize */ + /* methods */ + (destructor)BPy_GPUOffScreen__tp_dealloc, /* tp_dealloc */ + NULL, /* tp_print */ + NULL, /* tp_getattr */ + NULL, /* tp_setattr */ + NULL, /* tp_compare */ + NULL, /* tp_repr */ + NULL, /* tp_as_number */ + NULL, /* tp_as_sequence */ + NULL, /* tp_as_mapping */ + NULL, /* tp_hash */ + NULL, /* tp_call */ + NULL, /* tp_str */ + NULL, /* tp_getattro */ + NULL, /* tp_setattro */ + NULL, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT, /* tp_flags */ + py_gpu_offscreen_doc, /* Documentation string */ + NULL, /* tp_traverse */ + NULL, /* tp_clear */ + NULL, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + NULL, /* tp_iter */ + NULL, /* tp_iternext */ + bpy_gpu_offscreen_methods, /* tp_methods */ + NULL, /* tp_members */ + bpy_gpu_offscreen_getseters, /* tp_getset */ + NULL, /* tp_base */ + NULL, /* tp_dict */ + NULL, /* tp_descr_get */ + NULL, /* tp_descr_set */ + 0, /* tp_dictoffset */ + 0, /* tp_init */ + NULL, /* tp_alloc */ + NULL, /* tp_new */ + (freefunc)0, /* tp_free */ + NULL, /* tp_is_gc */ + NULL, /* tp_bases */ + NULL, /* tp_mro */ + NULL, /* tp_cache */ + NULL, /* tp_subclasses */ + NULL, /* tp_weaklist */ + (destructor) NULL /* tp_del */ +}; + +/* -------------------------------------------------------------------- */ +/* GPU offscreen methods */ + +static PyObject *BPy_GPU_OffScreen_CreatePyObject(GPUOffScreen *ofs) +{ + BPy_GPUOffScreen *self; + self = PyObject_New(BPy_GPUOffScreen, &BPy_GPUOffScreen_Type); + self->ofs = ofs; + return (PyObject *)self; +} + +PyDoc_STRVAR(pygpu_offscreen_new_doc, +"new(width, height, samples=0)\n" +"\n" +" Return a GPUOffScreen.\n" +"\n" +" :param width: Horizontal dimension of the buffer.\n" +" :type width: int`\n" +" :param height: Vertical dimension of the buffer.\n" +" :type height: int`\n" +" :param samples: OpenGL samples to use for MSAA or zero to disable.\n" +" :type samples: int\n" +" :return: Newly created off-screen buffer.\n" +" :rtype: :class:`gpu.GPUOffscreen`\n" +); +static PyObject *pygpu_offscreen_new(PyObject *UNUSED(self), PyObject *args, PyObject *kwds) +{ + static const char *kwlist[] = {"width", "height", "samples", NULL}; + + GPUOffScreen *ofs; + int width, height, samples = 0; + char err_out[256]; + + if (!PyArg_ParseTupleAndKeywords( + args, kwds, "ii|i:new", (char **)(kwlist), + &width, &height, &samples)) + { + return NULL; + } + + ofs = GPU_offscreen_create(width, height, samples, err_out); + + if (ofs == NULL) { + PyErr_Format(PyExc_RuntimeError, + "gpu.offscreen.new(...) failed with '%s'", + err_out[0] ? err_out : "unknown error"); + return NULL; + } + + return BPy_GPU_OffScreen_CreatePyObject(ofs); +} + +static struct PyMethodDef BPy_GPU_offscreen_methods[] = { + {"new", (PyCFunction)pygpu_offscreen_new, METH_VARARGS | METH_KEYWORDS, pygpu_offscreen_new_doc}, + {NULL, NULL, 0, NULL} +}; + +PyDoc_STRVAR(BPy_GPU_offscreen_doc, +"This module provides access to offscreen rendering functions." +); +static PyModuleDef BPy_GPU_offscreen_module_def = { + PyModuleDef_HEAD_INIT, + "gpu.offscreen", /* m_name */ + BPy_GPU_offscreen_doc, /* m_doc */ + 0, /* m_size */ + BPy_GPU_offscreen_methods, /* m_methods */ + NULL, /* m_reload */ + NULL, /* m_traverse */ + NULL, /* m_clear */ + NULL, /* m_free */ +}; + +PyObject *BPyInit_gpu_offscreen(void) +{ + PyObject *submodule; + + /* Register the 'GPUOffscreen' class */ + if (PyType_Ready(&BPy_GPUOffScreen_Type)) { + return NULL; + } + + submodule = PyModule_Create(&BPy_GPU_offscreen_module_def); + +#define MODULE_TYPE_ADD(s, t) \ + PyModule_AddObject(s, t.tp_name, (PyObject *)&t); Py_INCREF((PyObject *)&t) + + MODULE_TYPE_ADD(submodule, BPy_GPUOffScreen_Type); + +#undef MODULE_TYPE_ADD + + return submodule; +} + +#undef BPY_GPU_OFFSCREEN_CHECK_OBJ diff --git a/source/blender/python/mathutils/mathutils.c b/source/blender/python/mathutils/mathutils.c index 16d8d6477a5..635090869ea 100644 --- a/source/blender/python/mathutils/mathutils.c +++ b/source/blender/python/mathutils/mathutils.c @@ -355,7 +355,7 @@ int mathutils_any_to_rotmat(float rmat[3][3], PyObject *value, const char *error /* XXX We may want to use 'safer' BLI's compare_ff_relative ultimately? * LomontRRDCompare4() is an optimized version of Dawson's AlmostEqual2sComplement() (see [1] and [2]). * Dawson himself now claims this is not a 'safe' thing to do (pushing ULP method beyond its limits), - * an recommands using work from [3] instead, which is done in BLI func... + * an recommends using work from [3] instead, which is done in BLI func... * * [1] http://www.randydillon.org/Papers/2007/everfast.htm * [2] http://www.cygnus-software.com/papers/comparingfloats/comparingfloats.htm diff --git a/source/blender/python/mathutils/mathutils_bvhtree.c b/source/blender/python/mathutils/mathutils_bvhtree.c index 8a488fdfd08..9deb57d6760 100644 --- a/source/blender/python/mathutils/mathutils_bvhtree.c +++ b/source/blender/python/mathutils/mathutils_bvhtree.c @@ -277,7 +277,7 @@ static void py_bvhtree_raycast_cb(void *userdata, int index, const BVHTreeRay *r { const PyBVHTree *self = userdata; - const float (*coords)[3] = self->coords; + const float (*coords)[3] = (const float (*)[3])self->coords; const unsigned int *tri = self->tris[index]; const float *tri_co[3] = {coords[tri[0]], coords[tri[1]], coords[tri[2]]}; float dist; @@ -306,7 +306,7 @@ static void py_bvhtree_nearest_point_cb(void *userdata, int index, const float c { PyBVHTree *self = userdata; - const float (*coords)[3] = self->coords; + const float (*coords)[3] = (const float (*)[3])self->coords; const unsigned int *tri = self->tris[index]; const float *tri_co[3] = {coords[tri[0]], coords[tri[1]], coords[tri[2]]}; float nearest_tmp[3], dist_sq; @@ -352,7 +352,7 @@ static PyObject *py_bvhtree_ray_cast(PyBVHTree *self, PyObject *args) if (!PyArg_ParseTuple( args, (char *)"OO|f:ray_cast", - &py_co, &py_direction, max_dist)) + &py_co, &py_direction, &max_dist)) { return NULL; } diff --git a/source/blender/python/mathutils/mathutils_geometry.c b/source/blender/python/mathutils/mathutils_geometry.c index 81d000991d0..a4ca2520919 100644 --- a/source/blender/python/mathutils/mathutils_geometry.c +++ b/source/blender/python/mathutils/mathutils_geometry.c @@ -415,7 +415,9 @@ static PyObject *M_Geometry_volume_tetrahedron(PyObject *UNUSED(self), PyObject PyDoc_STRVAR(M_Geometry_intersect_line_line_2d_doc, ".. function:: intersect_line_line_2d(lineA_p1, lineA_p2, lineB_p1, lineB_p2)\n" "\n" -" Takes 2 lines (as 4 vectors) and returns a vector for their point of intersection or None.\n" +" Takes 2 segments (defined by 4 vectors) and returns a vector for their point of intersection or None.\n" +"\n" +" .. warning:: Despite its name, this function works on segments, and not on lines..." "\n" " :arg lineA_p1: First point of the first line\n" " :type lineA_p1: :class:`mathutils.Vector`\n" @@ -530,6 +532,7 @@ static PyObject *M_Geometry_intersect_plane_plane(PyObject *UNUSED(self), PyObje PyObject *ret, *ret_co, *ret_no; PyObject *py_plane_a_co, *py_plane_a_no, *py_plane_b_co, *py_plane_b_no; float plane_a_co[3], plane_a_no[3], plane_b_co[3], plane_b_no[3]; + float plane_a[4], plane_b[4]; float isect_co[3]; float isect_no[3]; @@ -549,9 +552,12 @@ static PyObject *M_Geometry_intersect_plane_plane(PyObject *UNUSED(self), PyObje return NULL; } - if (isect_plane_plane_v3(isect_co, isect_no, - plane_a_co, plane_a_no, - plane_b_co, plane_b_no)) + plane_from_point_normal_v3(plane_a, plane_a_co, plane_a_no); + plane_from_point_normal_v3(plane_b, plane_b_co, plane_b_no); + + if (isect_plane_plane_v3( + plane_a, plane_b, + isect_co, isect_no)) { normalize_v3(isect_no); diff --git a/source/blender/quicktime/apple/qtkit_export.m b/source/blender/quicktime/apple/qtkit_export.m index a4ee398da5d..9bc4ec444bb 100644 --- a/source/blender/quicktime/apple/qtkit_export.m +++ b/source/blender/quicktime/apple/qtkit_export.m @@ -378,8 +378,7 @@ int start_qt( } else { makeqtstring(rd, name, preview); - qtexport->filename = [[NSString alloc] initWithCString:name - encoding:[NSString defaultCStringEncoding]]; + qtexport->filename = [[NSString alloc] initWithUTF8String:name]; qtexport->movie = nil; qtexport->audioFile = NULL; diff --git a/source/blender/quicktime/quicktime_export.h b/source/blender/quicktime/quicktime_export.h index 8a10a4a05d6..41db83fb1c9 100644 --- a/source/blender/quicktime/quicktime_export.h +++ b/source/blender/quicktime/quicktime_export.h @@ -46,7 +46,7 @@ typedef struct QuicktimeCodecTypeDesc { int codecType; int rnatmpvalue; - char *codecName; + const char *codecName; } QuicktimeCodecTypeDesc; // quicktime movie output functions diff --git a/source/blender/render/extern/include/RE_pipeline.h b/source/blender/render/extern/include/RE_pipeline.h index 2a679f0f0d0..fd56c47c309 100644 --- a/source/blender/render/extern/include/RE_pipeline.h +++ b/source/blender/render/extern/include/RE_pipeline.h @@ -207,6 +207,10 @@ void RE_InitRenderCB(struct Render *re); void RE_FreeRender(struct Render *re); /* only called on exit */ void RE_FreeAllRender(void); +/* Free memory used by persistent data. + * Invoked when loading new file. + */ +void RE_FreeAllPersistentData(void); /* only call on file load */ void RE_FreeAllRenderResults(void); /* for external render engines that can keep persistent data */ diff --git a/source/blender/render/extern/include/RE_render_ext.h b/source/blender/render/extern/include/RE_render_ext.h index 6e1f128b7a5..85a9dc9fccd 100644 --- a/source/blender/render/extern/include/RE_render_ext.h +++ b/source/blender/render/extern/include/RE_render_ext.h @@ -63,7 +63,11 @@ void RE_sample_material_color( struct PointDensity; -void RE_sample_point_density(struct Scene *scene, struct PointDensity *pd, int resolution, float *values); +void RE_sample_point_density(struct Scene *scene, + struct PointDensity *pd, + const int resolution, + const bool use_render_params, + float *values); void RE_init_texture_rng(void); void RE_exit_texture_rng(void); diff --git a/source/blender/render/intern/include/renderdatabase.h b/source/blender/render/intern/include/renderdatabase.h index da45a2bfead..224974454e8 100644 --- a/source/blender/render/intern/include/renderdatabase.h +++ b/source/blender/render/intern/include/renderdatabase.h @@ -115,7 +115,9 @@ struct HaloRen *RE_inithalo_particle(struct Render *re, struct ObjectRen *obr, s struct StrandBuffer *RE_addStrandBuffer(struct ObjectRen *obr, int totvert); struct ObjectRen *RE_addRenderObject(struct Render *re, struct Object *ob, struct Object *par, int index, int psysindex, int lay); -struct ObjectInstanceRen *RE_addRenderInstance(struct Render *re, struct ObjectRen *obr, struct Object *ob, struct Object *par, int index, int psysindex, float mat[4][4], int lay); +struct ObjectInstanceRen *RE_addRenderInstance( + struct Render *re, struct ObjectRen *obr, struct Object *ob, struct Object *par, + int index, int psysindex, float mat[4][4], int lay, const struct DupliObject *dob); void RE_makeRenderInstances(struct Render *re); void RE_instance_rotate_ray_start(struct ObjectInstanceRen *obi, struct Isect *is); diff --git a/source/blender/render/intern/source/bake.c b/source/blender/render/intern/source/bake.c index 0210bec5ab4..30036c27b5d 100644 --- a/source/blender/render/intern/source/bake.c +++ b/source/blender/render/intern/source/bake.c @@ -320,7 +320,7 @@ static void bake_shade(void *handle, Object *ob, ShadeInput *shi, int UNUSED(qua } else { unsigned char *imcol = (unsigned char *)(bs->rect + bs->rectx * y + x); - copy_v4_v4_char((char *)imcol, (char *)col); + copy_v4_v4_uchar(imcol, col); } } @@ -375,8 +375,8 @@ static void bake_displacement(void *handle, ShadeInput *UNUSED(shi), float dist, bs->vcol->b = col[2]; } else { - char *imcol = (char *)(bs->rect + bs->rectx * y + x); - copy_v4_v4_char(imcol, (char *)col); + unsigned char *imcol = (unsigned char *)(bs->rect + bs->rectx * y + x); + copy_v4_v4_uchar(imcol, col); } } if (bs->rect_mask) { diff --git a/source/blender/render/intern/source/bake_api.c b/source/blender/render/intern/source/bake_api.c index dee75d43f36..77f6ab9cfc2 100644 --- a/source/blender/render/intern/source/bake_api.c +++ b/source/blender/render/intern/source/bake_api.c @@ -356,22 +356,26 @@ static bool cast_ray_highpoly( * This function populates an array of verts for the triangles of a mesh * Tangent and Normals are also stored */ -static void mesh_calc_tri_tessface( - TriTessFace *triangles, Mesh *me, bool tangent, DerivedMesh *dm) +static TriTessFace *mesh_calc_tri_tessface( + Mesh *me, bool tangent, DerivedMesh *dm) { int i; MVert *mvert; TSpace *tspace; float *precomputed_normals = NULL; bool calculate_normal; + const int tottri = poly_to_tri_count(me->totpoly, me->totloop); MLoopTri *looptri; + TriTessFace *triangles; + /* calculate normal for each polygon only once */ unsigned int mpoly_prev = UINT_MAX; float no[3]; mvert = CustomData_get_layer(&me->vdata, CD_MVERT); looptri = MEM_mallocN(sizeof(*looptri) * tottri, __func__); + triangles = MEM_mallocN(sizeof(TriTessFace) * tottri, __func__); if (tangent) { DM_ensure_normals(dm); @@ -419,6 +423,8 @@ static void mesh_calc_tri_tessface( } MEM_freeN(looptri); + + return triangles; } bool RE_bake_pixels_populate_from_objects( @@ -451,26 +457,20 @@ bool RE_bake_pixels_populate_from_objects( if (!is_cage) { dm_low = CDDM_from_mesh(me_low); - tris_low = MEM_mallocN(sizeof(TriTessFace) * (me_low->totface * 2), "MVerts Lowpoly Mesh"); - mesh_calc_tri_tessface(tris_low, me_low, true, dm_low); + tris_low = mesh_calc_tri_tessface(me_low, true, dm_low); } else if (is_custom_cage) { - tris_low = MEM_mallocN(sizeof(TriTessFace) * (me_low->totface * 2), "MVerts Lowpoly Mesh"); - mesh_calc_tri_tessface(tris_low, me_low, false, NULL); - - tris_cage = MEM_mallocN(sizeof(TriTessFace) * (me_low->totface * 2), "MVerts Cage Mesh"); - mesh_calc_tri_tessface(tris_cage, me_cage, false, NULL); + tris_low = mesh_calc_tri_tessface(me_low, false, NULL); + tris_cage = mesh_calc_tri_tessface(me_cage, false, NULL); } else { - tris_cage = MEM_mallocN(sizeof(TriTessFace) * (me_low->totface * 2), "MVerts Cage Mesh"); - mesh_calc_tri_tessface(tris_cage, me_cage, false, NULL); + tris_cage = mesh_calc_tri_tessface(me_cage, false, NULL); } invert_m4_m4(imat_low, mat_low); for (i = 0; i < tot_highpoly; i++) { - tris_high[i] = MEM_mallocN(sizeof(TriTessFace) * highpoly[i].me->totface, "MVerts Highpoly Mesh"); - mesh_calc_tri_tessface(tris_high[i], highpoly[i].me, false, NULL); + tris_high[i] = mesh_calc_tri_tessface(highpoly[i].me, false, NULL); dm_highpoly[i] = CDDM_from_mesh(highpoly[i].me); DM_ensure_tessface(dm_highpoly[i]); @@ -583,13 +583,26 @@ void RE_bake_pixels_populate( size_t i; int a, p_id; - MTFace *mtface; - MFace *mface; + const MLoopUV *mloopuv; + const int tottri = poly_to_tri_count(me->totpoly, me->totloop); + MLoopTri *looptri; /* we can't bake in edit mode */ if (me->edit_btmesh) return; + if ((uv_layer == NULL) || (uv_layer[0] == '\0')) { + mloopuv = CustomData_get_layer(&me->ldata, CD_MLOOPUV); + } + else { + int uv_id = CustomData_get_named_layer(&me->ldata, CD_MLOOPUV, uv_layer); + mloopuv = CustomData_get_layer_n(&me->ldata, CD_MTFACE, uv_id); + } + + if (mloopuv == NULL) + return; + + bd.pixel_array = pixel_array; bd.zspan = MEM_callocN(sizeof(ZSpan) * bake_images->size, "bake zspan"); @@ -602,54 +615,45 @@ void RE_bake_pixels_populate( zbuf_alloc_span(&bd.zspan[i], bake_images->data[i].width, bake_images->data[i].height, R.clipcrop); } - if ((uv_layer == NULL) || (uv_layer[0] == '\0')) { - mtface = CustomData_get_layer(&me->fdata, CD_MTFACE); - } - else { - int uv_id = CustomData_get_named_layer(&me->fdata, CD_MTFACE, uv_layer); - mtface = CustomData_get_layer_n(&me->fdata, CD_MTFACE, uv_id); - } - - mface = CustomData_get_layer(&me->fdata, CD_MFACE); + looptri = MEM_mallocN(sizeof(*looptri) * tottri, __func__); - if (mtface == NULL) - return; + BKE_mesh_recalc_looptri( + me->mloop, me->mpoly, + me->mvert, + me->totloop, me->totpoly, + looptri); p_id = -1; - for (i = 0; i < me->totface; i++) { - float vec[4][2]; - MTFace *mtf = &mtface[i]; - MFace *mf = &mface[i]; - int mat_nr = mf->mat_nr; + for (i = 0; i < tottri; i++) { + const MLoopTri *lt = &looptri[i]; + const MPoly *mp = &me->mpoly[lt->poly]; + float vec[3][2]; + int mat_nr = mp->mat_nr; int image_id = bake_images->lookup[mat_nr]; bd.bk_image = &bake_images->data[image_id]; bd.primitive_id = ++p_id; - for (a = 0; a < 4; a++) { + for (a = 0; a < 3; a++) { + const float *uv = mloopuv[lt->tri[a]].uv; + /* Note, workaround for pixel aligned UVs which are common and can screw up our intersection tests * where a pixel gets in between 2 faces or the middle of a quad, * camera aligned quads also have this problem but they are less common. * Add a small offset to the UVs, fixes bug #18685 - Campbell */ - vec[a][0] = mtf->uv[a][0] * (float)bd.bk_image->width - (0.5f + 0.001f); - vec[a][1] = mtf->uv[a][1] * (float)bd.bk_image->height - (0.5f + 0.002f); + vec[a][0] = uv[0] * (float)bd.bk_image->width - (0.5f + 0.001f); + vec[a][1] = uv[1] * (float)bd.bk_image->height - (0.5f + 0.002f); } bake_differentials(&bd, vec[0], vec[1], vec[2]); zspan_scanconvert(&bd.zspan[image_id], (void *)&bd, vec[0], vec[1], vec[2], store_bake_pixel); - - /* 4 vertices in the face */ - if (mf->v4 != 0) { - bd.primitive_id = ++p_id; - - bake_differentials(&bd, vec[0], vec[2], vec[3]); - zspan_scanconvert(&bd.zspan[image_id], (void *)&bd, vec[0], vec[2], vec[3], store_bake_pixel); - } } for (i = 0; i < bake_images->size; i++) { zbuf_free_span(&bd.zspan[i]); } + + MEM_freeN(looptri); MEM_freeN(bd.zspan); } @@ -718,8 +722,7 @@ void RE_bake_normal_world_to_tangent( DerivedMesh *dm = CDDM_from_mesh(me); - triangles = MEM_mallocN(sizeof(TriTessFace) * (me->totface * 2), "MVerts Mesh"); - mesh_calc_tri_tessface(triangles, me, true, dm); + triangles = mesh_calc_tri_tessface(me, true, dm); BLI_assert(num_pixels >= 3); diff --git a/source/blender/render/intern/source/convertblender.c b/source/blender/render/intern/source/convertblender.c index ee28c3b286f..0adcc16514e 100644 --- a/source/blender/render/intern/source/convertblender.c +++ b/source/blender/render/intern/source/convertblender.c @@ -4658,7 +4658,7 @@ static void add_render_object(Render *re, Object *ob, Object *par, DupliObject * /* only add instance for objects that have not been used for dupli */ if (!(ob->transflag & OB_RENDER_DUPLI)) { - obi= RE_addRenderInstance(re, obr, ob, par, index, 0, NULL, ob->lay); + obi = RE_addRenderInstance(re, obr, ob, par, index, 0, NULL, ob->lay, dob); if (dob) set_dupli_tex_mat(re, obi, dob, omat); } else @@ -4692,7 +4692,7 @@ static void add_render_object(Render *re, Object *ob, Object *par, DupliObject * /* only add instance for objects that have not been used for dupli */ if (!(ob->transflag & OB_RENDER_DUPLI)) { - obi= RE_addRenderInstance(re, obr, ob, par, index, psysindex, NULL, ob->lay); + obi = RE_addRenderInstance(re, obr, ob, par, index, psysindex, NULL, ob->lay, dob); if (dob) set_dupli_tex_mat(re, obi, dob, omat); } else @@ -5053,7 +5053,7 @@ static void database_init_objects(Render *re, unsigned int renderlay, int nolamp if (dob->type != OB_DUPLIGROUP || (obr=find_dupligroup_dupli(re, obd, 0))) { mul_m4_m4m4(mat, re->viewmat, dob->mat); /* ob = particle system, use that layer */ - obi= RE_addRenderInstance(re, NULL, obd, ob, dob->persistent_id[0], 0, mat, ob->lay); + obi = RE_addRenderInstance(re, NULL, obd, ob, dob->persistent_id[0], 0, mat, ob->lay, dob); /* fill in instance variables for texturing */ set_dupli_tex_mat(re, obi, dob, dob_extra->obmat); @@ -5080,7 +5080,7 @@ static void database_init_objects(Render *re, unsigned int renderlay, int nolamp if (dob->type != OB_DUPLIGROUP || (obr=find_dupligroup_dupli(re, obd, psysindex))) { if (obi == NULL) mul_m4_m4m4(mat, re->viewmat, dob->mat); - obi= RE_addRenderInstance(re, NULL, obd, ob, dob->persistent_id[0], psysindex++, mat, obd->lay); + obi = RE_addRenderInstance(re, NULL, obd, ob, dob->persistent_id[0], psysindex++, mat, obd->lay, dob); set_dupli_tex_mat(re, obi, dob, dob_extra->obmat); if (dob->type != OB_DUPLIGROUP) { diff --git a/source/blender/render/intern/source/envmap.c b/source/blender/render/intern/source/envmap.c index b9b908f550b..d70cc4b1ee0 100644 --- a/source/blender/render/intern/source/envmap.c +++ b/source/blender/render/intern/source/envmap.c @@ -262,7 +262,6 @@ static void env_set_imats(Render *re) void env_rotate_scene(Render *re, float mat[4][4], int do_rotate) { - GroupObject *go; ObjectRen *obr; ObjectInstanceRen *obi; LampRen *lar = NULL; @@ -321,19 +320,18 @@ void env_rotate_scene(Render *re, float mat[4][4], int do_rotate) invert_m4(obr->ob->imat_ren); } - for (go = re->lights.first; go; go = go->next) { - lar = go->lampren; - + for (lar = re->lampren.first; lar; lar = lar->next) { + float lamp_imat[4][4]; + /* copy from add_render_lamp */ if (do_rotate == 1) mul_m4_m4m4(tmpmat, re->viewmat, lar->lampmat); else mul_m4_m4m4(tmpmat, re->viewmat_orig, lar->lampmat); - invert_m4_m4(go->ob->imat, tmpmat); - + + invert_m4_m4(lamp_imat, tmpmat); copy_m3_m4(lar->mat, tmpmat); - - copy_m3_m4(lar->imat, go->ob->imat); + copy_m3_m4(lar->imat, lamp_imat); lar->vec[0]= -tmpmat[2][0]; lar->vec[1]= -tmpmat[2][1]; diff --git a/source/blender/render/intern/source/external_engine.c b/source/blender/render/intern/source/external_engine.c index fef453efce2..8adac7c7770 100644 --- a/source/blender/render/intern/source/external_engine.c +++ b/source/blender/render/intern/source/external_engine.c @@ -361,10 +361,12 @@ void RE_engine_set_error_message(RenderEngine *engine, const char *msg) Render *re = engine->re; if (re != NULL) { RenderResult *rr = RE_AcquireResultRead(re); - if (rr->error != NULL) { - MEM_freeN(rr->error); + if (rr) { + if (rr->error != NULL) { + MEM_freeN(rr->error); + } + rr->error = BLI_strdup(msg); } - rr->error = BLI_strdup(msg); RE_ReleaseResult(re); } } diff --git a/source/blender/render/intern/source/multires_bake.c b/source/blender/render/intern/source/multires_bake.c index 5fbd980e387..dcc33b99742 100644 --- a/source/blender/render/intern/source/multires_bake.c +++ b/source/blender/render/intern/source/multires_bake.c @@ -612,7 +612,7 @@ static void get_ccgdm_data(DerivedMesh *lodm, DerivedMesh *hidm, int col = cell_index % polys_per_grid_side; /* S is the vertex whose grid we are examining */ - S = loc_cage_poly_offs / (polys_per_grid_side * polys_per_grid_side); + S = poly_index / (1 << (2 * (lvl - 1))) - grid_offset[cage_face_index]; /* get offset of grid data for original cage face */ g_index = grid_offset[cage_face_index]; @@ -1179,20 +1179,20 @@ static void apply_ao_callback(DerivedMesh *lores_dm, DerivedMesh *hires_dm, void static void count_images(MultiresBakeRender *bkr) { - int a, totface; + int a, totpoly; DerivedMesh *dm = bkr->lores_dm; - MTFace *mtface = CustomData_get_layer(&dm->faceData, CD_MTFACE); + MTexPoly *mtexpoly = CustomData_get_layer(&dm->polyData, CD_MTEXPOLY); BLI_listbase_clear(&bkr->image); bkr->tot_image = 0; - totface = dm->getNumTessFaces(dm); + totpoly = dm->getNumPolys(dm); - for (a = 0; a < totface; a++) - mtface[a].tpage->id.flag &= ~LIB_DOIT; + for (a = 0; a < totpoly; a++) + mtexpoly[a].tpage->id.flag &= ~LIB_DOIT; - for (a = 0; a < totface; a++) { - Image *ima = mtface[a].tpage; + for (a = 0; a < totpoly; a++) { + Image *ima = mtexpoly[a].tpage; if ((ima->id.flag & LIB_DOIT) == 0) { LinkData *data = BLI_genericNodeN(ima); BLI_addtail(&bkr->image, data); @@ -1201,8 +1201,8 @@ static void count_images(MultiresBakeRender *bkr) } } - for (a = 0; a < totface; a++) - mtface[a].tpage->id.flag &= ~LIB_DOIT; + for (a = 0; a < totpoly; a++) + mtexpoly[a].tpage->id.flag &= ~LIB_DOIT; } static void bake_images(MultiresBakeRender *bkr, MultiresBakeResult *result) diff --git a/source/blender/render/intern/source/pipeline.c b/source/blender/render/intern/source/pipeline.c index 96039b7116c..d6ba97533b5 100644 --- a/source/blender/render/intern/source/pipeline.c +++ b/source/blender/render/intern/source/pipeline.c @@ -533,6 +533,17 @@ void RE_FreeAllRender(void) #endif } +void RE_FreeAllPersistentData(void) +{ + Render *re; + for (re = RenderGlobal.renderlist.first; re != NULL; re = re->next) { + if ((re->r.mode & R_PERSISTENT_DATA) != 0 && re->engine != NULL) { + RE_engine_free(re->engine); + re->engine = NULL; + } + } +} + /* on file load, free all re */ void RE_FreeAllRenderResults(void) { @@ -1270,8 +1281,11 @@ static void main_render_result_new(Render *re) BLI_rw_mutex_unlock(&re->resultmutex); - if (re->result->do_exr_tile) - render_result_exr_file_begin(re); + if (re->result) { + if (re->result->do_exr_tile) { + render_result_exr_file_begin(re); + } + } } static void threaded_tile_processor(Render *re) @@ -3154,11 +3168,17 @@ void RE_RenderFreestyleStrokes(Render *re, Main *bmain, Scene *scene, int render void RE_RenderFreestyleExternal(Render *re) { if (!re->test_break(re->tbh)) { - RE_Database_FromScene(re, re->main, re->scene, re->lay, 1); - RE_Database_Preprocess(re); + RenderView *rv; + init_freestyle(re); - add_freestyle(re, 1); - RE_Database_Free(re); + + for (rv = re->result->views.first; rv; rv = rv->next) { + RE_SetActiveRenderView(re, rv->name); + RE_Database_FromScene(re, re->main, re->scene, re->lay, 1); + RE_Database_Preprocess(re); + add_freestyle(re, 1); + RE_Database_Free(re); + } } } #endif @@ -3503,6 +3523,11 @@ void RE_BlenderAnim(Render *re, Main *bmain, Scene *scene, Object *camera_overri get_videos_dimensions(re, &rd, &width, &height); mh = BKE_movie_handle_get(scene->r.im_format.imtype); + if (mh == NULL) { + BKE_report(re->reports, RPT_ERROR, "Movie format unsupported"); + return; + } + re->movie_ctx_arr = MEM_mallocN(sizeof(void *) * totvideos, "Movies' Context"); for (i = 0; i < totvideos; i++) { diff --git a/source/blender/render/intern/source/pointdensity.c b/source/blender/render/intern/source/pointdensity.c index b8d8cc37ae3..9b58bde730a 100644 --- a/source/blender/render/intern/source/pointdensity.c +++ b/source/blender/render/intern/source/pointdensity.c @@ -121,7 +121,8 @@ static void pointdensity_cache_psys(Scene *scene, ParticleSystem *psys, float viewmat[4][4], float winmat[4][4], - int winx, int winy) + int winx, int winy, + const bool use_render_params) { DerivedMesh *dm; ParticleKey state; @@ -140,9 +141,20 @@ static void pointdensity_cache_psys(Scene *scene, } /* Just to create a valid rendering context for particles */ - psys_render_set(ob, psys, viewmat, winmat, winx, winy, 0); + if (use_render_params) { + psys_render_set(ob, psys, viewmat, winmat, winx, winy, 0); + } - dm = mesh_create_derived_render(scene, ob, CD_MASK_BAREMESH | CD_MASK_MTFACE | CD_MASK_MCOL); + if (use_render_params) { + dm = mesh_create_derived_render(scene, + ob, + CD_MASK_BAREMESH | CD_MASK_MTFACE | CD_MASK_MCOL); + } + else { + dm = mesh_get_derived_final(scene, + ob, + CD_MASK_BAREMESH | CD_MASK_MTFACE | CD_MASK_MCOL); + } if ( !psys_check_enabled(ob, psys)) { psys_render_restore(ob, psys); @@ -240,17 +252,32 @@ static void pointdensity_cache_psys(Scene *scene, psys->lattice_deform_data = NULL; } - psys_render_restore(ob, psys); + if (use_render_params) { + psys_render_restore(ob, psys); + } } -static void pointdensity_cache_object(Scene *scene, PointDensity *pd, Object *ob) +static void pointdensity_cache_object(Scene *scene, + PointDensity *pd, + Object *ob, + const bool use_render_params) { int i; DerivedMesh *dm; MVert *mvert = NULL; - dm = mesh_create_derived_render(scene, ob, CD_MASK_BAREMESH | CD_MASK_MTFACE | CD_MASK_MCOL); + if (use_render_params) { + dm = mesh_create_derived_render(scene, + ob, + CD_MASK_BAREMESH | CD_MASK_MTFACE | CD_MASK_MCOL); + } + else { + dm = mesh_get_derived_final(scene, + ob, + CD_MASK_BAREMESH | CD_MASK_MTFACE | CD_MASK_MCOL); + + } mvert = dm->getVertArray(dm); /* local object space */ pd->totpoints = dm->getNumVerts(dm); @@ -290,7 +317,8 @@ static void cache_pointdensity_ex(Scene *scene, PointDensity *pd, float viewmat[4][4], float winmat[4][4], - int winx, int winy) + int winx, int winy, + const bool use_render_params) { if (pd == NULL) { return; @@ -314,18 +342,28 @@ static void cache_pointdensity_ex(Scene *scene, return; } - pointdensity_cache_psys(scene, pd, ob, psys, viewmat, winmat, winx, winy); + pointdensity_cache_psys(scene, + pd, + ob, + psys, + viewmat, winmat, + winx, winy, + use_render_params); } else if (pd->source == TEX_PD_OBJECT) { Object *ob = pd->object; if (ob && ob->type == OB_MESH) - pointdensity_cache_object(scene, pd, ob); + pointdensity_cache_object(scene, pd, ob, use_render_params); } } void cache_pointdensity(Render *re, PointDensity *pd) { - cache_pointdensity_ex(re->scene, pd, re->viewmat, re->winmat, re->winx, re->winy); + cache_pointdensity_ex(re->scene, + pd, + re->viewmat, re->winmat, + re->winx, re->winy, + true); } void free_pointdensity(PointDensity *pd) @@ -597,6 +635,9 @@ int pointdensitytex(Tex *tex, const float texvec[3], TexResult *texres) BRICONT; + if (pd->color_source == TEX_PD_COLOR_CONSTANT) + return retval; + retval |= pointdensity_color(pd, texres, age, vec); BRICONTRGB; @@ -614,33 +655,71 @@ static void sample_dummy_point_density(int resolution, float *values) memset(values, 0, sizeof(float) * 4 * resolution * resolution * resolution); } -static void particle_system_minmax(Object *object, +static void particle_system_minmax(Scene *scene, + Object *object, ParticleSystem *psys, float radius, + const bool use_render_params, float min[3], float max[3]) { + const float size[3] = {radius, radius, radius}; + const float cfra = BKE_scene_frame_get(scene); ParticleSettings *part = psys->part; - float imat[4][4]; - float size[3] = {radius, radius, radius}; - PARTICLE_P; + ParticleSimulationData sim = {NULL}; + ParticleData *pa = NULL; + int i; + int total_particles; + float mat[4][4], imat[4][4]; + INIT_MINMAX(min, max); if (part->type == PART_HAIR) { /* TOOD(sergey): Not supported currently. */ return; } + + unit_m4(mat); + if (use_render_params) { + psys_render_set(object, psys, mat, mat, 1, 1, 0); + } + + sim.scene = scene; + sim.ob = object; + sim.psys = psys; + sim.psmd = psys_get_modifier(object, psys); + invert_m4_m4(imat, object->obmat); - LOOP_PARTICLES { + total_particles = psys->totpart + psys->totchild; + psys->lattice_deform_data = psys_create_lattice_deform_data(&sim); + + for (i = 0, pa = psys->particles; i < total_particles; i++, pa++) { float co_object[3], co_min[3], co_max[3]; - mul_v3_m4v3(co_object, imat, pa->state.co); + ParticleKey state; + state.time = cfra; + if (!psys_get_particle_state(&sim, i, &state, 0)) { + continue; + } + mul_v3_m4v3(co_object, imat, state.co); sub_v3_v3v3(co_min, co_object, size); add_v3_v3v3(co_max, co_object, size); minmax_v3v3_v3(min, max, co_min); minmax_v3v3_v3(min, max, co_max); } + + if (psys->lattice_deform_data) { + end_latt_deform(psys->lattice_deform_data); + psys->lattice_deform_data = NULL; + } + + if (use_render_params) { + psys_render_restore(object, psys); + } } -void RE_sample_point_density(Scene *scene, PointDensity *pd, - int resolution, float *values) +void RE_sample_point_density(Scene *scene, + PointDensity *pd, + const int resolution, + const bool use_render_params, + float *values) { const size_t resolution2 = resolution * resolution; Object *object = pd->object; @@ -663,7 +742,12 @@ void RE_sample_point_density(Scene *scene, PointDensity *pd, sample_dummy_point_density(resolution, values); return; } - particle_system_minmax(object, psys, pd->radius, min, max); + particle_system_minmax(scene, + object, + psys, + pd->radius, + use_render_params, + min, max); } else { float radius[3] = {pd->radius, pd->radius, pd->radius}; @@ -686,7 +770,7 @@ void RE_sample_point_density(Scene *scene, PointDensity *pd, unit_m4(mat); BLI_mutex_lock(&sample_mutex); - cache_pointdensity_ex(scene, pd, mat, mat, 1, 1); + cache_pointdensity_ex(scene, pd, mat, mat, 1, 1, use_render_params); for (z = 0; z < resolution; ++z) { for (y = 0; y < resolution; ++y) { for (x = 0; x < resolution; ++x) { diff --git a/source/blender/render/intern/source/rayshade.c b/source/blender/render/intern/source/rayshade.c index 70a8fdf3ba3..900312ee984 100644 --- a/source/blender/render/intern/source/rayshade.c +++ b/source/blender/render/intern/source/rayshade.c @@ -736,6 +736,7 @@ static void traceray(ShadeInput *origshi, ShadeResult *origshr, short depth, con //shi.sample= 0; // memset above, so don't need this shi.xs= origshi->xs; shi.ys= origshi->ys; + shi.do_manage= origshi->do_manage; shi.lay= origshi->lay; shi.passflag= SCE_PASS_COMBINED; /* result of tracing needs no pass info */ shi.combinedflag= 0xFFFFFF; /* ray trace does all options */ @@ -1622,6 +1623,7 @@ static void ray_trace_shadow_tra(Isect *is, ShadeInput *origshi, int depth, int shi.xs= origshi->xs; shi.ys= origshi->ys; + shi.do_manage= origshi->do_manage; shi.lay= origshi->lay; shi.nodes= origshi->nodes; diff --git a/source/blender/render/intern/source/rendercore.c b/source/blender/render/intern/source/rendercore.c index 894ade42a1f..910ea16607e 100644 --- a/source/blender/render/intern/source/rendercore.c +++ b/source/blender/render/intern/source/rendercore.c @@ -1971,9 +1971,9 @@ void add_halo_flare(Render *re) rect = RE_RenderLayerGetPass(rl, SCE_PASS_COMBINED, re->viewname); - if (rl==NULL || rect) - return; - + if (rect==NULL) + continue; + mode= R.r.mode; R.r.mode &= ~R_PANORAMA; diff --git a/source/blender/render/intern/source/renderdatabase.c b/source/blender/render/intern/source/renderdatabase.c index d271592af5f..5f78c8a52db 100644 --- a/source/blender/render/intern/source/renderdatabase.c +++ b/source/blender/render/intern/source/renderdatabase.c @@ -1363,7 +1363,9 @@ void project_renderdata(Render *re, /* ------------------------------------------------------------------------- */ -ObjectInstanceRen *RE_addRenderInstance(Render *re, ObjectRen *obr, Object *ob, Object *par, int index, int psysindex, float mat[4][4], int lay) +ObjectInstanceRen *RE_addRenderInstance( + Render *re, ObjectRen *obr, Object *ob, Object *par, + int index, int psysindex, float mat[4][4], int lay, const DupliObject *dob) { ObjectInstanceRen *obi; float mat3[3][3]; @@ -1377,33 +1379,30 @@ ObjectInstanceRen *RE_addRenderInstance(Render *re, ObjectRen *obr, Object *ob, obi->lay= lay; /* Fill particle info */ - if (obi->psysindex >= 0) { - int psysindex = 0; - int index; - ParticleSystem *psys; - if (obi->par) { - for (psys = obi->par->particlesystem.first; psys; psys = psys->next) { - if (psysindex == obi->psysindex) - break; - ++psysindex; + if (par && dob) { + const ParticleSystem *psys = dob->particle_system; + if (psys) { + int index; + if (obi->index < psys->totpart) { + index = obi->index; } - if (psys) { - if (obi->index < psys->totpart) - index = obi->index; - else { - index = psys->child[obi->index - psys->totpart].parent; - } - if (index >= 0) { - ParticleData* p = &psys->particles[index]; - obi->part_index = index; - obi->part_size = p->size; - obi->part_age = RE_GetStats(re)->cfra - p->time; - obi->part_lifetime = p->lifetime; - - copy_v3_v3(obi->part_co, p->state.co); - copy_v3_v3(obi->part_vel, p->state.vel); - copy_v3_v3(obi->part_avel, p->state.ave); - } + else if (psys->child) { + index = psys->child[obi->index - psys->totpart].parent; + } + else { + index = -1; + } + + if (index >= 0) { + const ParticleData *p = &psys->particles[index]; + obi->part_index = index; + obi->part_size = p->size; + obi->part_age = RE_GetStats(re)->cfra - p->time; + obi->part_lifetime = p->lifetime; + + copy_v3_v3(obi->part_co, p->state.co); + copy_v3_v3(obi->part_vel, p->state.vel); + copy_v3_v3(obi->part_avel, p->state.ave); } } } diff --git a/source/blender/render/intern/source/shadeoutput.c b/source/blender/render/intern/source/shadeoutput.c index 39dfa48d3f1..91f9723897c 100644 --- a/source/blender/render/intern/source/shadeoutput.c +++ b/source/blender/render/intern/source/shadeoutput.c @@ -1815,7 +1815,7 @@ void shade_lamp_loop(ShadeInput *shi, ShadeResult *shr) shr->combined[1]= shi->g; shr->combined[2]= shi->b; shr->alpha= shi->alpha; - return; + goto finally_shadeless; } if ( (ma->mode & (MA_VERTEXCOL|MA_VERTEXCOLP))== MA_VERTEXCOL ) { /* vertexcolor light */ @@ -2006,7 +2006,11 @@ void shade_lamp_loop(ShadeInput *shi, ShadeResult *shr) add_v3_v3(shr->combined, shr->emit); if (shi->combinedflag & SCE_PASS_SPEC) add_v3_v3(shr->combined, shr->spec); - + + + /* Last section of this function applies to shadeless colors too */ +finally_shadeless: + /* modulate by the object color */ if ((ma->shade_flag & MA_OBCOLOR) && shi->obr->ob) { if (!(ma->sss_flag & MA_DIFF_SSS) || !sss_pass_done(&R, ma)) { diff --git a/source/blender/windowmanager/WM_api.h b/source/blender/windowmanager/WM_api.h index 2164d457426..f0dbc4d4108 100644 --- a/source/blender/windowmanager/WM_api.h +++ b/source/blender/windowmanager/WM_api.h @@ -95,18 +95,19 @@ void WM_init_splash (struct bContext *C); void WM_check (struct bContext *C); -struct wmWindow *WM_window_open (struct bContext *C, const struct rcti *rect); - int WM_window_pixels_x (struct wmWindow *win); int WM_window_pixels_y (struct wmWindow *win); bool WM_window_is_fullscreen (struct wmWindow *win); /* defines for 'type' WM_window_open_temp */ -#define WM_WINDOW_RENDER 0 -#define WM_WINDOW_USERPREFS 1 -// #define WM_WINDOW_FILESEL 2 // UNUSED +enum { + WM_WINDOW_RENDER = 1, + WM_WINDOW_USERPREFS, + // WM_WINDOW_FILESEL // UNUSED +}; -void WM_window_open_temp (struct bContext *C, struct rcti *position, int type); +struct wmWindow *WM_window_open(struct bContext *C, const struct rcti *rect); +struct wmWindow *WM_window_open_temp(struct bContext *C, const struct rcti *rect_init, int type); /* returns true if draw method is triple buffer */ bool WM_is_draw_triple(struct wmWindow *win); @@ -138,6 +139,7 @@ void WM_paint_cursor_end(struct wmWindowManager *wm, void *handle); void WM_paint_cursor_tag_redraw(struct wmWindow *win, struct ARegion *ar); void WM_cursor_warp (struct wmWindow *win, int x, int y); +void WM_cursor_compatible_xy(wmWindow *win, int *x, int *y); float WM_cursor_pressure (const struct wmWindow *win); /* event map */ @@ -296,6 +298,7 @@ void WM_operator_properties_gesture_straightline(struct wmOperatorType *ot, int void WM_operator_properties_select_all(struct wmOperatorType *ot); void WM_operator_properties_select_action(struct wmOperatorType *ot, int default_action); void WM_operator_properties_select_action_simple(struct wmOperatorType *ot, int default_action); +void WM_operator_properties_select_random(struct wmOperatorType *ot); bool WM_operator_check_ui_enabled(const struct bContext *C, const char *idname); wmOperator *WM_operator_last_redo(const struct bContext *C); diff --git a/source/blender/windowmanager/intern/wm.c b/source/blender/windowmanager/intern/wm.c index b43425ef6cb..fd46d9bd1d0 100644 --- a/source/blender/windowmanager/intern/wm.c +++ b/source/blender/windowmanager/intern/wm.c @@ -376,7 +376,7 @@ void WM_check(bContext *C) } /* case: no open windows at all, for old file reads */ - wm_window_add_ghostwindows(wm); + wm_window_ghostwindows_ensure(wm); } /* case: fileread */ @@ -467,11 +467,13 @@ void wm_close_and_free(bContext *C, wmWindowManager *wm) void wm_close_and_free_all(bContext *C, ListBase *wmlist) { + Main *bmain = CTX_data_main(C); wmWindowManager *wm; while ((wm = wmlist->first)) { wm_close_and_free(C, wm); BLI_remlink(wmlist, wm); + BKE_libblock_free_data(bmain, &wm->id); MEM_freeN(wm); } } diff --git a/source/blender/windowmanager/intern/wm_cursors.c b/source/blender/windowmanager/intern/wm_cursors.c index d84b65847ca..d9466cbd035 100644 --- a/source/blender/windowmanager/intern/wm_cursors.c +++ b/source/blender/windowmanager/intern/wm_cursors.c @@ -199,14 +199,10 @@ void WM_cursor_grab_enable(wmWindow *win, bool wrap, bool hide, int bounds[4]) * It helps not to get a stuck WM when hitting a breakpoint * */ GHOST_TGrabCursorMode mode = GHOST_kGrabNormal; - float fac = GHOST_GetNativePixelSize(win->ghostwin); - /* in case pixel coords differ from window/mouse coords */ if (bounds) { - bounds[0] /= fac; - bounds[1] /= fac; - bounds[2] /= fac; - bounds[3] /= fac; + wm_cursor_position_to_ghost(win, &bounds[0], &bounds[1]); + wm_cursor_position_to_ghost(win, &bounds[2], &bounds[3]); } if (hide) { @@ -234,7 +230,15 @@ void WM_cursor_grab_disable(wmWindow *win, const int mouse_ungrab_xy[2]) { if ((G.debug & G_DEBUG) == 0) { if (win && win->ghostwin) { - GHOST_SetCursorGrab(win->ghostwin, GHOST_kGrabDisable, NULL, mouse_ungrab_xy); + if (mouse_ungrab_xy) { + int mouse_xy[2] = {mouse_ungrab_xy[0], mouse_ungrab_xy[1]}; + wm_cursor_position_to_ghost(win, &mouse_xy[0], &mouse_xy[1]); + GHOST_SetCursorGrab(win->ghostwin, GHOST_kGrabDisable, NULL, mouse_xy); + } + else { + GHOST_SetCursorGrab(win->ghostwin, GHOST_kGrabDisable, NULL, NULL); + } + win->grabcursor = GHOST_kGrabDisable; } } diff --git a/source/blender/windowmanager/intern/wm_event_system.c b/source/blender/windowmanager/intern/wm_event_system.c index 5a78dcf2361..2a9de6f5029 100644 --- a/source/blender/windowmanager/intern/wm_event_system.c +++ b/source/blender/windowmanager/intern/wm_event_system.c @@ -1801,7 +1801,13 @@ static int wm_handler_fileselect_do(bContext *C, ListBase *handlers, wmEventHand const SpaceLink *sl = sa->spacedata.first; const bool was_prev_temp = (sl->next && sl->next->spacetype == SPACE_IMAGE); - ED_screen_full_prevspace(C, sa, was_prev_temp); + if (sa->full) { + ED_screen_full_prevspace(C, sa, was_prev_temp); + } + /* user may have left fullscreen */ + else { + ED_area_prevspace(C, sa); + } } wm_handler_op_context(C, handler, CTX_wm_window(C)->eventstate); diff --git a/source/blender/windowmanager/intern/wm_files.c b/source/blender/windowmanager/intern/wm_files.c index a4f69b24351..8288b2ed1ef 100644 --- a/source/blender/windowmanager/intern/wm_files.c +++ b/source/blender/windowmanager/intern/wm_files.c @@ -76,10 +76,12 @@ #include "BKE_context.h" #include "BKE_depsgraph.h" #include "BKE_global.h" +#include "BKE_library.h" #include "BKE_main.h" #include "BKE_packedFile.h" #include "BKE_report.h" #include "BKE_sound.h" +#include "BKE_scene.h" #include "BKE_screen.h" #include "BLO_readfile.h" @@ -105,6 +107,9 @@ #include "GPU_draw.h" +/* only to report a missing engine */ +#include "RE_engine.h" + #ifdef WITH_PYTHON #include "BPY_extern.h" #endif @@ -334,11 +339,13 @@ static void wm_init_userdef(bContext *C, const bool from_memory) #define BKE_READ_EXOTIC_FAIL_FORMAT -2 /* file format is not supported */ #define BKE_READ_EXOTIC_FAIL_OPEN -1 /* Can't open the file */ #define BKE_READ_EXOTIC_OK_BLEND 0 /* .blend file */ +#if 0 #define BKE_READ_EXOTIC_OK_OTHER 1 /* other supported formats */ +#endif /* intended to check for non-blender formats but for now it only reads blends */ -static int wm_read_exotic(Scene *UNUSED(scene), const char *name) +static int wm_read_exotic(const char *name) { int len; gzFile gzfile; @@ -400,6 +407,104 @@ void WM_file_autoexec_init(const char *filepath) } } +void wm_file_read_report(bContext *C) +{ + ReportList *reports = NULL; + Scene *sce; + + for (sce = G.main->scene.first; sce; sce = sce->id.next) { + if (sce->r.engine[0] && + BLI_findstring(&R_engines, sce->r.engine, offsetof(RenderEngineType, idname)) == NULL) + { + if (reports == NULL) { + reports = CTX_wm_reports(C); + } + + BKE_reportf(reports, RPT_ERROR, + "Engine '%s' not available for scene '%s' " + "(an addon may need to be installed or enabled)", + sce->r.engine, sce->id.name + 2); + } + } + + if (reports) { + if (!G.background) { + WM_report_banner_show(C); + } + } +} + +/** + * Logic shared between #WM_file_read & #wm_homefile_read, + * updates to make after reading a file. + */ +static void wm_file_read_post(bContext *C, bool is_startup_file) +{ + bool addons_loaded = false; + wmWindowManager *wm = CTX_wm_manager(C); + + if (!G.background) { + /* remove windows which failed to be added via WM_check */ + wm_window_ghostwindows_remove_invalid(C, wm); + } + + CTX_wm_window_set(C, wm->windows.first); + + ED_editors_init(C); + DAG_on_visible_update(CTX_data_main(C), true); + +#ifdef WITH_PYTHON + if (is_startup_file) { + /* possible python hasn't been initialized */ + if (CTX_py_init_get(C)) { + /* sync addons, these may have changed from the defaults */ + BPY_string_exec(C, "__import__('addon_utils').reset_all()"); + + BPY_python_reset(C); + addons_loaded = true; + } + } + else { + /* run any texts that were loaded in and flagged as modules */ + BPY_python_reset(C); + addons_loaded = true; + } +#endif /* WITH_PYTHON */ + + WM_operatortype_last_properties_clear_all(); + + /* important to do before NULL'ing the context */ + BLI_callback_exec(CTX_data_main(C), NULL, BLI_CB_EVT_VERSION_UPDATE); + BLI_callback_exec(CTX_data_main(C), NULL, BLI_CB_EVT_LOAD_POST); + + /* would otherwise be handled by event loop */ + if (G.background) { + Main *bmain = CTX_data_main(C); + BKE_scene_update_tagged(bmain->eval_ctx, bmain, CTX_data_scene(C)); + } + + WM_event_add_notifier(C, NC_WM | ND_FILEREAD, NULL); + + /* report any errors. + * currently disabled if addons aren't yet loaded */ + if (addons_loaded) { + wm_file_read_report(C); + } + + if (!G.background) { + /* in background mode this makes it hard to load + * a blend file and do anything since the screen + * won't be set to a valid value again */ + CTX_wm_window_set(C, NULL); /* exits queues */ + } + + if (!G.background) { +// undo_editmode_clear(); + BKE_undo_reset(); + BKE_undo_write(C, "original"); /* save current state */ + } +} + bool WM_file_read(bContext *C, const char *filepath, ReportList *reports) { /* assume automated tasks with background, don't write recent file list */ @@ -419,7 +524,7 @@ bool WM_file_read(bContext *C, const char *filepath, ReportList *reports) /* first try to append data from exotic file formats... */ /* it throws error box when file doesn't exist and returns -1 */ /* note; it should set some error message somewhere... (ton) */ - retval = wm_read_exotic(CTX_data_scene(C), filepath); + retval = wm_read_exotic(filepath); /* we didn't succeed, now try to read Blender file */ if (retval == BKE_READ_EXOTIC_OK_BLEND) { @@ -464,58 +569,14 @@ bool WM_file_read(bContext *C, const char *filepath, ReportList *reports) } } - - WM_event_add_notifier(C, NC_WM | ND_FILEREAD, NULL); -// refresh_interface_font(); - - CTX_wm_window_set(C, CTX_wm_manager(C)->windows.first); - - ED_editors_init(C); - DAG_on_visible_update(CTX_data_main(C), true); - -#ifdef WITH_PYTHON - /* run any texts that were loaded in and flagged as modules */ - BPY_python_reset(C); -#endif - - WM_operatortype_last_properties_clear_all(); - - /* important to do before NULL'ing the context */ - BLI_callback_exec(CTX_data_main(C), NULL, BLI_CB_EVT_VERSION_UPDATE); - BLI_callback_exec(CTX_data_main(C), NULL, BLI_CB_EVT_LOAD_POST); - - if (!G.background) { - /* in background mode this makes it hard to load - * a blend file and do anything since the screen - * won't be set to a valid value again */ - CTX_wm_window_set(C, NULL); /* exits queues */ - } - -#if 0 - /* gives popups on windows but not linux, bug in report API - * but disable for now to stop users getting annoyed */ - /* TODO, make this show in header info window */ - { - Scene *sce; - for (sce = G.main->scene.first; sce; sce = sce->id.next) { - if (sce->r.engine[0] && - BLI_findstring(&R_engines, sce->r.engine, offsetof(RenderEngineType, idname)) == NULL) - { - BKE_reportf(reports, RPT_ERROR, "Engine '%s' not available for scene '%s' " - "(an addon may need to be installed or enabled)", - sce->r.engine, sce->id.name + 2); - } - } - } -#endif - - BKE_undo_reset(); - BKE_undo_write(C, "original"); /* save current state */ + wm_file_read_post(C, false); success = true; } +#if 0 else if (retval == BKE_READ_EXOTIC_OK_OTHER) BKE_undo_write(C, "Import file"); +#endif else if (retval == BKE_READ_EXOTIC_FAIL_OPEN) { BKE_reportf(reports, RPT_ERROR, "Cannot read file '%s': %s", filepath, errno ? strerror(errno) : TIP_("unable to open the file")); @@ -672,36 +733,7 @@ int wm_homefile_read(bContext *C, ReportList *reports, bool from_memory, const c G.save_over = 0; // start with save preference untitled.blend G.fileflags &= ~G_FILE_AUTOPLAY; /* disable autoplay in startup.blend... */ -// refresh_interface_font(); - -// undo_editmode_clear(); - BKE_undo_reset(); - BKE_undo_write(C, "original"); /* save current state */ - - ED_editors_init(C); - DAG_on_visible_update(CTX_data_main(C), true); - -#ifdef WITH_PYTHON - if (CTX_py_init_get(C)) { - /* sync addons, these may have changed from the defaults */ - BPY_string_exec(C, "__import__('addon_utils').reset_all()"); - - BPY_python_reset(C); - } -#endif - - WM_operatortype_last_properties_clear_all(); - - /* important to do before NULL'ing the context */ - BLI_callback_exec(CTX_data_main(C), NULL, BLI_CB_EVT_VERSION_UPDATE); - BLI_callback_exec(CTX_data_main(C), NULL, BLI_CB_EVT_LOAD_POST); - - WM_event_add_notifier(C, NC_WM | ND_FILEREAD, NULL); - - /* in background mode the scene will stay NULL */ - if (!G.background) { - CTX_wm_window_set(C, NULL); /* exits queues */ - } + wm_file_read_post(C, true); return true; } @@ -864,11 +896,11 @@ static void wm_history_file_update(void) /* screen can be NULL */ -static ImBuf *blend_file_thumb(Scene *scene, bScreen *screen, int **thumb_pt) +static ImBuf *blend_file_thumb(Scene *scene, bScreen *screen, BlendThumbnail **thumb_pt) { /* will be scaled down, but gives some nice oversampling */ ImBuf *ibuf; - int *thumb; + BlendThumbnail *thumb; char err_out[256] = "unknown"; /* screen if no camera found */ @@ -876,7 +908,11 @@ static ImBuf *blend_file_thumb(Scene *scene, bScreen *screen, int **thumb_pt) ARegion *ar = NULL; View3D *v3d = NULL; - *thumb_pt = NULL; + /* In case we are given a valid thumbnail data, just generate image from it. */ + if (*thumb_pt) { + thumb = *thumb_pt; + return BKE_main_thumbnail_to_imbuf(NULL, thumb); + } /* scene can be NULL if running a script at startup and calling the save operator */ if (G.background || scene == NULL) @@ -896,13 +932,18 @@ static ImBuf *blend_file_thumb(Scene *scene, bScreen *screen, int **thumb_pt) /* gets scaled to BLEN_THUMB_SIZE */ if (scene->camera) { - ibuf = ED_view3d_draw_offscreen_imbuf_simple(scene, scene->camera, - BLEN_THUMB_SIZE * 2, BLEN_THUMB_SIZE * 2, - IB_rect, OB_SOLID, false, false, false, R_ALPHAPREMUL, NULL, err_out); + ibuf = ED_view3d_draw_offscreen_imbuf_simple( + scene, scene->camera, + BLEN_THUMB_SIZE * 2, BLEN_THUMB_SIZE * 2, + IB_rect, OB_SOLID, false, false, false, R_ALPHAPREMUL, 0, NULL, + NULL, err_out); } else { - ibuf = ED_view3d_draw_offscreen_imbuf(scene, v3d, ar, BLEN_THUMB_SIZE * 2, BLEN_THUMB_SIZE * 2, - IB_rect, false, R_ALPHAPREMUL, NULL, err_out); + ibuf = ED_view3d_draw_offscreen_imbuf( + scene, v3d, ar, + BLEN_THUMB_SIZE * 2, BLEN_THUMB_SIZE * 2, + IB_rect, false, R_ALPHAPREMUL, 0, NULL, + NULL, err_out); } if (ibuf) { @@ -914,13 +955,7 @@ static ImBuf *blend_file_thumb(Scene *scene, bScreen *screen, int **thumb_pt) /* add pretty overlay */ IMB_thumb_overlay_blend(ibuf->rect, ibuf->x, ibuf->y, aspect); - /* first write into thumb buffer */ - thumb = MEM_mallocN(((2 + (BLEN_THUMB_SIZE * BLEN_THUMB_SIZE))) * sizeof(int), "write_file thumb"); - - thumb[0] = BLEN_THUMB_SIZE; - thumb[1] = BLEN_THUMB_SIZE; - - memcpy(thumb + 2, ibuf->rect, BLEN_THUMB_SIZE * BLEN_THUMB_SIZE * sizeof(int)); + thumb = BKE_main_thumbnail_from_imbuf(NULL, ibuf); } else { /* '*thumb_pt' needs to stay NULL to prevent a bad thumbnail from being handled */ @@ -959,25 +994,26 @@ int wm_file_write(bContext *C, const char *filepath, int fileflags, ReportList * { Library *li; int len; - int *thumb = NULL; + int ret = -1; + BlendThumbnail *thumb, *main_thumb; ImBuf *ibuf_thumb = NULL; len = strlen(filepath); if (len == 0) { BKE_report(reports, RPT_ERROR, "Path is empty, cannot save"); - return -1; + return ret; } if (len >= FILE_MAX) { BKE_report(reports, RPT_ERROR, "Path too long, cannot save"); - return -1; + return ret; } /* Check if file write permission is ok */ if (BLI_exists(filepath) && !BLI_file_is_writable(filepath)) { BKE_reportf(reports, RPT_ERROR, "Cannot save blend file, path '%s' is not writable", filepath); - return -1; + return ret; } /* note: used to replace the file extension (to ensure '.blend'), @@ -988,18 +1024,21 @@ int wm_file_write(bContext *C, const char *filepath, int fileflags, ReportList * for (li = G.main->library.first; li; li = li->id.next) { if (BLI_path_cmp(li->filepath, filepath) == 0) { BKE_reportf(reports, RPT_ERROR, "Cannot overwrite used library '%.240s'", filepath); - return -1; + return ret; } } + /* Call pre-save callbacks befores writing preview, that way you can generate custom file thumbnail... */ + BLI_callback_exec(G.main, NULL, BLI_CB_EVT_SAVE_PRE); + /* blend file thumbnail */ /* save before exit_editmode, otherwise derivedmeshes for shared data corrupt #27765) */ + /* Main now can store a .blend thumbnail, usefull for background mode or thumbnail customization. */ + main_thumb = thumb = CTX_data_main(C)->blen_thumb; if ((U.flag & USER_SAVE_PREVIEWS) && BLI_thread_is_main()) { ibuf_thumb = blend_file_thumb(CTX_data_scene(C), CTX_wm_screen(C), &thumb); } - BLI_callback_exec(G.main, NULL, BLI_CB_EVT_SAVE_PRE); - /* operator now handles overwrite checks */ if (G.fileflags & G_AUTOPACK) { @@ -1044,22 +1083,21 @@ int wm_file_write(bContext *C, const char *filepath, int fileflags, ReportList * if (ibuf_thumb) { IMB_thumb_delete(filepath, THB_FAIL); /* without this a failed thumb overrides */ ibuf_thumb = IMB_thumb_create(filepath, THB_LARGE, THB_SOURCE_BLEND, ibuf_thumb); - IMB_freeImBuf(ibuf_thumb); } - if (thumb) MEM_freeN(thumb); + ret = 0; /* Success. */ } - else { - if (ibuf_thumb) IMB_freeImBuf(ibuf_thumb); - if (thumb) MEM_freeN(thumb); - - WM_cursor_wait(0); - return -1; + + if (ibuf_thumb) { + IMB_freeImBuf(ibuf_thumb); + } + if (thumb && thumb != main_thumb) { + MEM_freeN(thumb); } WM_cursor_wait(0); - - return 0; + + return ret; } /** diff --git a/source/blender/windowmanager/intern/wm_init_exit.c b/source/blender/windowmanager/intern/wm_init_exit.c index adf28cb7c8b..a60a2d28acb 100644 --- a/source/blender/windowmanager/intern/wm_init_exit.c +++ b/source/blender/windowmanager/intern/wm_init_exit.c @@ -159,7 +159,9 @@ void WM_init(bContext *C, int argc, const char **argv) BKE_library_callback_free_editor_id_reference_set(WM_main_remove_editor_id_reference); /* library.c */ BKE_blender_callback_test_break_set(wm_window_testbreak); /* blender.c */ BKE_spacedata_callback_id_unref_set(ED_spacedata_id_unref); /* screen.c */ - DAG_editors_update_cb(ED_render_id_flush_update, ED_render_scene_update); /* depsgraph.c */ + DAG_editors_update_cb(ED_render_id_flush_update, + ED_render_scene_update, + ED_render_scene_update_pre); /* depsgraph.c */ ED_spacetypes_init(); /* editors/space_api/spacetype.c */ @@ -174,6 +176,10 @@ void WM_init(bContext *C, int argc, const char **argv) ED_spacedropwidgets_init(); + /* reports cant be initialized before the wm, + * but keep before file reading, since that may report errors */ + wm_init_reports(C); + /* get the default database, plus a wm */ wm_homefile_read(C, NULL, G.factory_startup, NULL); @@ -191,6 +197,10 @@ void WM_init(bContext *C, int argc, const char **argv) GPU_set_anisotropic(U.anisotropic_filter); GPU_set_gpu_mipmapping(U.use_gpu_mipmap); +#ifdef WITH_OPENSUBDIV + openSubdiv_init(); +#endif + UI_init(); } else { @@ -225,8 +235,6 @@ void WM_init(bContext *C, int argc, const char **argv) if (!G.background && !wm_start_with_console) GHOST_toggleConsole(3); - wm_init_reports(C); /* reports cant be initialized before the wm */ - clear_matcopybuf(); ED_render_clear_mtex_copybuf(); @@ -255,13 +263,24 @@ void WM_init(bContext *C, int argc, const char **argv) /* that prevents loading both the kept session, and the file on the command line */ } else { + /* note, logic here is from wm_file_read_post, + * call functions that depend on Python being initialized. */ + /* normally 'wm_homefile_read' will do this, * however python is not initialized when called from this function. * * unlikely any handlers are set but its possible, * note that recovering the last session does its own callbacks. */ + CTX_wm_window_set(C, CTX_wm_manager(C)->windows.first); + BLI_callback_exec(CTX_data_main(C), NULL, BLI_CB_EVT_VERSION_UPDATE); BLI_callback_exec(CTX_data_main(C), NULL, BLI_CB_EVT_LOAD_POST); + + wm_file_read_report(C); + + if (!G.background) { + CTX_wm_window_set(C, NULL); + } } } @@ -500,9 +519,6 @@ void WM_exit_ext(bContext *C, const bool do_python) ED_clipboard_posebuf_free(); BKE_node_clipboard_clear(); - /* widgetmaps after freeing blender, so no deleted data get accessed during cleaning up of areas */ - WM_widgetmaptypes_free(); - BLF_exit(); #ifdef WITH_INTERNATIONAL diff --git a/source/blender/windowmanager/intern/wm_keymap.c b/source/blender/windowmanager/intern/wm_keymap.c index e658396fb16..016583e69a5 100644 --- a/source/blender/windowmanager/intern/wm_keymap.c +++ b/source/blender/windowmanager/intern/wm_keymap.c @@ -586,8 +586,23 @@ static void wm_keymap_patch(wmKeyMap *km, wmKeyMap *diff_km) /* Do not re-add an already existing keymap item! See T42088. */ /* We seek only for exact copy here! See T42137. */ kmi_add = wm_keymap_find_item_equals(km, kmdi->add_item); + + /* If kmi_add is same as kmi_remove (can happen in some cases, typically when we got kmi_remove + * from wm_keymap_find_item_equals_result()), no need to add or remove anything, see T45579. */ + /* Note: This typically happens when we apply user-defined keymap diff to a base one that was exported + * with that customized keymap already. In that case: + * - wm_keymap_find_item_equals(km, kmdi->remove_item) finds nothing (because actual shortcut of + * current base does not match kmdi->remove_item any more). + * - wm_keymap_find_item_equals_result(km, kmdi->remove_item) finds the current kmi from + * base keymap (because it does exactly the same thing). + * - wm_keymap_find_item_equals(km, kmdi->add_item) finds the same kmi, since base keymap was + * exported with that user-defined shortcut already! + * Maybe we should rather keep user-defined keymaps specific to a given base one? */ + if (kmi_add != NULL && kmi_add == kmi_remove) { + kmi_remove = NULL; + } /* only if nothing to remove or item to remove found */ - if (!kmi_add && (!kmdi->remove_item || kmi_remove)) { + else if (!kmi_add && (!kmdi->remove_item || kmi_remove)) { kmi_add = wm_keymap_item_copy(kmdi->add_item); kmi_add->flag |= KMI_USER_MODIFIED; @@ -888,15 +903,21 @@ static void wm_user_modal_keymap_set_items(wmWindowManager *wm, wmKeyMap *km) const char *WM_key_event_string(const short type, const bool compact) { - const char *name = NULL; + EnumPropertyItem *it; + const int i = RNA_enum_from_value(event_type_items, (int)type); + + if (i == -1) { + return ""; + } + it = &event_type_items[i]; + /* We first try enum items' description (abused as shortname here), and fall back to usual name if empty. */ - if ((compact && RNA_enum_description(event_type_items, (int)type, &name) && name[0]) || - RNA_enum_name(event_type_items, (int)type, &name)) - { - return IFACE_(name); + if (compact && it->description[0]) { + /* XXX No context for enum descriptions... In practice shall not be an issue though. */ + return IFACE_(it->description); } - return ""; + return CTX_IFACE_(BLT_I18NCONTEXT_UI_EVENTS, it->name); } /* TODO: also support (some) value, like e.g. double-click? */ diff --git a/source/blender/windowmanager/intern/wm_operators.c b/source/blender/windowmanager/intern/wm_operators.c index 8d37e21da7e..0f0e6c9b771 100644 --- a/source/blender/windowmanager/intern/wm_operators.c +++ b/source/blender/windowmanager/intern/wm_operators.c @@ -59,10 +59,13 @@ #include "PIL_time.h" #include "BLI_blenlib.h" +#include "BLI_bitmap.h" #include "BLI_dial.h" #include "BLI_dynstr.h" /*for WM_operator_pystring */ +#include "BLI_linklist.h" #include "BLI_linklist_stack.h" #include "BLI_math.h" +#include "BLI_memarena.h" #include "BLI_utildefines.h" #include "BLI_ghash.h" @@ -1212,10 +1215,10 @@ void WM_operator_properties_filesel(wmOperatorType *ot, int filter, short type, PropertyRNA *prop; static EnumPropertyItem file_display_items[] = { - {FILE_DEFAULTDISPLAY, "FILE_DEFAULTDISPLAY", 0, "Default", "Automatically determine display type for files"}, - {FILE_SHORTDISPLAY, "FILE_SHORTDISPLAY", ICON_SHORTDISPLAY, "Short List", "Display files as short list"}, - {FILE_LONGDISPLAY, "FILE_LONGDISPLAY", ICON_LONGDISPLAY, "Long List", "Display files as a detailed list"}, - {FILE_IMGDISPLAY, "FILE_IMGDISPLAY", ICON_IMGDISPLAY, "Thumbnails", "Display files as thumbnails"}, + {FILE_DEFAULTDISPLAY, "DEFAULT", 0, "Default", "Automatically determine display type for files"}, + {FILE_SHORTDISPLAY, "LIST_SHORT", ICON_SHORTDISPLAY, "Short List", "Display files as short list"}, + {FILE_LONGDISPLAY, "LIST_LONG", ICON_LONGDISPLAY, "Long List", "Display files as a detailed list"}, + {FILE_IMGDISPLAY, "THUMBNAIL", ICON_IMGDISPLAY, "Thumbnails", "Display files as thumbnails"}, {0, NULL, 0, NULL, NULL} }; @@ -1320,6 +1323,22 @@ void WM_operator_properties_select_action_simple(wmOperatorType *ot, int default wm_operator_properties_select_action_ex(ot, default_action, select_actions); } +/** + * Use for all select random operators. + * Adds properties: percent, seed, action. + */ +void WM_operator_properties_select_random(wmOperatorType *ot) +{ + RNA_def_float_percentage( + ot->srna, "percent", 50.f, 0.0f, 100.0f, + "Percent", "Percentage of objects to select randomly", 0.f, 100.0f); + RNA_def_int( + ot->srna, "seed", 0, 0, INT_MAX, + "Random Seed", "Seed for the random number generator", 0, 255); + + WM_operator_properties_select_action_simple(ot, SEL_SELECT); +} + void WM_operator_properties_select_all(wmOperatorType *ot) { WM_operator_properties_select_action(ot, SEL_TOGGLE); @@ -1539,6 +1558,8 @@ static uiBlock *wm_block_create_redo(bContext *C, ARegion *ar, void *arg_op) if (op->type->flag & OPTYPE_MACRO) { for (op = op->macro.first; op; op = op->next) { uiLayoutOperatorButs(C, layout, op, NULL, 'H', UI_LAYOUT_OP_SHOW_TITLE); + if (op->next) + uiItemS(layout); } } else { @@ -2226,6 +2247,17 @@ static int wm_operator_winactive_normal(bContext *C) return 1; } +/* included for script-access */ +static void WM_OT_window_close(wmOperatorType *ot) +{ + ot->name = "Close Window"; + ot->idname = "WM_OT_window_close"; + ot->description = "Close the current Blender window"; + + ot->exec = wm_window_close_exec; + ot->poll = WM_operator_winactive; +} + static void WM_OT_window_duplicate(wmOperatorType *ot) { ot->name = "Duplicate Window"; @@ -2588,106 +2620,150 @@ static int wm_link_append_invoke(bContext *C, wmOperator *op, const wmEvent *UNU static short wm_link_append_flag(wmOperator *op) { + PropertyRNA *prop; short flag = 0; - if (RNA_boolean_get(op->ptr, "autoselect")) flag |= FILE_AUTOSELECT; - if (RNA_boolean_get(op->ptr, "active_layer")) flag |= FILE_ACTIVELAY; - if (RNA_struct_find_property(op->ptr, "relative_path") && RNA_boolean_get(op->ptr, "relative_path")) flag |= FILE_RELPATH; - if (RNA_boolean_get(op->ptr, "link")) flag |= FILE_LINK; - if (RNA_boolean_get(op->ptr, "instance_groups")) flag |= FILE_GROUP_INSTANCE; + if (RNA_boolean_get(op->ptr, "autoselect")) + flag |= FILE_AUTOSELECT; + if (RNA_boolean_get(op->ptr, "active_layer")) + flag |= FILE_ACTIVELAY; + if ((prop = RNA_struct_find_property(op->ptr, "relative_path")) && RNA_property_boolean_get(op->ptr, prop)) + flag |= FILE_RELPATH; + if (RNA_boolean_get(op->ptr, "link")) + flag |= FILE_LINK; + if (RNA_boolean_get(op->ptr, "instance_groups")) + flag |= FILE_GROUP_INSTANCE; return flag; } -/* Helper. - * if `name` is non-NULL, we assume a single-item link/append. - * else if `*todo_libraries` is NULL we assume first-run. - */ -static void wm_link_append_do_libgroup( - bContext *C, wmOperator *op, const char *root, const char *libname, char *group, char *name, - const short flag, GSet **todo_libraries) +typedef struct WMLinkAppendDataItem { + char *name; + BLI_bitmap *libraries; /* All libs (from WMLinkAppendData.libraries) to try to load this ID from. */ + short idcode; + + ID *new_id; + void *customdata; +} WMLinkAppendDataItem; + +typedef struct WMLinkAppendData { + LinkNodePair libraries; + LinkNodePair items; + int num_libraries; + int num_items; + short flag; + + /* Internal 'private' data */ + MemArena *memarena; +} WMLinkAppendData; + +static WMLinkAppendData *wm_link_append_data_new(const int flag) { - Main *bmain = CTX_data_main(C); - Main *mainl; - BlendHandle *bh; - Library *lib; + MemArena *ma = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, __func__); + WMLinkAppendData *lapp_data = BLI_memarena_calloc(ma, sizeof(*lapp_data)); - char path[FILE_MAX_LIBEXTRA], relname[FILE_MAX]; - int idcode; - const bool is_first_run = (*todo_libraries == NULL); + lapp_data->flag = flag; + lapp_data->memarena = ma; - BLI_assert(group); - idcode = BKE_idcode_from_name(group); + return lapp_data; +} - bh = BLO_blendhandle_from_file(libname, op->reports); +static void wm_link_append_data_free(WMLinkAppendData *lapp_data) +{ + BLI_memarena_free(lapp_data->memarena); +} - if (bh == NULL) { - /* unlikely since we just browsed it, but possible - * error reports will have been made by BLO_blendhandle_from_file() */ - return; - } +/* WARNING! *Never* call wm_link_append_data_library_add() after having added some items! */ + +static void wm_link_append_data_library_add(WMLinkAppendData *lapp_data, const char *libname) +{ + size_t len = strlen(libname) + 1; + char *libpath = BLI_memarena_alloc(lapp_data->memarena, len); - /* here appending/linking starts */ - mainl = BLO_library_append_begin(bmain, &bh, libname); - lib = mainl->curlib; - BLI_assert(lib); + BLI_strncpy(libpath, libname, len); + BLI_linklist_append_arena(&lapp_data->libraries, libpath, lapp_data->memarena); + lapp_data->num_libraries++; +} - if (mainl->versionfile < 250) { - BKE_reportf(op->reports, RPT_WARNING, - "Linking or appending from a very old .blend file format (%d.%d), no animation conversion will " - "be done! You may want to re-save your lib file with current Blender", - mainl->versionfile, mainl->subversionfile); - } +static WMLinkAppendDataItem *wm_link_append_data_item_add( + WMLinkAppendData *lapp_data, const char *idname, const short idcode, void *customdata) +{ + WMLinkAppendDataItem *item = BLI_memarena_alloc(lapp_data->memarena, sizeof(*item)); + size_t len = strlen(idname) + 1; - if (name) { - BLO_library_append_named_part_ex(C, mainl, &bh, name, idcode, flag); - } - else { - if (is_first_run) { - *todo_libraries = BLI_gset_new(BLI_ghashutil_strhash_p, BLI_ghashutil_strcmp, __func__); - } + item->name = BLI_memarena_alloc(lapp_data->memarena, len); + BLI_strncpy(item->name, idname, len); + item->idcode = idcode; + item->libraries = BLI_BITMAP_NEW_MEMARENA(lapp_data->memarena, lapp_data->num_libraries); - RNA_BEGIN (op->ptr, itemptr, "files") - { - char curr_libname[FILE_MAX]; - int curr_idcode; + item->new_id = NULL; + item->customdata = customdata; - RNA_string_get(&itemptr, "name", relname); + BLI_linklist_append_arena(&lapp_data->items, item, lapp_data->memarena); + lapp_data->num_items++; - BLI_join_dirfile(path, sizeof(path), root, relname); + return item; +} - if (BLO_library_path_explode(path, curr_libname, &group, &name)) { - if (!group || !name) { - continue; - } +static void wm_link_do( + WMLinkAppendData *lapp_data, ReportList *reports, Main *bmain, Scene *scene, View3D *v3d) +{ + Main *mainl; + BlendHandle *bh; + Library *lib; - curr_idcode = BKE_idcode_from_name(group); + const int flag = lapp_data->flag; - if ((idcode == curr_idcode) && (BLI_path_cmp(curr_libname, libname) == 0)) { - BLO_library_append_named_part_ex(C, mainl, &bh, name, idcode, flag); - } - else if (is_first_run) { - BLI_join_dirfile(path, sizeof(path), curr_libname, group); - if (!BLI_gset_haskey(*todo_libraries, path)) { - BLI_gset_insert(*todo_libraries, BLI_strdup(path)); - } - } - } + LinkNode *liblink, *itemlink; + int lib_idx, item_idx; + + BLI_assert(lapp_data->num_items && lapp_data->num_libraries); + + for (lib_idx = 0, liblink = lapp_data->libraries.list; liblink; lib_idx++, liblink = liblink->next) { + char *libname = liblink->link; + + bh = BLO_blendhandle_from_file(libname, reports); + + if (bh == NULL) { + /* Unlikely since we just browsed it, but possible + * Error reports will have been made by BLO_blendhandle_from_file() */ + continue; } - RNA_END; - } - BLO_library_append_end(C, mainl, &bh, idcode, flag); - BLO_blendhandle_close(bh); + /* here appending/linking starts */ + mainl = BLO_library_link_begin(bmain, &bh, libname); + lib = mainl->curlib; + BLI_assert(lib); + UNUSED_VARS_NDEBUG(lib); + + if (mainl->versionfile < 250) { + BKE_reportf(reports, RPT_WARNING, + "Linking or appending from a very old .blend file format (%d.%d), no animation conversion will " + "be done! You may want to re-save your lib file with current Blender", + mainl->versionfile, mainl->subversionfile); + } - /* mark all library linked objects to be updated */ - BKE_main_lib_objects_recalc_all(bmain); - IMB_colormanagement_check_file_config(bmain); + /* For each lib file, we try to link all items belonging to that lib, + * and tag those successful to not try to load them again with the other libs. */ + for (item_idx = 0, itemlink = lapp_data->items.list; itemlink; item_idx++, itemlink = itemlink->next) { + WMLinkAppendDataItem *item = itemlink->link; + ID *new_id; - /* append, rather than linking */ - if ((flag & FILE_LINK) == 0) { - BLI_assert(BLI_findindex(&bmain->library, lib) != -1); - BKE_library_make_local(bmain, lib, true); + if (!BLI_BITMAP_TEST(item->libraries, lib_idx)) { + continue; + } + + new_id = BLO_library_link_named_part_ex(mainl, &bh, item->idcode, item->name, flag, scene, v3d); + if (new_id) { + /* If the link is sucessful, clear item's libs 'todo' flags. + * This avoids trying to link same item with other libraries to come. */ + BLI_BITMAP_SET_ALL(item->libraries, false, lapp_data->num_libraries); + item->new_id = new_id; + } + } + + BLO_library_link_end(mainl, &bh, flag, scene, v3d); + BLO_blendhandle_close(bh); } } @@ -2696,13 +2772,12 @@ static int wm_link_append_exec(bContext *C, wmOperator *op) Main *bmain = CTX_data_main(C); Scene *scene = CTX_data_scene(C); PropertyRNA *prop; + WMLinkAppendData *lapp_data; char path[FILE_MAX_LIBEXTRA], root[FILE_MAXDIR], libname[FILE_MAX], relname[FILE_MAX]; char *group, *name; int totfiles = 0; short flag; - GSet *todo_libraries = NULL; - RNA_string_get(op->ptr, "filename", relname); RNA_string_get(op->ptr, "directory", root); @@ -2710,15 +2785,15 @@ static int wm_link_append_exec(bContext *C, wmOperator *op) /* test if we have a valid data */ if (!BLO_library_path_explode(path, libname, &group, &name)) { - BKE_report(op->reports, RPT_ERROR, "Not a library"); + BKE_reportf(op->reports, RPT_ERROR, "'%s': not a library", path); return OPERATOR_CANCELLED; } else if (!group) { - BKE_report(op->reports, RPT_ERROR, "Nothing indicated"); + BKE_reportf(op->reports, RPT_ERROR, "'%s': nothing indicated", path); return OPERATOR_CANCELLED; } else if (BLI_path_cmp(bmain->name, libname) == 0) { - BKE_report(op->reports, RPT_ERROR, "Cannot use current file as library"); + BKE_reportf(op->reports, RPT_ERROR, "'%s': cannot use current file as library", path); return OPERATOR_CANCELLED; } @@ -2728,55 +2803,112 @@ static int wm_link_append_exec(bContext *C, wmOperator *op) totfiles = RNA_property_collection_length(op->ptr, prop); if (totfiles == 0) { if (!name) { - BKE_report(op->reports, RPT_ERROR, "Nothing indicated"); + BKE_reportf(op->reports, RPT_ERROR, "'%s': nothing indicated", path); return OPERATOR_CANCELLED; } } } else if (!name) { - BKE_report(op->reports, RPT_ERROR, "Nothing indicated"); + BKE_reportf(op->reports, RPT_ERROR, "'%s': nothing indicated", path); return OPERATOR_CANCELLED; } flag = wm_link_append_flag(op); /* sanity checks for flag */ - if (scene->id.lib && (flag & FILE_GROUP_INSTANCE)) { - /* TODO, user never gets this message */ - BKE_reportf(op->reports, RPT_WARNING, "Scene '%s' is linked, group instance disabled", scene->id.name + 2); + if (scene && scene->id.lib) { + BKE_reportf(op->reports, RPT_WARNING, + "Scene '%s' is linked, instantiation of objects & groups is disabled", scene->id.name + 2); flag &= ~FILE_GROUP_INSTANCE; + scene = NULL; } /* from here down, no error returns */ - /* now we have or selected, or an indicated file */ - if (RNA_boolean_get(op->ptr, "autoselect")) + if (scene && RNA_boolean_get(op->ptr, "autoselect")) { BKE_scene_base_deselect_all(scene); + } /* tag everything, all untagged data can be made local * its also generally useful to know what is new * - * take extra care BKE_main_id_flag_all(LIB_LINK_TAG, false) is called after! */ - BKE_main_id_flag_all(bmain, LIB_PRE_EXISTING, 1); + * take extra care BKE_main_id_flag_all(bmain, LIB_PRE_EXISTING, false) is called after! */ + BKE_main_id_flag_all(bmain, LIB_PRE_EXISTING, true); + /* We define our working data... + * Note that here, each item 'uses' one library, and only one. */ + lapp_data = wm_link_append_data_new(flag); if (totfiles != 0) { - name = NULL; - } + GHash *libraries = BLI_ghash_new(BLI_ghashutil_strhash_p, BLI_ghashutil_strcmp, __func__); + int lib_idx = 0; + + RNA_BEGIN (op->ptr, itemptr, "files") + { + RNA_string_get(&itemptr, "name", relname); + + BLI_join_dirfile(path, sizeof(path), root, relname); + + if (BLO_library_path_explode(path, libname, &group, &name)) { + if (!group || !name) { + continue; + } - wm_link_append_do_libgroup(C, op, root, libname, group, name, flag, &todo_libraries); + if (!BLI_ghash_haskey(libraries, libname)) { + BLI_ghash_insert(libraries, BLI_strdup(libname), SET_INT_IN_POINTER(lib_idx)); + lib_idx++; + wm_link_append_data_library_add(lapp_data, libname); + } + } + } + RNA_END; - if (todo_libraries) { - GSetIterator libs_it; + RNA_BEGIN (op->ptr, itemptr, "files") + { + RNA_string_get(&itemptr, "name", relname); - GSET_ITER(libs_it, todo_libraries) { - char *libpath = (char *)BLI_gsetIterator_getKey(&libs_it); + BLI_join_dirfile(path, sizeof(path), root, relname); - BLO_library_path_explode(libpath, libname, &group, NULL); + if (BLO_library_path_explode(path, libname, &group, &name)) { + WMLinkAppendDataItem *item; + if (!group || !name) { + printf("skipping %s\n", path); + continue; + } + + lib_idx = GET_INT_FROM_POINTER(BLI_ghash_lookup(libraries, libname)); - wm_link_append_do_libgroup(C, op, root, libname, group, NULL, flag, &todo_libraries); + item = wm_link_append_data_item_add(lapp_data, name, BKE_idcode_from_name(group), NULL); + BLI_BITMAP_ENABLE(item->libraries, lib_idx); + } } + RNA_END; - BLI_gset_free(todo_libraries, MEM_freeN); + BLI_ghash_free(libraries, MEM_freeN, NULL); + } + else { + WMLinkAppendDataItem *item; + + wm_link_append_data_library_add(lapp_data, libname); + item = wm_link_append_data_item_add(lapp_data, name, BKE_idcode_from_name(group), NULL); + BLI_BITMAP_ENABLE(item->libraries, 0); + } + + /* XXX We'd need re-entrant locking on Main for this to work... */ + /* BKE_main_lock(bmain); */ + + wm_link_do(lapp_data, op->reports, bmain, scene, CTX_wm_view3d(C)); + + /* BKE_main_unlock(bmain); */ + + wm_link_append_data_free(lapp_data); + + /* mark all library linked objects to be updated */ + BKE_main_lib_objects_recalc_all(bmain); + IMB_colormanagement_check_file_config(bmain); + + /* append, rather than linking */ + if ((flag & FILE_LINK) == 0) { + BKE_library_make_local(bmain, NULL, true); } /* important we unset, otherwise these object wont @@ -4448,7 +4580,7 @@ static void radial_control_cancel(bContext *C, wmOperator *op) static int radial_control_modal(bContext *C, wmOperator *op, const wmEvent *event) { RadialControl *rc = op->customdata; - float new_value, dist, zoom[2]; + float new_value, dist = 0.0f, zoom[2]; float delta[2], ret = OPERATOR_RUNNING_MODAL; bool snap; float angle_precision = 0.0f; @@ -5004,7 +5136,7 @@ static void WM_OT_previews_ensure(wmOperatorType *ot) static EnumPropertyItem preview_id_type_items[] = { {FILTER_ID_SCE, "SCENE", 0, "Scenes", ""}, {FILTER_ID_GR, "GROUP", 0, "Groups", ""}, - {FILTER_ID_OB, "OBJECT", 0, "Objects", ""}, + {FILTER_ID_OB, "OBJECT", 0, "Objects", ""}, {FILTER_ID_MA, "MATERIAL", 0, "Materials", ""}, {FILTER_ID_LA, "LAMP", 0, "Lamps", ""}, {FILTER_ID_WO, "WORLD", 0, "Worlds", ""}, @@ -5159,6 +5291,7 @@ void wm_operatortype_init(void) /* reserve size is set based on blender default setup */ global_ops_hash = BLI_ghash_str_new_ex("wm_operatortype_init gh", 2048); + WM_operatortype_append(WM_OT_window_close); WM_operatortype_append(WM_OT_window_duplicate); WM_operatortype_append(WM_OT_read_history); WM_operatortype_append(WM_OT_read_homefile); diff --git a/source/blender/windowmanager/intern/wm_playanim.c b/source/blender/windowmanager/intern/wm_playanim.c index e63b4661870..2150d94d9b0 100644 --- a/source/blender/windowmanager/intern/wm_playanim.c +++ b/source/blender/windowmanager/intern/wm_playanim.c @@ -77,10 +77,10 @@ # include AUD_SOUND_H # include AUD_SPECIAL_H -AUD_Sound *source = NULL; -AUD_Handle *playback_handle = NULL; -AUD_Handle *scrub_handle = NULL; -AUD_Device *audio_device = NULL; +static AUD_Sound *source = NULL; +static AUD_Handle *playback_handle = NULL; +static AUD_Handle *scrub_handle = NULL; +static AUD_Device *audio_device = NULL; #endif /* simple limiter to avoid flooding memory */ @@ -383,7 +383,6 @@ static void build_pict_list_ex(PlayState *ps, const char *first, int totframes, // short val; PlayAnimPict *picture = NULL; struct ImBuf *ibuf = NULL; - char str[32 + FILE_MAX]; struct anim *anim; if (IMB_isanim(first)) { @@ -402,8 +401,7 @@ static void build_pict_list_ex(PlayState *ps, const char *first, int totframes, picture->anim = anim; picture->frame = pic; picture->IB_flags = IB_rect; - BLI_snprintf(str, sizeof(str), "%s : %4.d", first, pic + 1); - picture->name = strdup(str); + picture->name = BLI_sprintfN("%s : %4.d", first, pic + 1); BLI_addtail(&picsbase, picture); } } @@ -414,7 +412,14 @@ static void build_pict_list_ex(PlayState *ps, const char *first, int totframes, else { int count = 0; + int fp_framenr; + struct { + char head[FILE_MAX], tail[FILE_MAX]; + unsigned short digits; + } fp_decoded; + BLI_strncpy(filepath, first, sizeof(filepath)); + fp_framenr = BLI_stringdec(filepath, fp_decoded.head, fp_decoded.tail, &fp_decoded.digits); pupdate_time(); ptottime = 1.0; @@ -480,8 +485,8 @@ static void build_pict_list_ex(PlayState *ps, const char *first, int totframes, } picture->mem = mem; - picture->name = strdup(filepath); - picture->frame = count; /* not exact but should work for positioning */ + picture->name = BLI_strdup(filepath); + picture->frame = count; close(file); BLI_addtail(&picsbase, picture); count++; @@ -505,7 +510,9 @@ static void build_pict_list_ex(PlayState *ps, const char *first, int totframes, ptottime = 0.0; } - BLI_newname(filepath, +fstep); + /* create a new filepath each time */ + fp_framenr += fstep; + BLI_stringenc(filepath, fp_decoded.head, fp_decoded.tail, fp_decoded.digits, fp_framenr); while ((hasevent = GHOST_ProcessEvents(g_WS.ghost_system, 0))) { if (hasevent) { @@ -544,17 +551,16 @@ static void update_sound_fps(void) static void change_frame(PlayState *ps, int cx) { int sizex, sizey; - int i; + int i, i_last; - playanim_window_get_size(&sizex, &sizey); - ps->picture = picsbase.first; - /* TODO - store in ps direct? */ - i = 0; - while (ps->picture) { - i++; - ps->picture = ps->picture->next; + if (BLI_listbase_is_empty(&picsbase)) { + return; } - i = (i * cx) / sizex; + + playanim_window_get_size(&sizex, &sizey); + i_last = ((struct PlayAnimPict *)picsbase.last)->frame; + i = (i_last * cx) / sizex; + CLAMP(i, 0, i_last); #ifdef WITH_AUDASPACE if (scrub_handle) { @@ -588,11 +594,8 @@ static void change_frame(PlayState *ps, int cx) } #endif - ps->picture = picsbase.first; - for (; i > 0; i--) { - if (ps->picture->next == NULL) break; - ps->picture = ps->picture->next; - } + ps->picture = BLI_findlink(&picsbase, i); + BLI_assert(ps->picture != NULL); ps->sstep = true; ps->wait2 = false; @@ -977,6 +980,19 @@ static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr ps_void) GHOST_TEventCursorData *cd = GHOST_GetEventData(evt); int cx, cy; + /* Ignore 'in-between' events, since they can make scrubbing lag. + * + * Ideally we would keep into the event queue and see if this is the last motion event. + * however the API currently doesn't support this. */ + { + int x_test, y_test; + GHOST_GetCursorPosition(g_WS.ghost_system, &x_test, &y_test); + if (x_test != cd->x || y_test != cd->y) { + /* we're not the last event... skipping */ + break; + } + } + GHOST_ScreenToClient(g_WS.ghost_window, cd->x, cd->y, &cx, &cy); change_frame(ps, cx); @@ -1093,7 +1109,6 @@ static char *wm_main_playanim_intern(int argc, const char **argv) GHOST_TUns32 maxwinx, maxwiny; int i; /* This was done to disambiguate the name for use under c++. */ - struct anim *anim = NULL; int start_x = 0, start_y = 0; int sfra = -1; int efra = -1; @@ -1101,20 +1116,6 @@ static char *wm_main_playanim_intern(int argc, const char **argv) PlayState ps = {0}; -#ifdef WITH_AUDASPACE - AUD_DeviceSpecs specs; - - specs.rate = AUD_RATE_44100; - specs.format = AUD_FORMAT_S16; - specs.channels = AUD_CHANNELS_STEREO; - - AUD_initOnce(); - - if (!(audio_device = AUD_init("OpenAL", specs, 1024, "Blender"))) - audio_device = AUD_init("Null", specs, 0, "Blender"); - -#endif - /* ps.doubleb = true;*/ /* UNUSED */ ps.go = true; ps.direction = true; @@ -1208,12 +1209,13 @@ static char *wm_main_playanim_intern(int argc, const char **argv) BLI_strncpy(filepath, argv[1], sizeof(filepath)); } else { - BLI_current_working_dir(filepath, sizeof(filepath)); - BLI_add_slash(filepath); + printf("%s: no filepath argument given\n", __func__); + exit(1); } if (IMB_isanim(filepath)) { /* OCIO_TODO: support different input color spaces */ + struct anim *anim; anim = IMB_open_anim(filepath, IB_rect, 0, NULL); if (anim) { ibuf = IMB_anim_absolute(anim, 0, IMB_TC_NONE, IMB_PROXY_NONE); @@ -1485,13 +1487,13 @@ static char *wm_main_playanim_intern(int argc, const char **argv) } } } - ps.picture = picsbase.first; - anim = NULL; - while (ps.picture) { - if (ps.picture && ps.picture->anim && (anim != ps.picture->anim)) { - // to prevent divx crashes - anim = ps.picture->anim; - IMB_close_anim(anim); + while ((ps.picture = BLI_pophead(&picsbase))) { + if (ps.picture->anim) { + if ((ps.picture->next == NULL) || + (ps.picture->next->anim != ps.picture->anim)) + { + IMB_close_anim(ps.picture->anim); + } } if (ps.picture->ibuf) { @@ -1501,7 +1503,8 @@ static char *wm_main_playanim_intern(int argc, const char **argv) MEM_freeN(ps.picture->mem); } - ps.picture = ps.picture->next; + MEM_freeN((void *)ps.picture->name); + MEM_freeN(ps.picture); } /* cleanup */ @@ -1514,12 +1517,16 @@ static char *wm_main_playanim_intern(int argc, const char **argv) added_images = 0; #ifdef WITH_AUDASPACE - if (playback_handle) + if (playback_handle) { AUD_Handle_stop(playback_handle); - if (scrub_handle) + playback_handle = NULL; + } + if (scrub_handle) { AUD_Handle_stop(scrub_handle); + scrub_handle = NULL; + } AUD_Sound_free(source); - AUD_exit(audio_device); + source = NULL; #endif #if 0 // XXX25 @@ -1557,18 +1564,43 @@ static char *wm_main_playanim_intern(int argc, const char **argv) void WM_main_playanim(int argc, const char **argv) { + const char *argv_next[2]; bool looping = true; +#ifdef WITH_AUDASPACE + { + AUD_DeviceSpecs specs; + + specs.rate = AUD_RATE_44100; + specs.format = AUD_FORMAT_S16; + specs.channels = AUD_CHANNELS_STEREO; + + AUD_initOnce(); + + if (!(audio_device = AUD_init("OpenAL", specs, 1024, "Blender"))) { + audio_device = AUD_init("Null", specs, 0, "Blender"); + } + } +#endif + while (looping) { const char *filepath = wm_main_playanim_intern(argc, argv); if (filepath) { /* use simple args */ - argv[1] = "-a"; - argv[2] = filepath; - argc = 3; + argv_next[0] = argv[0]; + argv_next[1] = filepath; + argc = 2; + + /* continue with new args */ + argv = argv_next; } else { looping = false; } } + +#ifdef WITH_AUDASPACE + AUD_exit(audio_device); + AUD_exitOnce(); +#endif } diff --git a/source/blender/windowmanager/intern/wm_window.c b/source/blender/windowmanager/intern/wm_window.c index af7e9c8ca33..d8e6671afda 100644 --- a/source/blender/windowmanager/intern/wm_window.c +++ b/source/blender/windowmanager/intern/wm_window.c @@ -329,12 +329,17 @@ void wm_window_close(bContext *C, wmWindowManager *wm, wmWindow *win) CTX_wm_window_set(C, win); /* needed by handlers */ WM_event_remove_handlers(C, &win->handlers); WM_event_remove_handlers(C, &win->modalhandlers); - ED_screen_exit(C, win, win->screen); + + /* for regular use this will _never_ be NULL, + * however we may be freeing an improperly initialized window. */ + if (win->screen) { + ED_screen_exit(C, win, win->screen); + } wm_window_free(C, wm, win); /* if temp screen, delete it after window free (it stops jobs that can access it) */ - if (screen->temp) { + if (screen && screen->temp) { Main *bmain = CTX_data_main(C); BKE_libblock_free(bmain, screen); } @@ -380,7 +385,7 @@ float wm_window_pixelsize(wmWindow *win) } /* belongs to below */ -static void wm_window_add_ghostwindow(wmWindowManager *wm, const char *title, wmWindow *win) +static void wm_window_ghostwindow_add(wmWindowManager *wm, const char *title, wmWindow *win) { GHOST_WindowHandle ghostwin; GHOST_GLSettings glSettings = {0}; @@ -466,14 +471,26 @@ static void wm_window_add_ghostwindow(wmWindowManager *wm, const char *title, wm } } -/* for wmWindows without ghostwin, open these and clear */ -/* window size is read from window, if 0 it uses prefsize */ -/* called in WM_check, also inits stuff after file read */ -void wm_window_add_ghostwindows(wmWindowManager *wm) +/** + * Initialize #wmWindows without ghostwin, open these and clear. + * + * window size is read from window, if 0 it uses prefsize + * called in #WM_check, also inits stuff after file read. + * + * \warning + * After running, 'win->ghostwin' can be NULL in rare cases + * (where OpenGL driver fails to create a context for eg). + * We could remove them with #wm_window_ghostwindows_remove_invalid + * but better not since caller may continue to use. + * Instead, caller needs to handle the error case and cleanup. + */ +void wm_window_ghostwindows_ensure(wmWindowManager *wm) { wmKeyMap *keymap; wmWindow *win; + BLI_assert(G.background == false); + /* no commandline prefsize? then we set this. * Note that these values will be used only * when there is no startup.blend yet. @@ -521,7 +538,7 @@ void wm_window_add_ghostwindows(wmWindowManager *wm) win->cursor = CURSOR_STD; } - wm_window_add_ghostwindow(wm, "Blender", win); + wm_window_ghostwindow_add(wm, "Blender", win); } /* happens after fileread */ if (win->eventstate == NULL) @@ -546,11 +563,33 @@ void wm_window_add_ghostwindows(wmWindowManager *wm) } } -/* new window, no screen yet, but we open ghostwindow for it */ -/* also gets the window level handlers */ -/* area-rip calls this */ +/** + * Call after #wm_window_ghostwindows_ensure or #WM_check + * (after loading a new file) in the unlikely event a window couldn't be created. + */ +void wm_window_ghostwindows_remove_invalid(bContext *C, wmWindowManager *wm) +{ + wmWindow *win, *win_next; + + BLI_assert(G.background == false); + + for (win = wm->windows.first; win; win = win_next) { + win_next = win->next; + if (win->ghostwin == NULL) { + wm_window_close(C, wm, win); + } + } +} + +/** + * new window, no screen yet, but we open ghostwindow for it, + * also gets the window level handlers + * \note area-rip calls this. + * \return the window or NULL. + */ wmWindow *WM_window_open(bContext *C, const rcti *rect) { + wmWindow *win_prev = CTX_wm_window(C); wmWindow *win = wm_window_new(C); win->posx = rect->xmin; @@ -561,22 +600,35 @@ wmWindow *WM_window_open(bContext *C, const rcti *rect) win->drawmethod = U.wmdrawmethod; WM_check(C); - - return win; -} -/* uses screen->temp tag to define what to do, currently it limits - * to only one "temp" window for render out, preferences, filewindow, etc */ -/* type is defined in WM_api.h */ + if (win->ghostwin) { + return win; + } + else { + wm_window_close(C, CTX_wm_manager(C), win); + CTX_wm_window_set(C, win_prev); + return NULL; + } +} -void WM_window_open_temp(bContext *C, rcti *position, int type) +/** + * Uses `screen->temp` tag to define what to do, currently it limits + * to only one "temp" window for render out, preferences, filewindow, etc... + * + * \param type: WM_WINDOW_RENDER, WM_WINDOW_USERPREFS... + * \return the window or NULL. + */ +wmWindow *WM_window_open_temp(bContext *C, const rcti *rect_init, int type) { + wmWindow *win_prev = CTX_wm_window(C); wmWindow *win; ScrArea *sa; Scene *scene = CTX_data_scene(C); - + const char *title; + rcti rect = *rect_init; + /* changes rect to fit within desktop */ - wm_window_check_position(position); + wm_window_check_position(&rect); /* test if we have a temp screen already */ for (win = CTX_wm_manager(C)->windows.first; win; win = win->next) @@ -587,12 +639,12 @@ void WM_window_open_temp(bContext *C, rcti *position, int type) if (win == NULL) { win = wm_window_new(C); - win->posx = position->xmin; - win->posy = position->ymin; + win->posx = rect.xmin; + win->posy = rect.ymin; } - win->sizex = BLI_rcti_size_x(position); - win->sizey = BLI_rcti_size_y(position); + win->sizex = BLI_rcti_size_x(&rect); + win->sizey = BLI_rcti_size_y(&rect); if (win->ghostwin) { wm_window_set_size(win, win->sizex, win->sizey); @@ -614,7 +666,13 @@ void WM_window_open_temp(bContext *C, rcti *position, int type) /* make window active, and validate/resize */ CTX_wm_window_set(C, win); WM_check(C); - + + /* It's possible `win->ghostwin == NULL`. + * instead of attempting to cleanup here (in a half finished state), + * finish setting up the screen, then free it at the end of the function, + * to avoid having to take into account a partially-created window. + */ + /* ensure it shows the right spacetype editor */ sa = win->screen->areabase.first; CTX_wm_area_set(C, sa); @@ -630,18 +688,38 @@ void WM_window_open_temp(bContext *C, rcti *position, int type) ED_screen_refresh(CTX_wm_manager(C), win); /* test scale */ if (sa->spacetype == SPACE_IMAGE) - GHOST_SetTitle(win->ghostwin, IFACE_("Blender Render")); + title = IFACE_("Blender Render"); else if (ELEM(sa->spacetype, SPACE_OUTLINER, SPACE_USERPREF)) - GHOST_SetTitle(win->ghostwin, IFACE_("Blender User Preferences")); + title = IFACE_("Blender User Preferences"); else if (sa->spacetype == SPACE_FILE) - GHOST_SetTitle(win->ghostwin, IFACE_("Blender File View")); + title = IFACE_("Blender File View"); else - GHOST_SetTitle(win->ghostwin, "Blender"); + title = "Blender"; + + if (win->ghostwin) { + GHOST_SetTitle(win->ghostwin, title); + return win; + } + else { + /* very unlikely! but opening a new window can fail */ + wm_window_close(C, CTX_wm_manager(C), win); + CTX_wm_window_set(C, win_prev); + + return NULL; + } } /* ****************** Operators ****************** */ +int wm_window_close_exec(bContext *C, wmOperator *UNUSED(op)) +{ + wmWindowManager *wm = CTX_wm_manager(C); + wmWindow *win = CTX_wm_window(C); + wm_window_close(C, wm, win); + return OPERATOR_FINISHED; +} + /* operator callback */ int wm_window_duplicate_exec(bContext *C, wmOperator *UNUSED(op)) { @@ -676,7 +754,7 @@ int wm_window_fullscreen_toggle_exec(bContext *C, wmOperator *UNUSED(op)) /* ************ events *************** */ -static void wm_convert_cursor_position(wmWindow *win, int *x, int *y) +void wm_cursor_position_from_ghost(wmWindow *win, int *x, int *y) { float fac = GHOST_GetNativePixelSize(win->ghostwin); @@ -687,11 +765,21 @@ static void wm_convert_cursor_position(wmWindow *win, int *x, int *y) *y *= fac; } +void wm_cursor_position_to_ghost(wmWindow *win, int *x, int *y) +{ + float fac = GHOST_GetNativePixelSize(win->ghostwin); + + *x /= fac; + *y /= fac; + *y = win->sizey - *y - 1; + + GHOST_ClientToScreen(win->ghostwin, *x, *y, x, y); +} void wm_get_cursor_position(wmWindow *win, int *x, int *y) { GHOST_GetCursorPosition(g_system, x, y); - wm_convert_cursor_position(win, x, y); + wm_cursor_position_from_ghost(win, x, y); } typedef enum { @@ -1017,9 +1105,12 @@ static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr C_void_ptr #if defined(__APPLE__) || defined(WIN32) /* OSX and Win32 don't return to the mainloop while resize */ - wm_event_do_handlers(C); wm_event_do_notifiers(C); wm_draw_update(C); + + /* Warning! code above nulls 'C->wm.window', causing BGE to quit, see: T45699. + * Further, its easier to match behavior across platforms, so restore the window. */ + CTX_wm_window_set(C, win); #endif } } @@ -1115,7 +1206,7 @@ static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr C_void_ptr { GHOST_TEventTrackpadData *pd = data; - wm_convert_cursor_position(win, &pd->x, &pd->y); + wm_cursor_position_from_ghost(win, &pd->x, &pd->y); wm_event_add_ghostevent(wm, win, type, time, data); break; } @@ -1123,7 +1214,7 @@ static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr C_void_ptr { GHOST_TEventCursorData *cd = data; - wm_convert_cursor_position(win, &cd->x, &cd->y); + wm_cursor_position_from_ghost(win, &cd->x, &cd->y); wm_event_add_ghostevent(wm, win, type, time, data); break; } @@ -1274,7 +1365,7 @@ void WM_event_timer_sleep(wmWindowManager *wm, wmWindow *UNUSED(win), wmTimer *t wmTimer *WM_event_add_timer(wmWindowManager *wm, wmWindow *win, int event_type, double timestep) { wmTimer *wt = MEM_callocN(sizeof(wmTimer), "window timer"); - + wt->event_type = event_type; wt->ltime = PIL_check_seconds_timer(); wt->ntime = wt->ltime + timestep; @@ -1538,14 +1629,9 @@ void WM_init_native_pixels(bool do_it) void WM_cursor_warp(wmWindow *win, int x, int y) { if (win && win->ghostwin) { - float f = GHOST_GetNativePixelSize(win->ghostwin); int oldx = x, oldy = y; - x = x / f; - y = y / f; - y = win->sizey - y - 1; - - GHOST_ClientToScreen(win->ghostwin, x, y, &x, &y); + wm_cursor_position_to_ghost(win, &x, &y); GHOST_SetCursorPosition(g_system, x, y); win->eventstate->prevx = oldx; @@ -1557,6 +1643,18 @@ void WM_cursor_warp(wmWindow *win, int x, int y) } /** + * Set x, y to values we can actually position the cursor to. + */ +void WM_cursor_compatible_xy(wmWindow *win, int *x, int *y) +{ + float f = GHOST_GetNativePixelSize(win->ghostwin); + if (f != 1.0f) { + *x = (int)(*x / f) * f; + *y = (int)(*y / f) * f; + } +} + +/** * Get the cursor pressure, in most cases you'll want to use wmTabletData from the event */ float WM_cursor_pressure(const struct wmWindow *win) diff --git a/source/blender/windowmanager/wm_files.h b/source/blender/windowmanager/wm_files.h index 467926aa770..4b35f662a99 100644 --- a/source/blender/windowmanager/wm_files.h +++ b/source/blender/windowmanager/wm_files.h @@ -38,6 +38,7 @@ int wm_homefile_read_exec(struct bContext *C, struct wmOperator *op); int wm_homefile_read(struct bContext *C, struct ReportList *reports, bool from_memory, const char *filepath); int wm_homefile_write_exec(struct bContext *C, struct wmOperator *op); int wm_userpref_write_exec(struct bContext *C, struct wmOperator *op); +void wm_file_read_report(bContext *C); #endif /* __WM_FILES_H__ */ diff --git a/source/blender/windowmanager/wm_window.h b/source/blender/windowmanager/wm_window.h index a104f6aba39..c106f9d7851 100644 --- a/source/blender/windowmanager/wm_window.h +++ b/source/blender/windowmanager/wm_window.h @@ -48,7 +48,8 @@ void wm_window_free (bContext *C, wmWindowManager *wm, wmWindow *win); void wm_window_close (bContext *C, wmWindowManager *wm, wmWindow *win); void wm_window_title (wmWindowManager *wm, wmWindow *win); -void wm_window_add_ghostwindows (wmWindowManager *wm); +void wm_window_ghostwindows_ensure(wmWindowManager *wm); +void wm_window_ghostwindows_remove_invalid(bContext *C, wmWindowManager *wm); void wm_window_process_events (const bContext *C); void wm_window_process_events_nosleep(void); @@ -64,7 +65,9 @@ bool wm_window_get_swap_interval(wmWindow *win, int *intervalOut); float wm_window_pixelsize(wmWindow *win); -void wm_get_cursor_position (wmWindow *win, int *x, int *y); +void wm_get_cursor_position (wmWindow *win, int *x, int *y); +void wm_cursor_position_from_ghost (wmWindow *win, int *x, int *y); +void wm_cursor_position_to_ghost (wmWindow *win, int *x, int *y); void wm_window_testbreak (void); @@ -74,6 +77,7 @@ void wm_window_IME_end (wmWindow *win); #endif /* *************** window operators ************** */ +int wm_window_close_exec(bContext *C, struct wmOperator *op); int wm_window_duplicate_exec(bContext *C, struct wmOperator *op); int wm_window_fullscreen_toggle_exec(bContext *C, struct wmOperator *op); |